Reference

The command line, the modes, and exactly what subset of Python 3 pyc compiles today.

Usage

$ pyc [options] <file.py>

pyc reads <file.py> and everything it imports, analyzes the whole program, and writes a native executable. The intermediate C is kept as <file.py>.c.

Options

FlagEffect
-o <path>, --output <path>Output binary path. Default: the input file name with its extension stripped.
-x, --execCompile (cached in ~/.cache/pyc) and run. Arguments after the script go to the program. For #! lines.
--strictCPython semantics or a compile error: every type violation is fatal, and no accommodations apply.
--permissiveThe default. Named accommodations are allowed, and each one warns where it applies.
--safePermissive, and also zero-initialize locals that may be read before assignment.
--refuse-impreciseRefuse a program whose inference left a container element or a parameter untyped.
-b, --emit-llvmUse the LLVM backend.
-j, --jitCompile with LLVM and run in-process (implies -b).
--replInteractive REPL, backed by the JIT.
-O, --optimizeCompile the generated C at -O2 (the default).
--no-optimizeCompile the generated C at -O0, for debugging.
-g, --debug-infoEmit debug information.
--htmlEmit an HTML view of the type-annotated program.
-D <dir>, --system-directory <dir>pyc's library directory. Default: $PYC_SYSTEM_DIRECTORY, else ., else the pyc executable's directory.
-v, --verbose / -d, --debugMore output; repeat for more. --help also lists the development options.

Modes

Static typing without boxing can't express everything CPython does. pyc's rule is that it never deviates silently.

  • --strict: the program has CPython's semantics, or it does not compile.
  • --permissive (the default) additionally allows a few named accommodations. For example, a numeric slot holding both int and float is widened to float. Each accommodation is behind a named flag, warns where it applies, and is off under --strict.

A value that genuinely holds two unrelated types is refused in every mode, with the variable and the union named. More in Strict dialect.

Module search path

Imports resolve against the current directory, then <pyc-dir>/pyc_lib/, then each directory in PYTHONPATH. The source file's own directory is not searched, so compile from the program's directory or add it to PYTHONPATH.

$ PYTHONPATH=/my/libs pyc myprogram.py

Supported Python

ClassesInheritance, super(), class attributes, operator overloading, __str__/__repr__, __iter__/__next__, __enter__/__exit__, read-only @property, @staticmethod, @classmethod (cls(...))
FunctionsClosures, nonlocal/global, lambdas, default and mutable default arguments, *args, nested functions, local classes
Exceptionstry/except/else/finally, raise, user hierarchies, built-in exceptions raised by the runtime
Generatorsyield, yield from, send(), return values
async / awaitCompiled to coroutines and run on pyc's own event loop (no asyncio module yet)
Control flowif/elif/else, for/while with else, with, match/case (all PEP 634 patterns), comprehensions, generator expressions, starred assignment
Built-in typesint (64-bit), float, bool, str, bytes, bytearray, list, tuple, dict, set, range, slice, None
Stringsf-strings, %-formatting, the str method set
Modulesimport, from … import, packages and relative imports, all resolved at compile time

Language extensions

pyc's builtin library (__pyc__/) is itself Python, written with a few compiler directives. They are available to library authors, and are the way to bind a C function:

DirectivePurpose
__pyc_c_call__(ret, fn, ...)Call a C function inline
__pyc_primitive__(sym, ...)Invoke a compiler primitive
__pyc_char__The uint8 / C char type
__pyc_operator__Access C-level operators directly
__pyc_insert_c_header__(h)Include a C header in the generated code
@vector("s")Declare a class as a fixed-size value-type vector
pyc_lib/math.py (excerpt)
def sqrt(x): return __pyc_c_call__(float, "sqrt", float, x)

Limitations

Out of scope by design, because they conflict with whole-program static typing:

  • eval, exec, dynamic import, and getattr/setattr with run-time names
  • The full metaclass protocol, and the CPython C-extension API
  • Values that need boxing: one slot holding unrelated types over time

Not yet supported, each tracked by an issue:

  • **kwargs and keyword-only parameters (issues/182)
  • Property setters and deleters (issues/007)
  • complex
  • Attribute reads through cls in a @classmethod (issues/184)
  • Integers past 64 bits. Literals that don't fit are warned, and refused under --strict.
  • The standard library is limited to the modules in pyc_lib/. See Libraries.

The full list, including known wrong answers under repair, is in issues/ and ifa/issues/.