Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(12431)

Delta Between Two Patch Sets: Lib/runpy.py

Issue 14285: Traceback wrong on ImportError while executing a package
Left Patch Set: Created 4 years, 6 months ago
Right Patch Set: Created 3 years, 9 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « Doc/using/cmdline.rst ('k') | Lib/test/test_cmd_line_script.py » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 """runpy.py - locating and running Python code using the module namespace 1 """runpy.py - locating and running Python code using the module namespace
2 2
3 Provides support for locating and running Python scripts using the Python 3 Provides support for locating and running Python scripts using the Python
4 module namespace instead of the native filesystem. 4 module namespace instead of the native filesystem.
5 5
6 This allows Python code to play nicely with non-filesystem based PEP 302 6 This allows Python code to play nicely with non-filesystem based PEP 302
7 importers when locating support scripts as well as when importing modules. 7 importers when locating support scripts as well as when importing modules.
8 """ 8 """
9 # Written by Nick Coghlan <ncoghlan at gmail.com> 9 # Written by Nick Coghlan <ncoghlan at gmail.com>
10 # to implement PEP 338 (Executing Modules as Scripts) 10 # to implement PEP 338 (Executing Modules as Scripts)
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
51 def __enter__(self): 51 def __enter__(self):
52 if self._saved_value is not self._sentinel: 52 if self._saved_value is not self._sentinel:
53 raise RuntimeError("Already preserving saved value") 53 raise RuntimeError("Already preserving saved value")
54 self._saved_value = sys.argv[0] 54 self._saved_value = sys.argv[0]
55 sys.argv[0] = self.value 55 sys.argv[0] = self.value
56 56
57 def __exit__(self, *args): 57 def __exit__(self, *args):
58 self.value = self._sentinel 58 self.value = self._sentinel
59 sys.argv[0] = self._saved_value 59 sys.argv[0] = self._saved_value
60 60
61 # TODO: Replace these helpers with importlib._bootstrap functions 61 # TODO: Replace these helpers with importlib._bootstrap_external functions.
62 def _run_code(code, run_globals, init_globals=None, 62 def _run_code(code, run_globals, init_globals=None,
63 mod_name=None, mod_spec=None, 63 mod_name=None, mod_spec=None,
64 pkg_name=None, script_name=None): 64 pkg_name=None, script_name=None):
65 """Helper to run code in nominated namespace""" 65 """Helper to run code in nominated namespace"""
66 if init_globals is not None: 66 if init_globals is not None:
67 run_globals.update(init_globals) 67 run_globals.update(init_globals)
68 if mod_spec is None: 68 if mod_spec is None:
69 loader = None 69 loader = None
70 fname = script_name 70 fname = script_name
71 cached = None 71 cached = None
(...skipping 20 matching lines...) Expand all
92 fname = script_name if mod_spec is None else mod_spec.origin 92 fname = script_name if mod_spec is None else mod_spec.origin
93 with _TempModule(mod_name) as temp_module, _ModifiedArgv0(fname): 93 with _TempModule(mod_name) as temp_module, _ModifiedArgv0(fname):
94 mod_globals = temp_module.module.__dict__ 94 mod_globals = temp_module.module.__dict__
95 _run_code(code, mod_globals, init_globals, 95 _run_code(code, mod_globals, init_globals,
96 mod_name, mod_spec, pkg_name, script_name) 96 mod_name, mod_spec, pkg_name, script_name)
97 # Copy the globals of the temporary module, as they 97 # Copy the globals of the temporary module, as they
98 # may be cleared when the temporary module goes away 98 # may be cleared when the temporary module goes away
99 return mod_globals.copy() 99 return mod_globals.copy()
100 100
101 # Helper to get the loader, code and filename for a module 101 # Helper to get the loader, code and filename for a module
102 def _get_module_details(mod_name): 102 def _get_module_details(mod_name, error=ImportError):
103 if mod_name.startswith("."):
104 raise error("Relative module names not supported")
105 pkg_name, _, _ = mod_name.rpartition(".")
106 if pkg_name:
107 # Try importing the parent to avoid catching initialization errors
108 try:
109 __import__(pkg_name)
110 except ImportError as err:
111 # If the parent or higher ancestor package is missing, this is an
112 # error that we may want to catch. But do not allow other errors
113 # to be caught.
114 if err.name is None or (err.name != pkg_name and
115 not pkg_name.startswith(err.name + ".")):
116 raise
117 raise error(format(err))
118
103 try: 119 try:
104 spec = importlib.util.find_spec(mod_name) 120 spec = importlib.util.find_spec(mod_name)
105 except (ImportError, AttributeError, TypeError, ValueError) as ex: 121 except (ImportError, AttributeError, TypeError, ValueError) as ex:
106 # This hack fixes an impedance mismatch between pkgutil and 122 # This hack fixes an impedance mismatch between pkgutil and
107 # importlib, where the latter raises other errors for cases where 123 # importlib, where the latter raises other errors for cases where
108 # pkgutil previously raised ImportError 124 # pkgutil previously raised ImportError
109 msg = "Error while finding spec for {!r} ({}: {})" 125 msg = "Error while finding spec for {!r} ({}: {})"
110 raise ImportError(msg.format(mod_name, type(ex), ex)) from ex 126 raise error(msg.format(mod_name, type(ex).__name__, ex)) from ex
111 if spec is None: 127 if spec is None:
112 raise ImportError("No module named %s" % mod_name) 128 raise error("No module named %s" % mod_name)
113 if spec.submodule_search_locations is not None: 129 if spec.submodule_search_locations is not None:
114 if mod_name == "__main__" or mod_name.endswith(".__main__"): 130 if mod_name == "__main__" or mod_name.endswith(".__main__"):
115 raise ImportError("Cannot use package as __main__ module") 131 raise error("Cannot use package as __main__ module")
116 try: 132 try:
117 pkg_main_name = mod_name + ".__main__" 133 pkg_main_name = mod_name + ".__main__"
118 return _get_module_details(pkg_main_name) 134 return _get_module_details(pkg_main_name, error)
119 except ImportError as e: 135 except error as e:
120 raise ImportError(("%s; %r is a package and cannot " + 136 raise error(("%s; %r is a package and cannot " +
121 "be directly executed") %(e, mod_name)) 137 "be directly executed") %(e, mod_name))
122 loader = spec.loader 138 loader = spec.loader
123 if loader is None: 139 if loader is None:
124 raise ImportError("%r is a namespace package and cannot be executed" 140 raise error("%r is a namespace package and cannot be executed"
125 % mod_name) 141 % mod_name)
126 code = loader.get_code(mod_name) 142 try:
143 code = loader.get_code(mod_name)
144 except ImportError as e:
145 raise error(format(e)) from e
127 if code is None: 146 if code is None:
128 raise ImportError("No code object available for %s" % mod_name) 147 raise error("No code object available for %s" % mod_name)
129 return mod_name, spec, code 148 return mod_name, spec, code
149
150 class _Error(Exception):
151 """Error that _run_module_as_main() should report without a traceback"""
130 152
131 # XXX ncoghlan: Should this be documented and made public? 153 # XXX ncoghlan: Should this be documented and made public?
132 # (Current thoughts: don't repeat the mistake that lead to its 154 # (Current thoughts: don't repeat the mistake that lead to its
133 # creation when run_module() no longer met the needs of 155 # creation when run_module() no longer met the needs of
134 # mainmodule.c, but couldn't be changed because it was public) 156 # mainmodule.c, but couldn't be changed because it was public)
135 def _run_module_as_main(mod_name, alter_argv=True): 157 def _run_module_as_main(mod_name, alter_argv=True):
136 """Runs the designated module in the __main__ namespace 158 """Runs the designated module in the __main__ namespace
137 159
138 Note that the executed module will have full access to the 160 Note that the executed module will have full access to the
139 __main__ namespace. If this is not desirable, the run_module() 161 __main__ namespace. If this is not desirable, the run_module()
140 function should be used to run the module code in a fresh namespace. 162 function should be used to run the module code in a fresh namespace.
141 163
142 At the very least, these variables in __main__ will be overwritten: 164 At the very least, these variables in __main__ will be overwritten:
143 __name__ 165 __name__
144 __file__ 166 __file__
145 __cached__ 167 __cached__
146 __loader__ 168 __loader__
147 __package__ 169 __package__
148 """ 170 """
149 try: 171 try:
150 if alter_argv or mod_name != "__main__": # i.e. -m switch 172 if alter_argv or mod_name != "__main__": # i.e. -m switch
151 mod_name, mod_spec, code = _get_module_details(mod_name) 173 mod_name, mod_spec, code = _get_module_details(mod_name, _Error)
152 else: # i.e. directory or zipfile execution 174 else: # i.e. directory or zipfile execution
153 mod_name, mod_spec, code = _get_main_module_details() 175 mod_name, mod_spec, code = _get_main_module_details(_Error)
154 except ImportError as exc: 176 except _Error as exc:
155 # TODO: This incorrectly suppresses traceback reporting when the
156 # exception was raised by user code in __init__.py; see Issue 14285
157 msg = "%s: %s" % (sys.executable, exc) 177 msg = "%s: %s" % (sys.executable, exc)
158 sys.exit(msg) 178 sys.exit(msg)
159 main_globals = sys.modules["__main__"].__dict__ 179 main_globals = sys.modules["__main__"].__dict__
160 if alter_argv: 180 if alter_argv:
161 sys.argv[0] = mod_spec.origin 181 sys.argv[0] = mod_spec.origin
162 return _run_code(code, main_globals, None, 182 return _run_code(code, main_globals, None,
163 "__main__", mod_spec) 183 "__main__", mod_spec)
164 184
165 def run_module(mod_name, init_globals=None, 185 def run_module(mod_name, init_globals=None,
166 run_name=None, alter_sys=False): 186 run_name=None, alter_sys=False):
167 """Execute a module's code without importing it 187 """Execute a module's code without importing it
168 188
169 Returns the resulting top level namespace dictionary 189 Returns the resulting top level namespace dictionary
170 """ 190 """
171 mod_name, mod_spec, code = _get_module_details(mod_name) 191 mod_name, mod_spec, code = _get_module_details(mod_name)
172 if run_name is None: 192 if run_name is None:
173 run_name = mod_name 193 run_name = mod_name
174 if alter_sys: 194 if alter_sys:
175 return _run_module_code(code, init_globals, run_name, mod_spec) 195 return _run_module_code(code, init_globals, run_name, mod_spec)
176 else: 196 else:
177 # Leave the sys module alone 197 # Leave the sys module alone
178 return _run_code(code, {}, init_globals, run_name, mod_spec) 198 return _run_code(code, {}, init_globals, run_name, mod_spec)
179 199
180 def _get_main_module_details(): 200 def _get_main_module_details(error=ImportError):
181 # Helper that gives a nicer error message when attempting to 201 # Helper that gives a nicer error message when attempting to
182 # execute a zipfile or directory by invoking __main__.py 202 # execute a zipfile or directory by invoking __main__.py
183 # Also moves the standard __main__ out of the way so that the 203 # Also moves the standard __main__ out of the way so that the
184 # preexisting __loader__ entry doesn't cause issues 204 # preexisting __loader__ entry doesn't cause issues
185 main_name = "__main__" 205 main_name = "__main__"
186 saved_main = sys.modules[main_name] 206 saved_main = sys.modules[main_name]
187 del sys.modules[main_name] 207 del sys.modules[main_name]
188 try: 208 try:
189 return _get_module_details(main_name) 209 return _get_module_details(main_name)
190 except ImportError as exc: 210 except ImportError as exc:
191 if main_name in str(exc): 211 if main_name in str(exc):
192 raise ImportError("can't find %r module in %r" % 212 raise error("can't find %r module in %r" %
193 (main_name, sys.path[0])) from exc 213 (main_name, sys.path[0])) from exc
194 raise 214 raise
195 finally: 215 finally:
196 sys.modules[main_name] = saved_main 216 sys.modules[main_name] = saved_main
197 217
198 218
199 def _get_code_from_file(run_name, fname): 219 def _get_code_from_file(run_name, fname):
200 # Check for a compiled file first 220 # Check for a compiled file first
201 with open(fname, "rb") as f: 221 with open(fname, "rb") as f:
202 code = read_code(f) 222 code = read_code(f)
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 pass 275 pass
256 276
257 277
258 if __name__ == "__main__": 278 if __name__ == "__main__":
259 # Run the module specified as the next command line argument 279 # Run the module specified as the next command line argument
260 if len(sys.argv) < 2: 280 if len(sys.argv) < 2:
261 print("No module specified for execution", file=sys.stderr) 281 print("No module specified for execution", file=sys.stderr)
262 else: 282 else:
263 del sys.argv[0] # Make the requested module sys.argv[0] 283 del sys.argv[0] # Make the requested module sys.argv[0]
264 _run_module_as_main(sys.argv[0]) 284 _run_module_as_main(sys.argv[0])
LEFTRIGHT

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+