Created
December 13, 2019 22:15
-
-
Save aldanor/3750deee879bf3591126a3ba975c1966 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "code", | |
"execution_count": 55, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"# NSFW: abuse `with` blocks to allow for 'namespaced code execution'" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 51, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"import ast\n", | |
"import inspect\n", | |
"import sys\n", | |
"\n", | |
"import astor\n", | |
"\n", | |
"\n", | |
"class scope:\n", | |
" def __init__(self):\n", | |
" self.ns = {}\n", | |
" \n", | |
" def __dir__(self):\n", | |
" return sorted(self.ns)\n", | |
" \n", | |
" def __getattr__(self, key):\n", | |
" return self.ns[key]\n", | |
" \n", | |
" def __enter__(self):\n", | |
" # get the parent frame\n", | |
" frame = inspect.currentframe().f_back\n", | |
" # get the source of the parent frame\n", | |
" try:\n", | |
" source = inspect.getsource(frame)\n", | |
" except:\n", | |
" source = frame.f_locals['__source__']\n", | |
" # parse the source code into AST\n", | |
" body = ast.parse(source)\n", | |
" # find the currently invoked 'with' statement\n", | |
" for node in ast.walk(body):\n", | |
" if getattr(node, 'lineno', 0) == frame.f_lineno:\n", | |
" assert isinstance(node, ast.With)\n", | |
" break\n", | |
" else:\n", | |
" assert 0\n", | |
" # wrap the body of 'with' in a new module\n", | |
" code = astor.to_source(ast.Module(node.body))\n", | |
" # inject source to allow nested with blocks\n", | |
" self.ns['__source__'] = code\n", | |
" # execute it\n", | |
" exec(code, frame.f_globals, self.ns)\n", | |
" del self.ns['__source__']\n", | |
" # and *after* interrupt stack trace to prevent execution...\n", | |
" sys.settrace(lambda *args, **keys: None)\n", | |
" frame.f_trace = lambda frame, event, arg: 1 / 0\n", | |
" \n", | |
" def __exit__(self, exc_type, exc_value, traceback):\n", | |
" # restore frame stack tracing\n", | |
" frame = inspect.currentframe().f_back\n", | |
" frame.f_trace = None\n", | |
" return True " | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 52, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"a=1\n", | |
"A: a=1\n", | |
"A: a=2\n", | |
"A: b=3\n", | |
"a=1\n", | |
"a=4\n", | |
"A: a=2\n", | |
"A: b=3\n", | |
"a=4\n", | |
"A.a = 5\n", | |
"A.b = 6\n" | |
] | |
} | |
], | |
"source": [ | |
"A = scope()\n", | |
"\n", | |
"a = 1\n", | |
"print(f'a={a}')\n", | |
"\n", | |
"with A:\n", | |
" print(f'A: a={a}')\n", | |
" a = 2\n", | |
" print(f'A: a={a}')\n", | |
" b = 3\n", | |
" print(f'A: b={b}')\n", | |
"\n", | |
"print(f'a={a}')\n", | |
"a = 4\n", | |
"print(f'a={a}')\n", | |
"\n", | |
"with A:\n", | |
" print(f'A: a={a}')\n", | |
" print(f'A: b={b}')\n", | |
" a = 5\n", | |
" b = 6\n", | |
" \n", | |
"print(f'a={a}')\n", | |
"print(f'A.a = {A.a}')\n", | |
"print(f'A.b = {A.b}')" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 54, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"a=1\n", | |
"A: a=1\n", | |
"A: a=2\n", | |
" B: a=1\n", | |
" B: a=10\n", | |
"A: a=100\n", | |
" B: a=10\n", | |
" B: a=20\n", | |
"A: a=100\n", | |
"a=1\n", | |
"a=3\n", | |
"B: a=20\n", | |
"B: a=20\n", | |
"A: a=100\n", | |
"A: a=4\n", | |
"a=3\n" | |
] | |
} | |
], | |
"source": [ | |
"A = scope()\n", | |
"B = scope()\n", | |
"\n", | |
"a = 1\n", | |
"print(f'a={a}')\n", | |
"\n", | |
"with A:\n", | |
" print(f'A: a={a}')\n", | |
" a = 2\n", | |
" print(f'A: a={a}')\n", | |
" with B:\n", | |
" print(f' B: a={a}')\n", | |
" a = 10\n", | |
" print(f' B: a={a}')\n", | |
" a = 100\n", | |
" print(f'A: a={a}')\n", | |
" with B:\n", | |
" print(f' B: a={a}')\n", | |
" a = 20\n", | |
" print(f' B: a={a}')\n", | |
" print(f'A: a={a}')\n", | |
"\n", | |
"print(f'a={a}')\n", | |
"a = 3\n", | |
"print(f'a={a}')\n", | |
"\n", | |
"with B:\n", | |
" print(f'B: a={a}')\n", | |
" a = 20\n", | |
" print(f'B: a={a}')\n", | |
" \n", | |
"with A:\n", | |
" print(f'A: a={a}')\n", | |
" a = 4\n", | |
" print(f'A: a={a}')\n", | |
"\n", | |
"print(f'a={a}')" | |
] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "Python [conda env:mercante-ai] *", | |
"language": "python", | |
"name": "conda-env-mercante-ai-py" | |
}, | |
"language_info": { | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 3 | |
}, | |
"file_extension": ".py", | |
"mimetype": "text/x-python", | |
"name": "python", | |
"nbconvert_exporter": "python", | |
"pygments_lexer": "ipython3", | |
"version": "3.6.8" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 4 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment