catscan is now petscan
[harrypotter-wikipedia-cdsw] / win_unicode_console / runner.py
1
2 from types import CodeType as Code
3 import sys
4 import traceback
5 import __main__
6 from ctypes import pythonapi, POINTER, c_long, cast
7 import tokenize
8
9
10 inspect_flag = cast(pythonapi.Py_InspectFlag, POINTER(c_long)).contents
11
12 def set_inspect_flag(value):
13         inspect_flag.value = int(value)
14
15
16 def update_code(codeobj, **kwargs):
17         fields = ["argcount", "kwonlyargcount", "nlocals", "stacksize", "flags",
18                 "code", "consts", "names", "varnames", "filename", "name",
19                 "firstlineno", "lnotab", "freevars", "cellvars"]
20         
21         def field_values():
22                 for field in fields:
23                         value = kwargs.get(field, None)
24                         if value is None:
25                                 yield getattr(codeobj, "co_{}".format(field))
26                         else:
27                                 yield value
28         
29         return Code(*field_values())
30
31 def update_code_recursively(codeobj, **kwargs):
32         updated = {}
33         
34         def update(codeobj, **kwargs):
35                 result = updated.get(codeobj, None)
36                 if result is not None:
37                         return result
38                 
39                 if any(isinstance(c, Code) for c in codeobj.co_consts):
40                         consts = tuple(update(c, **kwargs) if isinstance(c, Code) else c
41                                 for c in codeobj.co_consts)
42                 else:
43                         consts = codeobj.co_consts
44                 
45                 result = update_code(codeobj, consts=consts, **kwargs)
46                 updated[codeobj] = result
47                 return result
48         
49         return update(codeobj, **kwargs)
50
51
52 def get_code(path):
53         with tokenize.open(path) as f:  # opens with detected source encoding
54                 source = f.read()
55         
56         try:
57                 code = compile(source, path, "exec")
58         except UnicodeEncodeError:
59                 code = compile(source, "<encoding error>", "exec")
60                 code = update_code_recursively(code, filename=path)
61                         # so code constains correct filename (even if it contains Unicode)
62                         # and tracebacks show contents of code lines
63         
64         return code
65
66 class MainLoader:
67         # to reload __main__ properly
68         
69         def __init__(self, path):
70                 self.path = path
71         
72         def load_module(self, name):
73                 code = get_code(self.path)
74                 exec(code, __main__.__dict__)
75                 return __main__
76                 
77 def run_script():
78         sys.argv.pop(0) # so sys.argv looks correct from script being run
79         path = sys.argv[0]
80         __main__.__file__ = path
81         __main__.__loader__ = MainLoader(path)
82         
83         
84         try:
85                 code = get_code(path)
86         except Exception as e:
87                 traceback.print_exception(e.__class__, e, e.__traceback__.tb_next.tb_next, chain=False)
88         else:
89                 try:
90                         exec(code, __main__.__dict__)
91                 except BaseException as e:
92                         if not sys.flags.inspect and isinstance(e, SystemExit):
93                                 raise
94                         else:
95                                 traceback.print_exception(e.__class__, e, e.__traceback__.tb_next)
96

Benjamin Mako Hill || Want to submit a patch?