X-Git-Url: https://projects.mako.cc/source/twitter-api-cdsw/blobdiff_plain/90a7a18fb765fb79af12bf4e694573fef9fd653a..c09c5f5d95d501c31271233a3c34b88daee6a997:/win_unicode_console/runner.py diff --git a/win_unicode_console/runner.py b/win_unicode_console/runner.py new file mode 100644 index 0000000..4b22904 --- /dev/null +++ b/win_unicode_console/runner.py @@ -0,0 +1,96 @@ + +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, "", "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) +