Skip to content

Instantly share code, notes, and snippets.

@podhmo
Created July 5, 2021 05:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save podhmo/f8b263b93fc4127713b4d91a7e2bb7bb to your computer and use it in GitHub Desktop.
Save podhmo/f8b263b93fc4127713b4d91a7e2bb7bb to your computer and use it in GitHub Desktop.
from dataclasses import dataclass
import configlang
@dataclass
class Point:
x: int
y: int
@dataclass
class Pair:
left: Point
right: Point
def run(y: int) -> dict:
p0 = Point(x=10, y=y)
pair = f(y)
p1 = Point(x=20, y=y)
def f(y):
p0 = Point(x=10, y=y)
p1 = Point(x=20, y=y)
return Pair(p0, p1)
print(configlang.run_dsl(run))
# {'y': 20, 'p0': Point(x=10, y=20), 'pair': Pair(left=Point(x=10, y=20), right=Point(x=20, y=20)), 'p1': Point(x=20, y=20)}
import inspect
import ast
import sys
def transform(fn, *, globals: dict):
"""
transform
```
<code>
```
to
```
# try:
_exception = None
<code>
except Exception as exc:
_exception = exc
finally:
return locals()
```
"""
t: ast.Module = ast.parse(inspect.getsource(fn))
assert len(t.body) == 1, len(t.Body)
node = t.body[0]
assert isinstance(node, ast.FunctionDef), type(node)
node_body = node.body
node.body = [
ast.Assign(
targets=[ast.Name(id="_exception", ctx=ast.Store())],
value=ast.Constant(value=None),
),
ast.Try(
body=node_body,
handlers=[
ast.ExceptHandler(
type=ast.Name(id="Exception", ctx=ast.Load()),
name="exc",
body=[
ast.Assign(
targets=[ast.Name(id="_exception", ctx=ast.Store())],
value=ast.Name(id="exc", ctx=ast.Load()),
)
],
)
],
orelse=[],
finalbody=[
ast.Return(
value=ast.Call(
func=ast.Name(id="locals", ctx=ast.Load()), args=[], keywords=[]
)
)
],
),
]
ast.fix_missing_locations(node)
offset = fn.__code__.co_firstlineno - 1
for x in ast.walk(node):
if hasattr(x, "lineno"):
x.lineno += offset
# todo: bind fn.__code__ (side effect)
filename = fn.__code__.co_filename
# filename = "<ast>"
code = compile(t, filename, "exec")
D = {}
exec(code, globals, D)
transformed = D[fn.__name__]
# transformed.__code__.co_firstlineno = fn.__code__.co_firstlineno
return transformed
def run_dsl(run, *, globals=None, depth=1):
if globals is None:
frame = sys._getframe(depth)
globals = frame.f_globals
fn = transform(run, globals=globals)
resources = fn(y=20)
exc: Exception = resources.pop("_exception", None)
if exc is not None:
# te = traceback.TracebackException.from_exception(exc)
# print("".join(te.format()))
raise exc from None
return resources
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment