diff options
author | Nick Coghlan <ncoghlan@gmail.com> | 2012-07-15 08:09:52 (GMT) |
---|---|---|
committer | Nick Coghlan <ncoghlan@gmail.com> | 2012-07-15 08:09:52 (GMT) |
commit | 85e729ec3b6708af956fb47ff4936521020ff5e5 (patch) | |
tree | d0b10ba33497b7df8480eef9a915ca17c96d32c6 /Lib/runpy.py | |
parent | f96cf911a0dfb5344ab9b298c87af76ff3006e33 (diff) | |
download | cpython-85e729ec3b6708af956fb47ff4936521020ff5e5.zip cpython-85e729ec3b6708af956fb47ff4936521020ff5e5.tar.gz cpython-85e729ec3b6708af956fb47ff4936521020ff5e5.tar.bz2 |
Take the first step in resolving the messy pkgutil vs importlib edge cases by basing pkgutil explicitly on importlib, deprecating its internal import emulation and setting __main__.__loader__ correctly so that runpy still works (Affects #15343, #15314, #15357)
Diffstat (limited to 'Lib/runpy.py')
-rw-r--r-- | Lib/runpy.py | 56 |
1 files changed, 19 insertions, 37 deletions
diff --git a/Lib/runpy.py b/Lib/runpy.py index 8ca325b..5823943 100644 --- a/Lib/runpy.py +++ b/Lib/runpy.py @@ -13,11 +13,8 @@ importers when locating support scripts as well as when importing modules. import os import sys import imp -from pkgutil import read_code -try: - from imp import get_loader -except ImportError: - from pkgutil import get_loader +import importlib.machinery +from pkgutil import read_code, get_loader, get_importer __all__ = [ "run_module", "run_path", @@ -154,6 +151,7 @@ def _run_module_as_main(mod_name, alter_argv=True): # know what the code was looking for info = "can't find '__main__' module in %r" % sys.argv[0] msg = "%s: %s" % (sys.executable, info) + raise sys.exit(msg) pkg_name = mod_name.rpartition('.')[0] main_globals = sys.modules["__main__"].__dict__ @@ -183,36 +181,23 @@ def run_module(mod_name, init_globals=None, def _get_main_module_details(): # Helper that gives a nicer error message when attempting to # execute a zipfile or directory by invoking __main__.py + # Also moves the standard __main__ out of the way so that the + # preexisting __loader__ entry doesn't cause issues main_name = "__main__" + saved_main = sys.modules[main_name] + del sys.modules[main_name] try: return _get_module_details(main_name) except ImportError as exc: if main_name in str(exc): raise ImportError("can't find %r module in %r" % - (main_name, sys.path[0])) + (main_name, sys.path[0])) from exc raise + finally: + sys.modules[main_name] = saved_main -# XXX (ncoghlan): Perhaps expose the C API function -# as imp.get_importer instead of reimplementing it in Python? -def _get_importer(path_name): - """Python version of PyImport_GetImporter C API function""" - cache = sys.path_importer_cache - try: - importer = cache[path_name] - except KeyError: - for hook in sys.path_hooks: - try: - importer = hook(path_name) - break - except ImportError: - pass - else: - importer = None - cache[path_name] = importer - return importer - -def _get_code_from_file(fname): +def _get_code_from_file(run_name, fname): # Check for a compiled file first with open(fname, "rb") as f: code = read_code(f) @@ -220,7 +205,10 @@ def _get_code_from_file(fname): # That didn't work, so try it as normal source code with open(fname, "rb") as f: code = compile(f.read(), fname, 'exec') - return code + loader = importlib.machinery.SourceFileLoader(run_name, fname) + else: + loader = importlib.machinery.SourcelessFileLoader(run_name, fname) + return code, loader def run_path(path_name, init_globals=None, run_name=None): """Execute code located at the specified filesystem location @@ -235,13 +223,13 @@ def run_path(path_name, init_globals=None, run_name=None): if run_name is None: run_name = "<run_path>" pkg_name = run_name.rpartition(".")[0] - importer = _get_importer(path_name) + importer = get_importer(path_name) if isinstance(importer, (type(None), imp.NullImporter)): # Not a valid sys.path entry, so run the code directly # execfile() doesn't help as we want to allow compiled files - code = _get_code_from_file(path_name) + code, mod_loader = _get_code_from_file(run_name, path_name) return _run_module_code(code, init_globals, run_name, path_name, - pkg_name=pkg_name) + mod_loader, pkg_name) else: # Importer is defined for path, so add it to # the start of sys.path @@ -253,13 +241,7 @@ def run_path(path_name, init_globals=None, run_name=None): # have no choice and we have to remove it even while we read the # code. If we don't do this, a __loader__ attribute in the # existing __main__ module may prevent location of the new module. - main_name = "__main__" - saved_main = sys.modules[main_name] - del sys.modules[main_name] - try: - mod_name, loader, code, fname = _get_main_module_details() - finally: - sys.modules[main_name] = saved_main + mod_name, loader, code, fname = _get_main_module_details() with _TempModule(run_name) as temp_module, \ _ModifiedArgv0(path_name): mod_globals = temp_module.module.__dict__ |