Skip to content

MiguelMarcelino/py2many

 
 

Repository files navigation

py2many: Python to many CLike languages transpiler

Build License

Why

Python is popular, easy to program in, but has poor runtime performance. We can fix that by transpiling a subset of the language into a more performant, statically typed language.

A second benefit is security. Writing security sensitive code in a low level language like C is error prone and could lead to privilege escalation. Specialized languages such as wuffs exist to address this use case. py2many can be a more general purpose solution to the problem where you can verify the source via unit tests before you transpile.

A third potential use case is to accelerate python code by transpiling it into an extension

Swift and Kotlin dominate the mobile app development workflow. However, there is no one solution that works well for lower level libraries where there is desire to share code between platforms. Kotlin Mobile Multiplatform (KMM) is a player in this place, but it hasn't really caught on. py2many provides an alternative.

Lastly, it's a great educational tool to learn a new language by implementing a backend for your favorite language.

Status

Rust is the language where the focus of development has been.

C++14 is historically the first language to be supported. C++17 is now required for some features.

Preliminary support exists for Julia, Kotlin, Nim, Go and Dart.

py2many can also emit Python 3 code that includes inferred type annotations, and revisions to the syntax intended to simplify parsing of the code.

History

Based on Julian Konchunas' pyrs http://github.com/konchunas/pyrs

Based on Lukas Martinelli Py14 (https://github.com/lukasmartinelli/py14) and Py14/python-3 (https://github.com/ProgVal/py14/tree/python-3) branch by Valentin Lorentz.

Example

Original Python version.

def fib(i: int) -> int:
    if i == 0 or i == 1:
        return 1
    return fib(i - 1) + fib(i - 2)

Transpiled Rust code:

fn fib(i: i32) -> i32 {
    if i == 0 || i == 1 {
        return 1;
    }
    return (fib((i - 1)) + fib((i - 2)));
}

Transpiled code for other languages:

https://github.com/adsharma/py2many/tree/main/tests/expected (fib*)

Trying it out

Local installation

Windows Local installation:

setup.py install --user  # installs to $HOME/.local

OR

Linux

sudo ./setup.py install  # installs systemwide

Transpiling

To run Py2Many, you can use the following command

py2many --<lang>=1 <path> [--outdir=<out_path>] [--indent=<indent_val>] [--comment-unsupported=<True|False>] [--extension=<True|False>] [--suffix=<suffix_val>] [--force=<True|False>] [--typpete=<True|False>] [--project=<True|False>] [--expected=<exp_path>] [--config=<config_path>]
  • lang: The language we want to use (See examples in section below)
  • path: Is either a path to a Python module or a folder containing Python modules.
  • outdir: Where to output the transpiled results. If this is not specified when path is a folder, py2many will create a new folder with the name of the original folder and add the suffix -py2many. The default is None
  • indent: Indentation to use in languages that care. The default is None
  • comment-unsupported: Place unsupported constructs in comments. The default is False
  • extension: Build a python extension. The default is False
  • suffix: Alternate suffix to use instead of the default one for the language. The default is None
  • force: When output and input are the same file, force overwriting. The default is False
  • typpete: Use typpete for inference. The default is False
  • project: Create a project when using directory mode. The default is True
  • expected: Location of output files to compare. Can either be a directory containing the expected file or a file. The file must have the same name as the input file.
  • config: Input configuration files for the transpiler. They can be used to add external annotations to the Python source code or inject flags for the transpiler

Configuration files

We provide the layout of a possible configuration file below:

[DEFAULT]
<default_param> = <val>

[FLAGS]
<flag> = True | False

[ANNOTATIONS]
<annotation_file_name>.yaml

Dependencies

Please install the following modules before running Py2Many:

pip install toposort

Example

Add the py2many script to your $PATH and run:

py2many --cpp=1 tests/cases/fib.py
py2many --rust=1 tests/cases/fib.py
py2many --julia=1 tests/cases/fib.py
py2many --kotlin=1 tests/cases/fib.py
py2many --nim=1 tests/cases/fib.py
py2many --dart=1 tests/cases/fib.py
py2many --go=1 tests/cases/fib.py

Compiling:

clang tests/cases/fib.cpp
rustc tests/cases/fib.rs
...

Requirements:

  • python 3
  • clang
  • rustc

Many of the transpilers rely on a language specific formatter to parse the output and reformat it. Typically this is the most prominent formatter for the language, such as rustfmt for Rust.

Most of the transpilers also rely on external libraries to provide bridges from Python constructs to the target language.

The steps to install these external libraries can be found in .github/workflows/main.yml.

Contributing

See CONTRIBUTING.md for how to test your changes and contribute to this project.

About

Python to CLike languages transpiler

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Python 97.1%
  • Rust 0.9%
  • Julia 0.7%
  • C++ 0.3%
  • Dart 0.3%
  • Go 0.2%
  • Other 0.5%