cpython: fccd733aa78b (original) (raw)
--- a/Lib/runpy.py +++ b/Lib/runpy.py @@ -114,6 +114,15 @@ def _get_module_details(mod_name, error= if e.name is None or (e.name != pkg_name and not pkg_name.startswith(e.name + ".")): raise
# Warn if the module has already been imported under its normal name[](#l1.7)
existing = sys.modules.get(mod_name)[](#l1.8)
if existing is not None and not hasattr(existing, "__path__"):[](#l1.9)
from warnings import warn[](#l1.10)
msg = "{mod_name!r} found in sys.modules after import of " \[](#l1.11)
"package {pkg_name!r}, but prior to execution of " \[](#l1.12)
"{mod_name!r}; this may result in unpredictable " \[](#l1.13)
"behaviour".format(mod_name=mod_name, pkg_name=pkg_name)[](#l1.14)
warn(RuntimeWarning(msg))[](#l1.15)
try: spec = importlib.util.find_spec(mod_name) @@ -121,7 +130,7 @@ def _get_module_details(mod_name, error= # This hack fixes an impedance mismatch between pkgutil and # importlib, where the latter raises other errors for cases where # pkgutil previously raised ImportError
msg = "Error while finding spec for {!r} ({}: {})"[](#l1.23)
if spec is None: raise error("No module named %s" % mod_name)msg = "Error while finding module specification for {!r} ({}: {})"[](#l1.24) raise error(msg.format(mod_name, type(ex).__name__, ex)) from ex[](#l1.25)
--- a/Lib/test/test_cmd_line_script.py +++ b/Lib/test/test_cmd_line_script.py @@ -425,8 +425,9 @@ class CmdLineTest(unittest.TestCase): # Exercise error reporting for various invalid package executions tests = ( ('builtins', br'No code object available'),
('builtins.x', br'Error while finding spec.*AttributeError'),[](#l2.7)
('builtins.x.y', br'Error while finding spec.*'[](#l2.8)
('builtins.x', br'Error while finding module specification.*'[](#l2.9)
br'AttributeError'),[](#l2.10)
('builtins.x.y', br'Error while finding module specification.*'[](#l2.11) br'ImportError.*No module named.*not a package'),[](#l2.12) ('os.path', br'loader.*cannot handle'),[](#l2.13) ('importlib', br'No module named.*'[](#l2.14)
@@ -449,7 +450,8 @@ class CmdLineTest(unittest.TestCase): with open('test_pkg/init.pyc', 'wb'): pass err = self.check_dash_m_failure('test_pkg')
self.assertRegex(err, br'Error while finding spec.*'[](#l2.19)
self.assertRegex(err,[](#l2.20)
br'Error while finding module specification.*'[](#l2.21) br'ImportError.*bad magic number')[](#l2.22) self.assertNotIn(b'is a package', err)[](#l2.23) self.assertNotIn(b'Traceback', err)[](#l2.24)
--- a/Lib/test/test_runpy.py +++ b/Lib/test/test_runpy.py @@ -7,6 +7,7 @@ import re import tempfile import importlib, importlib.machinery, importlib.util import py_compile +import warnings from test.support import ( forget, make_legacy_pyc, unload, verbose, no_tracing, create_empty_file, temp_dir) @@ -246,7 +247,7 @@ class RunModuleTestCase(unittest.TestCas mod_fname) return pkg_dir, mod_fname, mod_name, mod_spec
- def _del_pkg(self, top): for entry in list(sys.modules): if entry.startswith("runpy_pkg"): del sys.modules[entry]
@@ -320,7 +321,7 @@ class RunModuleTestCase(unittest.TestCas self._fix_ns_for_legacy_pyc(expected_ns, alter_sys) self.check_code_execution(create_ns, expected_ns) finally:
self._del_pkg(pkg_dir, depth, mod_name)[](#l3.24)
self._del_pkg(pkg_dir)[](#l3.25) if verbose > 1: print("Module executed successfully")[](#l3.26)
def _check_package(self, depth, alter_sys=False, @@ -361,7 +362,7 @@ class RunModuleTestCase(unittest.TestCas self._fix_ns_for_legacy_pyc(expected_ns, alter_sys) self.check_code_execution(create_ns, expected_ns) finally:
self._del_pkg(pkg_dir, depth, pkg_name)[](#l3.33)
self._del_pkg(pkg_dir)[](#l3.34) if verbose > 1: print("Package executed successfully")[](#l3.35)
def _add_relative_modules(self, base_dir, source, depth): @@ -424,7 +425,7 @@ from ..uncle.cousin import nephew self.assertIn("nephew", d2) del d2 # Ensure loader entry doesn't keep file open finally:
self._del_pkg(pkg_dir, depth, mod_name)[](#l3.42)
self._del_pkg(pkg_dir)[](#l3.43) if verbose > 1: print("Module executed successfully")[](#l3.44)
def test_run_module(self): @@ -447,7 +448,7 @@ from ..uncle.cousin import nephew result = self._make_pkg("", 1, "main") pkg_dir, _, mod_name, _ = result mod_name = mod_name.replace(".main", "")
self.addCleanup(self._del_pkg, pkg_dir, 1, mod_name)[](#l3.51)
self.addCleanup(self._del_pkg, pkg_dir)[](#l3.52) init = os.path.join(pkg_dir, "__runpy_pkg__", "__init__.py")[](#l3.53)
exceptions = (ImportError, AttributeError, TypeError, ValueError) @@ -470,6 +471,31 @@ from ..uncle.cousin import nephew else: self.fail("Nothing raised; expected {}".format(name))
- def test_submodule_imported_warning(self):
pkg_dir, _, mod_name, _ = self._make_pkg("", 1)[](#l3.61)
try:[](#l3.62)
__import__(mod_name)[](#l3.63)
with self.assertWarnsRegex(RuntimeWarning,[](#l3.64)
r"found in sys\.modules"):[](#l3.65)
run_module(mod_name)[](#l3.66)
finally:[](#l3.67)
self._del_pkg(pkg_dir)[](#l3.68)
- def test_package_imported_no_warning(self):
pkg_dir, _, mod_name, _ = self._make_pkg("", 1, "__main__")[](#l3.71)
self.addCleanup(self._del_pkg, pkg_dir)[](#l3.72)
package = mod_name.replace(".__main__", "")[](#l3.73)
# No warning should occur if we only imported the parent package[](#l3.74)
__import__(package)[](#l3.75)
self.assertIn(package, sys.modules)[](#l3.76)
with warnings.catch_warnings():[](#l3.77)
warnings.simplefilter("error", RuntimeWarning)[](#l3.78)
run_module(package)[](#l3.79)
# But the warning should occur if we imported the __main__ submodule[](#l3.80)
__import__(mod_name)[](#l3.81)
with self.assertWarnsRegex(RuntimeWarning, r"found in sys\.modules"):[](#l3.82)
run_module(package)[](#l3.83)
+ def test_run_package_in_namespace_package(self): for depth in range(1, 4): if verbose > 1: print("Testing package depth:", depth) @@ -524,7 +550,7 @@ from ..uncle.cousin import nephew try: self.check_code_execution(create_ns, expected_ns) finally:
self._del_pkg(pkg_dir, depth, mod_name)[](#l3.92)
self._del_pkg(pkg_dir)[](#l3.93)
def test_pkgutil_walk_packages(self): # This is a dodgy hack to use the test_runpy infrastructure to test @@ -548,7 +574,7 @@ from ..uncle.cousin import nephew expected_modules.add(pkg_name + ".runpy_test") pkg_dir, mod_fname, mod_name, mod_spec = ( self._make_pkg("", max_depth))
self.addCleanup(self._del_pkg, pkg_dir, max_depth, mod_name)[](#l3.101)
self.addCleanup(self._del_pkg, pkg_dir)[](#l3.102) for depth in range(2, max_depth+1):[](#l3.103) self._add_relative_modules(pkg_dir, "", depth)[](#l3.104) for finder, mod_name, ispkg in pkgutil.walk_packages([pkg_dir]):[](#l3.105)
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ What's New in Python 3.6.0 beta 1 Core and Builtins ----------------- +- Issue #27487: Warn if a submodule argument to "python -m" or