--- /dev/null
+
+from types import CodeType as Code
+import sys
+import traceback
+import __main__
+from ctypes import pythonapi, POINTER, c_long, cast
+import tokenize
+
+
+inspect_flag = cast(pythonapi.Py_InspectFlag, POINTER(c_long)).contents
+
+def set_inspect_flag(value):
+ inspect_flag.value = int(value)
+
+
+def update_code(codeobj, **kwargs):
+ fields = ["argcount", "kwonlyargcount", "nlocals", "stacksize", "flags",
+ "code", "consts", "names", "varnames", "filename", "name",
+ "firstlineno", "lnotab", "freevars", "cellvars"]
+
+ def field_values():
+ for field in fields:
+ value = kwargs.get(field, None)
+ if value is None:
+ yield getattr(codeobj, "co_{}".format(field))
+ else:
+ yield value
+
+ return Code(*field_values())
+
+def update_code_recursively(codeobj, **kwargs):
+ updated = {}
+
+ def update(codeobj, **kwargs):
+ result = updated.get(codeobj, None)
+ if result is not None:
+ return result
+
+ if any(isinstance(c, Code) for c in codeobj.co_consts):
+ consts = tuple(update(c, **kwargs) if isinstance(c, Code) else c
+ for c in codeobj.co_consts)
+ else:
+ consts = codeobj.co_consts
+
+ result = update_code(codeobj, consts=consts, **kwargs)
+ updated[codeobj] = result
+ return result
+
+ return update(codeobj, **kwargs)
+
+
+def get_code(path):
+ with tokenize.open(path) as f: # opens with detected source encoding
+ source = f.read()
+
+ try:
+ code = compile(source, path, "exec")
+ except UnicodeEncodeError:
+ code = compile(source, "<encoding error>", "exec")
+ code = update_code_recursively(code, filename=path)
+ # so code constains correct filename (even if it contains Unicode)
+ # and tracebacks show contents of code lines
+
+ return code
+
+class MainLoader:
+ # to reload __main__ properly
+
+ def __init__(self, path):
+ self.path = path
+
+ def load_module(self, name):
+ code = get_code(self.path)
+ exec(code, __main__.__dict__)
+ return __main__
+
+def run_script():
+ sys.argv.pop(0) # so sys.argv looks correct from script being run
+ path = sys.argv[0]
+ __main__.__file__ = path
+ __main__.__loader__ = MainLoader(path)
+
+
+ try:
+ code = get_code(path)
+ except Exception as e:
+ traceback.print_exception(e.__class__, e, e.__traceback__.tb_next.tb_next, chain=False)
+ else:
+ try:
+ exec(code, __main__.__dict__)
+ except BaseException as e:
+ if not sys.flags.inspect and isinstance(e, SystemExit):
+ raise
+ else:
+ traceback.print_exception(e.__class__, e, e.__traceback__.tb_next)
+