this package is heavily inspired by srcgen .
(todo: gentle introduction)
- generating code with with-syntax
- string injection after writing string
from prestring.python import PythonModule
m = PythonModule()
with m.class_("Point", metaclass="InterfaceMeta"):
with m.def_("__init__", "self", "value"):
m.stmt("self.value = value")
with m.def_("__str__", "self"):
m.return_("self.value")
output is.
class Point(object, metaclass=InterfaceMeta)
def __init__(self, value):
self.value = value
def __str__(self):
return self.value
from prestring.python import PythonModule
m = PythonModule()
with m.def_("setup", "config"):
import_area = m.submodule()
m.sep()
for k in ["a", "b", "c", "d", "e"]:
import_area.stmt("from .plugins import {k}_plugin", k=k)
m.stmt("config.activate({}_plugin)", k)
print(m)
def setup(config):
from .plugins import(
a_plugin,
b_plugin,
c_plugin,
d_plugin,
e_plugin
)
config.activate(a_plugin)
config.activate(b_plugin)
config.activate(c_plugin)
config.activate(d_plugin)
config.activate(e_plugin)
- prestring.output
- prestring.python.transform, prestring.text.transform
prestring.output can write multiple files.
import sys
from prestring.python import Module
from prestring.output import output, cleanup_all # noqa
dst = sys.argv[1]
with output(root=dst) as fs:
with fs.open("projects/x.txt", "w") as wf:
print("hello x", file=wf)
print("bye x", file=wf)
with fs.open("projects/y.txt", "w") as wf:
print("hello y", file=wf)
print("bye y", file=wf)
with fs.open("projects/z.py", "w", opener=Module) as m:
with m.def_("hello"):
m.stmt("print('hello')")
Above code will generate three files. if creating directory is needed, it will be created automatically.
$ python src/main.py dst
[D] create dst/projects
[F] create dst/projects/x.txt
[F] create dst/projects/y.txt
[F] create dst/projects/z.py
On rerun, no message is displayed. And rerun with VERBOSE=1 var env to see more detailed output.
$ python src/main.py dst
$ VERBOSE=1 python src/main.py dst
[F] no change dst/projects/x.txt
[F] no change dst/projects/y.txt
[F] no change dst/projects/z.py
Running with CONSOLE=1 varenv or calling with use_console=True option, doesn't save files.
$ CONSOLE=1 python src/main.py dst
[F] update dst/projects/x.txt
[F] update dst/projects/y.txt
[F] update dst/projects/z.py
# more verbose output
VERBOSE=1 CONSOLE=1 python src/00/main.py dst/00/create
# dst/00/create/projects/x.txt
----------------------------------------
hello x
bye x
# dst/00/create/projects/y.txt
----------------------------------------
hello y
bye y
# dst/00/create/projects/z.py
----------------------------------------
def hello():
print('hello')
the Transform function means converting raw source code (or text) to prestring's code. And you can use python -m prestring.python (or running python -m prestring.text) as a CLI command, as follows.
$ cat hello.py
def hello(name: str, *, message: str = "hello world"):
"""
greeting message
"""
print(f"{name}: {message}")
if __name__ == "__main__":
hello("foo")
$ python -m prestring.python hello.py
from prestring.python import PythonModule
def gen(*, m=None, indent=' '):
m = m or PythonModule(indent=indent)
import textwrap
with m.def_('hello', 'name: str', '*', 'message: str = "hello world"'):
m.docstring(textwrap.dedent("""
greeting message
""").strip())
m.stmt('print(f"{name}: {message}")')
with m.if_('__name__ == "__main__"'):
m.stmt('hello("foo")')
return m
if __name__ == "__main__":
m = gen(indent=' ')
print(m)
Of course, reversible.
$ python <(python -m prestring.python hello.py)
def hello(name: str, *, message: str = "hello world"):
"""
greeting message
"""
print(f"{name}: {message}")
if __name__ == "__main__":
hello("foo")
$ python hello.py
foo: hello world
$ python <(python <(python -m prestring.python hello.py))
foo: hello world
If you want to prestring's expression as first step, in other language, prestring.text is probably useful.
$ python -m prestring.text --tab hello.go
from prestring.text import Module
def gen(*, m=None, indent='\t'):
m = m or Module(indent=indent)
m.stmt('package main')
m.sep()
m.stmt('import (')
with m.scope():
m.stmt('"fmt"')
m.stmt('"os"')
m.stmt(')')
m.sep()
m.stmt('// Hello is print Hello')
m.stmt('func Hello(name string) {')
with m.scope():
m.stmt('fmt.Printf("%s: Hello", name)')
m.stmt('}')
m.sep()
m.stmt('func main() {')
with m.scope():
m.stmt('var name string')
m.stmt('if len(os.Args) > 1 {')
with m.scope():
m.stmt('name = os.Args[1]')
m.stmt('} else {')
with m.scope():
m.stmt('name = "foo"')
m.stmt('}')
m.stmt('// with block')
m.stmt('{')
with m.scope():
m.stmt('Hello(name)')
m.stmt('}')
m.stmt('}')
return m
if __name__ == "__main__":
m = gen(indent='\t')
print(m)