What a Program Looks Like

One complete working program, and a plain list of the shapes that do not compile yet. Read it in a minute and you will know whether your code is in scope.

Compiles and runs

Classes holding collections of instances, methods calling methods, string and dict work, comprehensions, f-strings, exceptions, generators, imports across your own files.

Refused, loudly

Everything not implemented is a compile error naming the construct, its line, the enclosing function, and a workaround. A refusal is the design, not a bug.

Answers differently

One documented case: int is 32 bits and wraps instead of growing. Everywhere else the rule is Python's answer or a loud failure.

A whole program

This is examples/shopping_cart.py from the repository, unedited. Nothing in it was chosen to show off a compiler feature, and its results are asserted against what CPython answers for the same source, under three WebAssembly runtimes.

shopping_cart.py
class Item:
    def __init__(self, name: str, price: float, qty: int):
        self.name = name
        self.price = price
        self.qty = qty

    def subtotal(self) -> float:
        return self.price * self.qty


class Cart:
    def __init__(self):
        self.items = []
        self.count = 0

    def add(self, name: str, price: float, qty: int):
        item = Item(name, price, qty)
        self.items.append(item)
        self.count = self.count + 1

    def total(self) -> float:
        out: float = 0.0
        for it in self.items:
            out = out + it.subtotal()
        return out


def discount_rate(total: float) -> float:
    if total >= 100.0:
        return 0.10
    if total >= 50.0:
        return 0.05
    return 0.0


def checkout() -> float:
    cart = Cart()
    cart.add("widget", 9.99, 3)
    cart.add("gadget", 24.50, 2)
    cart.add("doohickey", 5.00, 4)
    subtotal = cart.total()
    return subtotal - subtotal * discount_rate(subtotal)
Annotations
Parameter and return annotations pick the WebAssembly value types. A collection whose elements you compare, sort, or use as dict keys needs the parameterised form: List[str], not a bare list.
Entry points
Every module-level def is exported. There is no top-level run step, so module level holds definitions only; put the code that runs in a function, or under if __name__ == "__main__":.
Imports
import mod and from mod import f resolve sibling .py files from disk and link into the one output module. No PyPI packages: the supported subset is standard-library only.

What it costs

Median of nine release-build compilations on an Apple M1, via just benchmark. Wall-clock numbers from one machine, so read them for orders of magnitude, not percentages.

Program Source Compile Module Compile (opt) Module (opt)
shopping_cart2.0 KiB0.2 ms1.4 KiB1.2 ms1014 B
text_report3.4 KiB0.4 ms6.5 KiB5.8 ms5.7 KiB
library_project3.3 KiB0.5 ms3.6 KiB2.7 ms3.1 KiB
nested_collections4.7 KiB0.5 ms13.6 KiB4.1 ms12.7 KiB

A whole program compiles in well under a millisecond and produces a few kilobytes of WebAssembly, with no interpreter or runtime bundled in: the module is the program. Optimization is where the time goes. Binaryen costs 5 to 15 times the rest of the pipeline and takes 7 to 27% off the module, so it is worth running for something you ship and worth skipping in a fast edit loop, which is what CompilerOptions { optimize: false } is for. The first three rows are the end-to-end programs above; nested_collections is the feature example with the largest module, as a second data point at a different shape.

The rule the compiler holds itself to: a construct either produces Python's answer or fails loudly. It never quietly produces a different one.

Integer width is the single documented exception. int is a 32-bit two's-complement value, so 1000000 * 1000000 wraps to -727379968 where CPython answers 1000000000000. If your arithmetic can exceed 32 bits, your program is not in the supported subset.

Shapes that do not compile

Tagged by what happens when you try. refused is a compile error you will see immediately; differs is a case where the answer is not Python's; workaround means there is a supported way to write the same thing.

Where to look next

The repository's examples/ directory holds the programs this page is drawn from, each asserted against CPython in the test suite.