Issue #14285: Merge runpy fix from 3.5
This commit is contained in:
commit
8c0b5b998a
|
@ -36,7 +36,8 @@ The :mod:`runpy` module provides two functions:
|
||||||
import mechanism (refer to :pep:`302` for details) and then executed in a
|
import mechanism (refer to :pep:`302` for details) and then executed in a
|
||||||
fresh module namespace.
|
fresh module namespace.
|
||||||
|
|
||||||
If the supplied module name refers to a package rather than a normal
|
The *mod_name* argument should be an absolute module name.
|
||||||
|
If the module name refers to a package rather than a normal
|
||||||
module, then that package is imported and the ``__main__`` submodule within
|
module, then that package is imported and the ``__main__`` submodule within
|
||||||
that package is then executed and the resulting module globals dictionary
|
that package is then executed and the resulting module globals dictionary
|
||||||
returned.
|
returned.
|
||||||
|
|
|
@ -77,7 +77,7 @@ source.
|
||||||
the :mod:`__main__` module.
|
the :mod:`__main__` module.
|
||||||
|
|
||||||
Since the argument is a *module* name, you must not give a file extension
|
Since the argument is a *module* name, you must not give a file extension
|
||||||
(``.py``). The ``module-name`` should be a valid Python module name, but
|
(``.py``). The module name should be a valid absolute Python module name, but
|
||||||
the implementation may not always enforce this (e.g. it may allow you to
|
the implementation may not always enforce this (e.g. it may allow you to
|
||||||
use a name that includes a hyphen).
|
use a name that includes a hyphen).
|
||||||
|
|
||||||
|
|
22
Lib/runpy.py
22
Lib/runpy.py
|
@ -100,6 +100,21 @@ def _run_module_code(code, init_globals=None,
|
||||||
|
|
||||||
# Helper to get the loader, code and filename for a module
|
# Helper to get the loader, code and filename for a module
|
||||||
def _get_module_details(mod_name, error=ImportError):
|
def _get_module_details(mod_name, error=ImportError):
|
||||||
|
if mod_name.startswith("."):
|
||||||
|
raise error("Relative module names not supported")
|
||||||
|
pkg_name, _, _ = mod_name.rpartition(".")
|
||||||
|
if pkg_name:
|
||||||
|
# Try importing the parent to avoid catching initialization errors
|
||||||
|
try:
|
||||||
|
__import__(pkg_name)
|
||||||
|
except ImportError as e:
|
||||||
|
# If the parent or higher ancestor package is missing, let the
|
||||||
|
# error be raised by find_spec() below and then be caught. But do
|
||||||
|
# not allow other errors to be caught.
|
||||||
|
if e.name is None or (e.name != pkg_name and
|
||||||
|
not pkg_name.startswith(e.name + ".")):
|
||||||
|
raise
|
||||||
|
|
||||||
try:
|
try:
|
||||||
spec = importlib.util.find_spec(mod_name)
|
spec = importlib.util.find_spec(mod_name)
|
||||||
except (ImportError, AttributeError, TypeError, ValueError) as ex:
|
except (ImportError, AttributeError, TypeError, ValueError) as ex:
|
||||||
|
@ -107,17 +122,16 @@ def _get_module_details(mod_name, error=ImportError):
|
||||||
# importlib, where the latter raises other errors for cases where
|
# importlib, where the latter raises other errors for cases where
|
||||||
# pkgutil previously raised ImportError
|
# pkgutil previously raised ImportError
|
||||||
msg = "Error while finding spec for {!r} ({}: {})"
|
msg = "Error while finding spec for {!r} ({}: {})"
|
||||||
raise error(msg.format(mod_name, type(ex), ex)) from ex
|
raise error(msg.format(mod_name, type(ex).__name__, ex)) from ex
|
||||||
if spec is None:
|
if spec is None:
|
||||||
raise error("No module named %s" % mod_name)
|
raise error("No module named %s" % mod_name)
|
||||||
if spec.submodule_search_locations is not None:
|
if spec.submodule_search_locations is not None:
|
||||||
if mod_name == "__main__" or mod_name.endswith(".__main__"):
|
if mod_name == "__main__" or mod_name.endswith(".__main__"):
|
||||||
raise error("Cannot use package as __main__ module")
|
raise error("Cannot use package as __main__ module")
|
||||||
__import__(mod_name) # Do not catch exceptions initializing package
|
|
||||||
try:
|
try:
|
||||||
pkg_main_name = mod_name + ".__main__"
|
pkg_main_name = mod_name + ".__main__"
|
||||||
return _get_module_details(pkg_main_name)
|
return _get_module_details(pkg_main_name, error)
|
||||||
except ImportError as e:
|
except error as e:
|
||||||
raise error(("%s; %r is a package and cannot " +
|
raise error(("%s; %r is a package and cannot " +
|
||||||
"be directly executed") %(e, mod_name))
|
"be directly executed") %(e, mod_name))
|
||||||
loader = spec.loader
|
loader = spec.loader
|
||||||
|
|
|
@ -433,6 +433,7 @@ class CmdLineTest(unittest.TestCase):
|
||||||
('importlib', br'No module named.*'
|
('importlib', br'No module named.*'
|
||||||
br'is a package and cannot be directly executed'),
|
br'is a package and cannot be directly executed'),
|
||||||
('importlib.nonexistant', br'No module named'),
|
('importlib.nonexistant', br'No module named'),
|
||||||
|
('.unittest', br'Relative module names not supported'),
|
||||||
)
|
)
|
||||||
for name, regex in tests:
|
for name, regex in tests:
|
||||||
with self.subTest(name):
|
with self.subTest(name):
|
||||||
|
|
|
@ -197,8 +197,11 @@ class RunModuleTestCase(unittest.TestCase, CodeExecutionMixin):
|
||||||
self.expect_import_error("sys.imp.eric")
|
self.expect_import_error("sys.imp.eric")
|
||||||
self.expect_import_error("os.path.half")
|
self.expect_import_error("os.path.half")
|
||||||
self.expect_import_error("a.bee")
|
self.expect_import_error("a.bee")
|
||||||
|
# Relative names not allowed
|
||||||
self.expect_import_error(".howard")
|
self.expect_import_error(".howard")
|
||||||
self.expect_import_error("..eaten")
|
self.expect_import_error("..eaten")
|
||||||
|
self.expect_import_error(".test_runpy")
|
||||||
|
self.expect_import_error(".unittest")
|
||||||
# Package without __main__.py
|
# Package without __main__.py
|
||||||
self.expect_import_error("multiprocessing")
|
self.expect_import_error("multiprocessing")
|
||||||
|
|
||||||
|
@ -460,6 +463,12 @@ from ..uncle.cousin import nephew
|
||||||
self.assertNotIn("finding spec", format(err))
|
self.assertNotIn("finding spec", format(err))
|
||||||
else:
|
else:
|
||||||
self.fail("Nothing raised; expected {}".format(name))
|
self.fail("Nothing raised; expected {}".format(name))
|
||||||
|
try:
|
||||||
|
run_module(mod_name + ".submodule")
|
||||||
|
except exception as err:
|
||||||
|
self.assertNotIn("finding spec", format(err))
|
||||||
|
else:
|
||||||
|
self.fail("Nothing raised; expected {}".format(name))
|
||||||
|
|
||||||
def test_run_package_in_namespace_package(self):
|
def test_run_package_in_namespace_package(self):
|
||||||
for depth in range(1, 4):
|
for depth in range(1, 4):
|
||||||
|
|
Loading…
Reference in New Issue