All Projects → nvbn → Py Backwards

nvbn / Py Backwards

Python to python compiler that allows you to use Python 3.6 features in older versions.

Programming Languages

python
139335 projects - #7 most used programming language

Labels

Projects that are alternatives of or similar to Py Backwards

Gleam
⭐️ A friendly language for building type-safe, scalable systems!
Stars: ✭ 3,463 (+1058.19%)
Mutual labels:  compiler
Re Flex
The regex-centric, fast lexical analyzer generator for C++ with full Unicode support. Faster than Flex. Accepts Flex specifications. Generates reusable source code that is easy to understand. Introduces indent/dedent anchors, lazy quantifiers, functions for lex/syntax error reporting, and more. Seamlessly integrates with Bison and other parsers.
Stars: ✭ 274 (-8.36%)
Mutual labels:  compiler
Finn
Dataflow compiler for QNN inference on FPGAs
Stars: ✭ 284 (-5.02%)
Mutual labels:  compiler
Seq
A high-performance, Pythonic language for bioinformatics
Stars: ✭ 263 (-12.04%)
Mutual labels:  compiler
Mosml
Moscow ML is a light-weight implementation of Standard ML (SML), a strict functional language widely used in teaching and research.
Stars: ✭ 271 (-9.36%)
Mutual labels:  compiler
Write You A Haskell
Building a modern functional compiler from first principles. (http://dev.stephendiehl.com/fun/)
Stars: ✭ 3,064 (+924.75%)
Mutual labels:  compiler
Duckuino
Simple DuckyScript to Arduino C converter.
Stars: ✭ 263 (-12.04%)
Mutual labels:  compiler
Ante
The compile-time language
Stars: ✭ 295 (-1.34%)
Mutual labels:  compiler
Vult
Vult is a transcompiler well suited to write high-performance DSP code
Stars: ✭ 272 (-9.03%)
Mutual labels:  compiler
Shecc
A self-hosting and educational C compiler
Stars: ✭ 286 (-4.35%)
Mutual labels:  compiler
Clang
Mirror kept for legacy. Moved to https://github.com/llvm/llvm-project
Stars: ✭ 2,880 (+863.21%)
Mutual labels:  compiler
Yabfc
Yet Another Brainfuck Compiler; No dependencies and from the ground up
Stars: ✭ 269 (-10.03%)
Mutual labels:  compiler
Rascal
The implementation of the Rascal meta-programming language (including interpreter, type checker, parser generator, compiler and JVM based run-time system)
Stars: ✭ 284 (-5.02%)
Mutual labels:  compiler
Smlvm
Smallrepo Virtual Machine
Stars: ✭ 265 (-11.37%)
Mutual labels:  compiler
Datafun
Research on integrating datalog & lambda calculus via monotonicity types
Stars: ✭ 287 (-4.01%)
Mutual labels:  compiler
Mint
🍃 A refreshing programming language for the front-end web.
Stars: ✭ 3,607 (+1106.35%)
Mutual labels:  compiler
Clangwarnings.com
A list of Clang warnings and their descriptions.
Stars: ✭ 276 (-7.69%)
Mutual labels:  compiler
Sucrase
Super-fast alternative to Babel for when you can target modern JS runtimes
Stars: ✭ 4,436 (+1383.61%)
Mutual labels:  compiler
Lbforth
Self-hosting metacompiled Forth, bootstrapping from a few lines of C; targets Linux, Windows, ARM, RISC-V, 68000, PDP-11, asm.js.
Stars: ✭ 293 (-2.01%)
Mutual labels:  compiler
C Compiler
C--compiler which implements LL(1)\LR(0)\SLR\LR(1) and semantic analysis and MIPS generate
Stars: ✭ 286 (-4.35%)
Mutual labels:  compiler

Py-backwards Build Status

Python to python compiler that allows you to use some Python 3.6 features in older versions, you can try it in the online demo.

Requires Python 3.3+ to run, can compile down to 2.7.

Supported features

Target 3.5:

Target 3.4:

Target 3.3:

Target 3.2:

Target 2.7:

For example, if you have some python 3.6 code, like:

def returning_range(x: int):
    yield from range(x)
    return x


def x_printer(x):
    val: int
    val = yield from returning_range(x)
    print(f'val {val}')


def formatter(x: int) -> dict:
    items: list = [*x_printer(x), x]
    print(*items, *items)
    return {'items': items}


result = {'x': 10, **formatter(10)}
print(result)


class NumberManager:
    def ten(self):
        return 10

    @classmethod
    def eleven(cls):
        return 11


class ImportantNumberManager(NumberManager):
    def ten(self):
        return super().ten()

    @classmethod
    def eleven(cls):
        return super().eleven()


print(ImportantNumberManager().ten())
print(ImportantNumberManager.eleven())

You can compile it for python 2.7 with:

➜ py-backwards -i input.py -o output.py -t 2.7

Got some ugly code and ensure that it works:

➜ python3.6 input.py
val 10
0 1 2 3 4 5 6 7 8 9 10 0 1 2 3 4 5 6 7 8 9 10
{'x': 10, 'items': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}
10
11
➜ python2 output.py                           
val 10
0 1 2 3 4 5 6 7 8 9 10 0 1 2 3 4 5 6 7 8 9 10
{'x': 10, 'items': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}
10
11

Usage

Installation:

pip install py-backwards

Compile code:

py-backwards -i src -o compiled -t 2.7

Testing compiled code

For testing compiled code with each supported python version you can use tox and tox-py-backwards. You need to install them:

pip install tox tox-py-backwards

Fill tox.ini (py_backwards = true in testenv section enables py-backwards), like:

[tox]
envlist = py27,py33,py34,py35,py36

[testenv]
deps = pytest
commands = py.test
py_backwards = true

And run tests with:

tox

Distributing compiled code

For distributing packages compiled with py-backwards you can use py-backwards-packager. Install it with:

pip install py-backwards-packager

And change setup import in setup.py to:

try:
    from py_backwards_packager import setup
except ImportError:
    from setuptools import setup

By default all targets enabled, but you can limit them with:

setup(...,
      py_backwards_targets=['2.7', '3.3'])

After that your code will be automatically compiled on bdist and bdist_wheel.

Running on systems without Python 3.3+

You can use docker for running py-backwards on systems without Python 3.3+, for example for testing on travis-ci with Python 2.7:

docker run -v $(pwd):/data/ nvbn/py-backwards -i example -o out -t 2.7

Development

Setup:

pip install .
python setup.py develop
pip install -r requirements.txt

Run tests:

 py.test -vvvv --capture=sys --enable-functional

Run tests on systems without docker:

 py.test -vvvv

Writing code transformers

First of all, you need to inherit from BaseTransformer, BaseNodeTransformer (if you want to use NodeTransfromer interface), or BaseImportRewrite (if you want just to change import).

If you use BaseTransformer, override class method def transform(cls, tree: ast.AST) -> TransformationResult, like:

from ..types import TransformationResult
from .base import BaseTransformer


class MyTransformer(BaseTransformer):
    @classmethod
    def transform(cls, tree: ast.AST) -> TransformationResult:
        return TransformationResult(tree=tree,
                                    tree_changed=True,
                                    dependencies=[])

If you use BaseNodeTransformer, override visit_* methods, for simplification this class have a whole tree in self._tree, you should also set self._tree_changed = True if the tree was changed:

from .base import BaseNodeTransformer


class MyTransformer(BaseNodeTransformer):
    dependencies = []  # additional dependencies

    def visit_FunctionDef(self, node: ast.FunctionDef) -> ast.FunctionDef:
        self._tree_changed = True  # Mark that transformer changed tree
        return self.generic_visit(node)

If you use BaseImportRewrite, just override rewrites, like:

from .base import BaseImportRewrite


class MyTransformer(BaseImportRewrite):
    dependencies = ['pathlib2']

    rewrites = [('pathlib', 'pathlib2')]

After that you need to add your transformer to transformers.__init__.transformers.

It's hard to write code in AST, because of that we have snippets:

from ..utils.snippet import snippet, let, extend


@snippet
def my_snippet(class_name, class_body):
    class class_name:  # will be replaced with `class_name`
        extend(class_body)  # body of the class will be extended with `class_body`
        
        def fn(self):
            let(x)  # x will be replaced everywhere with unique name, like `_py_backwards_x_1`
            x = 10
            return x

And you can easily get content of snippet with:

my_snippet.get_body(class_name='MyClass',
                    class_body=[ast.Expr(...), ...])

Also please look at tree utils, it contains such useful functions like find, get_parent and etc.

Related projects

License MIT

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].