Cute Python codegen
Project description
trolskgen
Ergonomic codegen for Python - pip install trolskgen.
Note on Python 3.14 template strings.
From Python 3.14 upwards, there are template strings, these make trolskgen significantly more succinct.
Where previously you'd do:
name = t("f")
func = t(
"""
def {name}():
...
""",
name=name,
)
trolskgen.to_source(func)
As of Python 3.14, you can do:
name = t"f"
func = t"""
def {name}():
...
"""
trolskgen.to_source(func)
There are some if sys.version_info >= (3, 14) flags around, but it should just work come release date.
trolskgen lets you easily build and compose ast.AST trees, and thereby easily generate source code. It doesn't handle any formatting concerns, just ruff format it afterwards. If you want comments, sorry, instead use a docstring or some Annotated[] wizardry.
Quick example:
import trolskgen
from trolskgen import t
func = t(
"""
def {name}():
...
""",
name="f",
)
trolskgen.to_source(func)
trolskgen.to_ast(func)
Gives you the source str:
def f():
...
And the ast.AST:
ast.Module(
body=[
ast.FunctionDef(
name="f",
args=ast.arguments(...),
body=[ast.Expr(value=ast.Constant(value=Ellipsis))],
decorator_list=[],
type_params=[],
)
],
)
A more complete example:
import datetime as dt
name = "MySpecialClass"
bases = [int, list]
field_name = "d"
fields = [
t(
"a: {type_}",
type_=str,
),
t(
"{field_name}: dt.date = {default}",
field_name=field_name,
default=dt.date(2000, 1, 1),
),
]
method = t(
"""
def inc(self) -> None:
self.{field_name} += dt.timedelta(days=1)
""",
field_name=field_name,
)
my_special_class_source = t(
"""
class {name}({bases:*}, float):
{fields:*}
{method}
""",
name=name,
bases=bases,
fields=fields,
method=method,
)
trolskgen.to_source(my_special_class_source)
Gives you the source str:
class MySpecialClass(int, list, float):
a: str
d: dt.date = dt.date(2000, 1, 1)
def inc(self) -> None:
self.d += dt.timedelta(days=1)
API
| Building templates |
|---|
trolskgen.t(s: str, **kwargs: Any) -> trolskgen.templates.Template |
Creates source templates. If you use the format string :*, it will splat in place - see above: {bases:*}, {fields:*}
This is redundant as of Python 3.14 - see above.
| Converting to AST/source |
|---|
trolskgen.to_ast(o: Any, *, config: Config) -> ast.AST |
trolskgen.to_source(o: Any, *, config: Config) -> str |
Try to convert o into an ast.AST/str representation.
The following are special cases for the value of o:
ast.ASTnodes - these just get passed straight back out.trolskgen.templates.Templateorstring.templatelib.Template- these get parsed as Python code.
trolskgen will generate sensible ASTs, for the following types:
Noneintfloatstrboollisttupledictsetclassesfunctionsdt.datetimedt.dateenum.EnumdataclassAnnotated,T | U, etc.pydantic.BaseModel
Note that in conjunction with ruff, we have a decent pretty printer that you can use for test diffs etc.
We can add our own classes/overrides using:
| Configuring/Overriding |
|---|
trolskgen.ConvertInterface |
trolskgen.Converter |
trolskgen.Config |
trolskgen.Config().prepend_converter(converter: Converter, *, before: Converter | None) -> Config |
If you own the class, you can just add a __trolskgen__ method that satisfies trolskgen.ConvertInterface.
For example:
class MyInterfaceClass:
def __trolskgen__(self, f: trolskgen.F) -> ast.AST:
return f(t("MyInterfaceClass({values:*})", values=[1, 2, 3]))
trolskgen.to_source(MyInterfaceClass()) == "MyInterfaceClass(1, 2, 3)"
Note that we use f to recursively call trolskgen.to_ast(...) while preserving the current Config.
If you don't own the class, you can build a trolskgen.Config with a custom Converter function.
For example, if you for some reason wanted to render all ints in the form x + 1, you could:
def custom_int_converter(o: Any, f: trolskgen.F) -> ast.AST | None:
if not isinstance(o, int):
return None
return f(t(f"{o - 1} + 1"))
config = trolskgen.Config().prepend_converter(custom_int_converter)
trolskgen.to_source([6, 9], config=config) == "[5 + 1, 8 + 1]"
Development
uv pip install -e '.[dev]'
mypy .
pytest -vv
uv pip install build twine
python -m build
twine check dist/*
twine upload dist/*
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file trolskgen-0.0.7.tar.gz.
File metadata
- Download URL: trolskgen-0.0.7.tar.gz
- Upload date:
- Size: 14.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1b1065ebb3bf1890bc121323395ec3e744868bbffcdf465cbdf29fac5fa97ff0
|
|
| MD5 |
729812673aa82384faadf12f2e8898f3
|
|
| BLAKE2b-256 |
5bb941d3532b89f49a58b43dd73fec1da695ce43827a190a03cc3e5138f02c46
|
File details
Details for the file trolskgen-0.0.7-py3-none-any.whl.
File metadata
- Download URL: trolskgen-0.0.7-py3-none-any.whl
- Upload date:
- Size: 11.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0d1ea61c5f20cf6adddfb9626514fdefa9053b0ee87ad557b7129ea337c647ef
|
|
| MD5 |
4e9f3c5e4771f95de7c877745617900c
|
|
| BLAKE2b-256 |
3d4fcc8524f46e3969963614ccb29376fc30f2d686eae5bf70a66e82bd7c7488
|