1 """Execute files of Python code.""" |
1 """Execute files of Python code.""" |
2 |
2 |
3 import imp, os, sys |
3 import imp, marshal, os, sys |
4 |
4 |
5 from .backward import exec_function |
5 from .backward import exec_code_object, open_source |
6 from .misc import NoSource |
6 from .misc import ExceptionDuringRun, NoCode, NoSource |
7 |
7 |
8 |
8 |
9 try: |
9 try: |
10 # In Py 2.x, the builtins were in __builtin__ |
10 # In Py 2.x, the builtins were in __builtin__ |
11 BUILTINS = sys.modules['__builtin__'] |
11 BUILTINS = sys.modules['__builtin__'] |
12 except KeyError: |
12 except KeyError: |
13 # In Py 3.x, they're in builtins |
13 # In Py 3.x, they're in builtins |
14 BUILTINS = sys.modules['builtins'] |
14 BUILTINS = sys.modules['builtins'] |
15 |
15 |
16 |
16 |
17 def run_python_file(filename, args): |
17 def rsplit1(s, sep): |
|
18 """The same as s.rsplit(sep, 1), but works in 2.3""" |
|
19 parts = s.split(sep) |
|
20 return sep.join(parts[:-1]), parts[-1] |
|
21 |
|
22 |
|
23 def run_python_module(modulename, args): |
|
24 """Run a python module, as though with ``python -m name args...``. |
|
25 |
|
26 `modulename` is the name of the module, possibly a dot-separated name. |
|
27 `args` is the argument array to present as sys.argv, including the first |
|
28 element naming the module being executed. |
|
29 |
|
30 """ |
|
31 openfile = None |
|
32 glo, loc = globals(), locals() |
|
33 try: |
|
34 try: |
|
35 # Search for the module - inside its parent package, if any - using |
|
36 # standard import mechanics. |
|
37 if '.' in modulename: |
|
38 packagename, name = rsplit1(modulename, '.') |
|
39 package = __import__(packagename, glo, loc, ['__path__']) |
|
40 searchpath = package.__path__ |
|
41 else: |
|
42 packagename, name = None, modulename |
|
43 searchpath = None # "top-level search" in imp.find_module() |
|
44 openfile, pathname, _ = imp.find_module(name, searchpath) |
|
45 |
|
46 # Complain if this is a magic non-file module. |
|
47 if openfile is None and pathname is None: |
|
48 raise NoSource( |
|
49 "module does not live in a file: %r" % modulename |
|
50 ) |
|
51 |
|
52 # If `modulename` is actually a package, not a mere module, then we |
|
53 # pretend to be Python 2.7 and try running its __main__.py script. |
|
54 if openfile is None: |
|
55 packagename = modulename |
|
56 name = '__main__' |
|
57 package = __import__(packagename, glo, loc, ['__path__']) |
|
58 searchpath = package.__path__ |
|
59 openfile, pathname, _ = imp.find_module(name, searchpath) |
|
60 except ImportError: |
|
61 _, err, _ = sys.exc_info() |
|
62 raise NoSource(str(err)) |
|
63 finally: |
|
64 if openfile: |
|
65 openfile.close() |
|
66 |
|
67 # Finally, hand the file off to run_python_file for execution. |
|
68 pathname = os.path.abspath(pathname) |
|
69 args[0] = pathname |
|
70 run_python_file(pathname, args, package=packagename) |
|
71 |
|
72 |
|
73 def run_python_file(filename, args, package=None): |
18 """Run a python file as if it were the main program on the command line. |
74 """Run a python file as if it were the main program on the command line. |
19 |
75 |
20 `filename` is the path to the file to execute, it need not be a .py file. |
76 `filename` is the path to the file to execute, it need not be a .py file. |
21 `args` is the argument array to present as sys.argv, including the first |
77 `args` is the argument array to present as sys.argv, including the first |
22 element representing the file being executed. |
78 element naming the file being executed. `package` is the name of the |
|
79 enclosing package, if any. |
23 |
80 |
24 """ |
81 """ |
25 # Create a module to serve as __main__ |
82 # Create a module to serve as __main__ |
26 old_main_mod = sys.modules['__main__'] |
83 old_main_mod = sys.modules['__main__'] |
27 main_mod = imp.new_module('__main__') |
84 main_mod = imp.new_module('__main__') |
28 sys.modules['__main__'] = main_mod |
85 sys.modules['__main__'] = main_mod |
29 main_mod.__file__ = filename |
86 main_mod.__file__ = filename |
|
87 if package: |
|
88 main_mod.__package__ = package |
30 main_mod.__builtins__ = BUILTINS |
89 main_mod.__builtins__ = BUILTINS |
31 |
90 |
32 # Set sys.argv and the first path element properly. |
91 # Set sys.argv properly. |
33 old_argv = sys.argv |
92 old_argv = sys.argv |
34 old_path0 = sys.path[0] |
|
35 sys.argv = args |
93 sys.argv = args |
36 sys.path[0] = os.path.dirname(filename) |
|
37 |
94 |
38 try: |
95 try: |
|
96 # Make a code object somehow. |
|
97 if filename.endswith(".pyc") or filename.endswith(".pyo"): |
|
98 code = make_code_from_pyc(filename) |
|
99 else: |
|
100 code = make_code_from_py(filename) |
|
101 |
|
102 # Execute the code object. |
39 try: |
103 try: |
40 source = open(filename, 'rU').read() |
104 exec_code_object(code, main_mod.__dict__) |
41 except IOError: |
105 except SystemExit: |
42 raise NoSource("No file to run: %r" % filename) |
106 # The user called sys.exit(). Just pass it along to the upper |
43 exec_function(source, filename, main_mod.__dict__) |
107 # layers, where it will be handled. |
|
108 raise |
|
109 except: |
|
110 # Something went wrong while executing the user code. |
|
111 # Get the exc_info, and pack them into an exception that we can |
|
112 # throw up to the outer loop. We peel two layers off the traceback |
|
113 # so that the coverage.py code doesn't appear in the final printed |
|
114 # traceback. |
|
115 typ, err, tb = sys.exc_info() |
|
116 raise ExceptionDuringRun(typ, err, tb.tb_next.tb_next) |
44 finally: |
117 finally: |
45 # Restore the old __main__ |
118 # Restore the old __main__ |
46 sys.modules['__main__'] = old_main_mod |
119 sys.modules['__main__'] = old_main_mod |
47 |
120 |
48 # Restore the old argv and path |
121 # Restore the old argv and path |
49 sys.argv = old_argv |
122 sys.argv = old_argv |
50 sys.path[0] = old_path0 |
|
51 |
123 |
52 # |
124 def make_code_from_py(filename): |
53 # eflag: FileType = Python2 |
125 """Get source from `filename` and make a code object of it.""" |
|
126 # Open the source file. |
|
127 try: |
|
128 source_file = open_source(filename) |
|
129 except IOError: |
|
130 raise NoSource("No file to run: %r" % filename) |
|
131 |
|
132 try: |
|
133 source = source_file.read() |
|
134 finally: |
|
135 source_file.close() |
|
136 |
|
137 # We have the source. `compile` still needs the last line to be clean, |
|
138 # so make sure it is, then compile a code object from it. |
|
139 if not source or source[-1] != '\n': |
|
140 source += '\n' |
|
141 code = compile(source, filename, "exec") |
|
142 |
|
143 return code |
|
144 |
|
145 |
|
146 def make_code_from_pyc(filename): |
|
147 """Get a code object from a .pyc file.""" |
|
148 try: |
|
149 fpyc = open(filename, "rb") |
|
150 except IOError: |
|
151 raise NoCode("No file to run: %r" % filename) |
|
152 |
|
153 try: |
|
154 # First four bytes are a version-specific magic number. It has to |
|
155 # match or we won't run the file. |
|
156 magic = fpyc.read(4) |
|
157 if magic != imp.get_magic(): |
|
158 raise NoCode("Bad magic number in .pyc file") |
|
159 |
|
160 # Skip the junk in the header that we don't need. |
|
161 fpyc.read(4) # Skip the moddate. |
|
162 if sys.version_info >= (3, 3): |
|
163 # 3.3 added another long to the header (size), skip it. |
|
164 fpyc.read(4) |
|
165 |
|
166 # The rest of the file is the code object we want. |
|
167 code = marshal.load(fpyc) |
|
168 finally: |
|
169 fpyc.close() |
|
170 |
|
171 return code |