From 81c6e5f7f08fc5fa6851112f984a7dbd6128ba1e Mon Sep 17 00:00:00 2001 From: "Benjamin C. Wiley Sittler" Date: Mon, 19 Oct 2026 01:31:58 -0700 Subject: [PATCH] python-ecosys/astpp: Add `astpp` subset for micropython. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The full version of `astpp` on github abd PyPI is a self-inlining python macro preprocessor & runtime polyfill library. The AST parts run in big pythons, the runtime parts and the output both run in micropython too. This PR tries to add just the parts that run inside micropython as a `mip`-installable library. The subset here was made by running this, which used the pip-installed version of astpp running in CPython: ```bash astpp -O3 -D_OMIT_MAIN < ~/src/astpp/astpp.py > astpp.py && black astpp.py ``` This tool grew out of an audio tape archival project, but this particular piece proved useful enough in other projects to merit separation into its own standalone package/library. By adding `astpp` we make it possible to use exactly the same `const(`...`)` over in big python *and* in micropython, using the same syntax, and actually working at preprocessor-time when you use the `astpp` preprocessor - run the preprocessor in big pythons but use its outputs in all pythons including micropython. It also allows you to strip out debug code/assertions/docstrings. The `astpp` preprocessor does a version of `const` compatible with mpy-cross / micropython, that also works on "big" pythons. In the preprocessed output the contants' values will be inlined. It also allows you to do "conditional omission" so that parts of your code won't end up in the output - this is great if you have some fluffier features that make sense for "big" python, but you want them gone from your micropython version. It also supports -O/-O0/-O1/-O2/-O3/-OO optimization levels which do stuff like force `__debug__` to be `const(False)`, and strip out docstrings and such. Again, it's intended to reduce code size and token size. It also allows you to optionally replace things, and I use this to rewrite `@micropython.native` and `@micropython.viper` to `@keep` - which then gets stripped off by the preprocessor - allowing to easily build a version which can be mpy-cross compiled generically without being target CPU specific. In big python this module includes the preprocessor and a test suite too, but optimized builds omit the test suite and when you don't have the `ast` module the preprocessor itself won't be runnable. In any case, though, preprocessing your code actually gets rid of the `astpp` imports entirely and replaces the imported ports with small inlined replacements. I only tested on the Linux i386 port of micropython, but on that one it seems to work fine: ```bash micropython -c ' import mip mip.install("github:f-fix/astpp/astpp.py") from astpp import const, micropython @micropython.native def foo(bar): return dict(bar=bar) _X=const(3) print(foo(3)) ' ``` ``` Downloading github:f-fix/astpp/astpp.py to /home/bsittler/.micropython/lib Copying: /home/bsittler/.micropython/lib/astpp.py Done {'bar': 3} ``` Using the local version: ```bash micropython -c ' from astpp import const, micropython @micropython.native def foo(bar): return dict(bar=bar) _X=const(3) print(foo(3)) ' ``` ``` {'bar': 3} ``` Using the pip-installed version as a preprocessor: ```bash pipx install astpp && astpp -O3 <( echo ' from astpp import const, micropython @micropython.native def foo(bar): return dict(bar=bar) _X=const(3) print(foo(3)) ' ) ``` ``` installed package astpp 0.1.3, installed using Python 3.14.8 These apps are now available - astpp done! ✨ 🌟 ✨ try: from micropython import const except ImportError: def const(x): return x def keep(obj): return obj try: import micropython as _real_mpy except ImportError: _real_mpy = None if _real_mpy is not None: micropython = _real_mpy else: class _MicroPythonShim: native = staticmethod(keep) viper = staticmethod(keep) micropython = _MicroPythonShim() @micropython.native def foo(bar): return dict(bar=bar) print(foo(3)) ``` Running *that* in micropython: ``` micropython -c ' try: from micropython import const except ImportError: def const(x): return x def keep(obj): return obj try: import micropython as _real_mpy except ImportError: _real_mpy = None if _real_mpy is not None: micropython = _real_mpy else: class _MicroPythonShim: native = staticmethod(keep) viper = staticmethod(keep) micropython = _MicroPythonShim() @micropython.native def foo(bar): return dict(bar=bar) print(foo(3)) ' ``` ``` {'bar': 3} ``` The current alternative is to use micropython-specific imports and mpy-cross, but that provides equivalent benefits only on micropython. Using astpp those same benefits are realized on all pythons. I used generative AI tools when creating this PR, but a human has checked the code and is responsible for the code and the description above. Signed-off-by: Benjamin C. Wiley Sittler --- python-ecosys/astpp/astpp.py | 38 +++++++++++++++++++++++++++++++++ python-ecosys/astpp/manifest.py | 3 +++ 2 files changed, 41 insertions(+) create mode 100644 python-ecosys/astpp/astpp.py create mode 100644 python-ecosys/astpp/manifest.py diff --git a/python-ecosys/astpp/astpp.py b/python-ecosys/astpp/astpp.py new file mode 100644 index 000000000..9fecb60d0 --- /dev/null +++ b/python-ecosys/astpp/astpp.py @@ -0,0 +1,38 @@ +try: + from micropython import const +except ImportError: + + def const(x): + return x + + +def keep(obj): + return obj + + +def omit(obj): + return None + + +def keep_if(cond): + return keep if cond else omit + + +def omit_if(cond): + return omit if cond else keep + + +try: + import micropython as _real_mpy +except ImportError: + _real_mpy = None +if _real_mpy is not None: + micropython = _real_mpy +else: + + class _MicroPythonShim: + native = staticmethod(keep) + viper = staticmethod(keep) + + micropython = _MicroPythonShim() +__version__ = "0.1.3" diff --git a/python-ecosys/astpp/manifest.py b/python-ecosys/astpp/manifest.py new file mode 100644 index 000000000..19f3350bb --- /dev/null +++ b/python-ecosys/astpp/manifest.py @@ -0,0 +1,3 @@ +metadata(version="0.1.3", pypi="astpp") + +module("astpp.py")