astpp
Self-Inlining Python Macro Preprocessor & Runtime Polyfill Library
Project Homepage: https://github.com/f-fix/astpp
PyPI Project Page: https://pypi.org/project/astpp/
Overview
astpp is a dual-use Python library and AST-level macro preprocessor designed for cross-runtime codebases targeting MicroPython, PyPy, and CPython:
-
Runtime Polyfill (Zero-Build Development): Importing
astppprovides zero-overhead, runtime-compatible implementations of MicroPython compiler pragmas (const,micropython.native,micropython.viper) and conditional decorators (keep,omit,keep_if,omit_if). Scripts run directly under CPython, PyPy, or MicroPython without requiring an explicit compilation or preprocessing step. -
Compile-Time Preprocessor (Zero-Dependency Production Builds): When invoked as a script or via
astpp_main(),astppinspects the consumer's Abstract Syntax Tree (AST), removesfrom astpp import ...statements completely, and inlines minimal self-contained fallback definitions copied directly from its own source code. The emitted code has zero external runtime dependencies onastpp.py.
Installation
Via pip (CPython / PyPy / Host PC)
# Install from PyPI:
pip install astpp
# Or install directly from GitHub:
pip install git+https://github.com/f-fix/astpp.git
# Or install locally in editable development mode:
pip install -e .
Via mip (MicroPython)
# In MicroPython REPL (on Wi-Fi / Ethernet enabled board):
import mip
mip.install("github:f-fix/astpp")
# Or from your host computer over USB/UART via mpremote:
mpremote mip install github:f-fix/astpp
Key Features
- Macro Definitions (
-DNAME=VALUE): Rewrites target assignmentsNAME = ...toNAME = const(VALUE). Inlined constants are propagated directly into expressions throughout the module. - Dead-Branch Elimination:
Resolves
if,elif, andelsebranches whose conditions evaluate to compile-time constants (including comparisons==,!=,<,<=,>,>=,is,is not,in,not in, and boolean logicnot,and,or). Dead branches are pruned from the AST, while active branches are promoted or spliced without leaving ghostpassstatements. - Conditional CLI / Main Omission (
_OMIT_MAIN): Supports conditional omission of CLI logic via_OMIT_MAIN = const(False)with@omit_if(_OMIT_MAIN)andif not _OMIT_MAIN:guards, enabling compact library-only builds viaastpp -D_OMIT_MAIN=True. - Symmetric Conditional Decorators (
@keep,@omit,@keep_if,@omit_if):@keep: Preserves the definition and strips the decorator (zero runtime overhead).@omit: Drops the decorated function or class from the parse tree completely.@keep_if(cond)/@omit_if(cond): Evaluates compile-time conditions and resolves symmetrically to@keepor@omit.
- Compiler Optimization Parity (
-O,-OO,-O0–-O3):- Default /
-O0: Preserves__debug__and assertions for downstream runtime evaluation. -O/-O1: Sets__debug__ = Falseand purges allassertstatements.-OO/-O2: Purges assertions and strips docstrings from modules, classes, and functions.-O3: Full constant propagation, dead branch pruning, and inlining.
- Default /
- Self-Contained Testing (
--test): Executes built-in regression unit tests that parse and validate the documented examples directly from the module docstring.
Command-Line Usage
# Transform via stdin / stdout filter:
python3 astpp.py [-O[n]] [-DNAME=VAL ...] < input.py > output.py
# Transform using named input and output files:
python3 astpp.py -O3 -D_IS_DESKTOP_PY=False input.py -o output.py
# Display rich formatted help:
python3 astpp.py --help
# Run self-contained test suite:
python3 astpp.py --test
CLI Options
usage: astpp [-h] [-o OUTPUT] [-D NAME=VALUE] [-O [LEVEL]] [-OO] [--test]
[input]
Self-Inlining Macro Preprocessor & Runtime Polyfill Library.
positional arguments:
input Input Python source file or '-' for stdin (default: '-')
options:
-h, --help Show this help message and exit
-o OUTPUT, --output OUTPUT
Output destination file or '-' for stdout (default: '-')
-D NAME=VALUE Define macro replacement or override constant (e.g. -DNAME=VAL or -DNAME)
-O [LEVEL] Optimization level: -O (strip asserts, force __debug__=False),
-OO or -O2 (strip docstrings), -O3 (full)
-OO Optimization level 2: strip assertions, __debug__=False, and docstrings
--test Run self-contained unit test suite
Programmatic API
from astpp import astpp_main
import io
source = """
from astpp import const
BUFFER_SIZE = const(1024)
"""
in_stream = io.StringIO(source)
out_stream = io.StringIO()
rc = astpp_main(["-O3", "-DBUFFER_SIZE=512"], in_stream, out_stream)
assert rc == 0
print(out_stream.getvalue())
Documented & Tested Transformation Examples
Example 1: Import Inlining & Self-Parsing
Input:
from astpp import const
X = const(10)
Flags: -O3
Output:
try:
from micropython import const
except ImportError:
def const(x):
return x
X = const(10)
Example 2: Constant Definition & In-Line Override
Input:
_X = const(True)
BUFFER_SIZE = const(1024)
Flags: -DBUFFER_SIZE=512 -O
Output:
_X = const(True)
BUFFER_SIZE = const(512)
Example 3: Conditional Decorator Pruning
Input:
@keep_if(_IS_DESKTOP_PY)
def desktop_helper():
return 42
Flags: -D_IS_DESKTOP_PY=False
Output: (Empty — function deleted from AST)
Example 4: Assertions and Debug Block Stripping
Input:
assert 1 == 1, 'invariant'
if __debug__:
def debug_only():
pass
Flags: -O
Output: (Empty — assertions and debug blocks pruned)
Example 5: Native Decorator Stripping via Macro Mapping
Input:
@micropython.native
def fast_calc(x):
return x * 2
Flags: -Dmicropython.native=keep
Output:
def fast_calc(x):
return x * 2
Function & Runtime Reference
const(x)
Identity fallback for compile-time constants on non-MicroPython runtimes. On MicroPython, const() is intercepted natively at parse time to inline values. On CPython and PyPy, this function acts as an identity pass-through returning x.
keep(obj)
Identity decorator: keeps the decorated function or class as-is. When processed by astpp, the @keep decorator is stripped from the AST so that the compiled output incurs zero runtime decorator invocation overhead.
omit(obj)
Omission decorator: drops the decorated function or class completely. When processed by astpp, any node decorated with @omit is purged from the parse tree.
keep_if(cond)
Conditional decorator factory that preserves the target definition if cond is True. Returns the identity decorator keep if cond is True, or omit if False.
omit_if(cond)
Conditional decorator factory that drops the target definition if cond is True. Returns the omission decorator omit if cond is True, or keep if False.
_MicroPythonShim
Desktop compatibility shim providing no-op decorators (native = staticmethod(keep), viper = staticmethod(keep)) for MicroPython compiler pragmas on non-MicroPython runtimes.
License
MIT License. See LICENSE for details.
Note on the code and the tools used to write it
Parts of this code were written (including some initial ones that began in other, separate projects) with assistance from LLM-integrated coding tools. If you don't like it, feel free to use other software or rewrite parts you dislike. PRs are welcome!
How did I end up using those? Don't I dislike slop?
Yes, I hate slop. This project began because I wanted tape image conversion tools where the conversion steps were all clearly documented and readable code, but which also performed well enough in terms of accuracy to actually be the tool I use. I started out writing the tools myself, but my manual attempts hadn't yielded comparable accuracy to existing closed-source tools for some steps, so I started using the tools to help find the bugs and suggest improvements, and IMO the result is now good enough to actually be useful in some scenarios. In terms of slop, the tool-generated code doesn't closely resemble any existing solutions I have found. Rather it's a fairly passable translation of my requests into Python.
Metadata
Release files for astpp 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| astpp-0.1.1.tar.gz | 14.0 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| astpp-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 26.9 kB
Release files / astpp-0.1.1.tar.gz
| Download URL | astpp-0.1.1.tar.gz |
|---|---|
| Size | 14.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e8d92b48c9c6292f844c615ae8d7c6ae46eeffbec9e890de8cccf31a5418fc10
|
|
BLAKE2b-256 checksum How to use checksums |
720c29ddf5e2d3747b85166e08ec0620a2eaa59e6e42cc7c60057146ea3a862c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.8
|
Release files / astpp-0.1.1-py3-none-any.whl
| Download URL | astpp-0.1.1-py3-none-any.whl |
|---|---|
| Size | 12.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
537618d14b8e1a33f8d5224a1b68162aae8781ffab6b88852a854eaf7a000990
|
|
BLAKE2b-256 checksum How to use checksums |
42bce85db57860593048ad7cc16409aa7a173cd2c6ae6edffbe366d2b3f06cf9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.8
|
Security for astpp 0.1.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.