Issue #27487: Merge runpy warning from 3.5
This commit is contained in:
commit
f9ed528faf
11
Lib/runpy.py
11
Lib/runpy.py
@ -114,6 +114,15 @@ def _get_module_details(mod_name, error=ImportError):
|
|||||||
if e.name is None or (e.name != pkg_name and
|
if e.name is None or (e.name != pkg_name and
|
||||||
not pkg_name.startswith(e.name + ".")):
|
not pkg_name.startswith(e.name + ".")):
|
||||||
raise
|
raise
|
||||||
|
# Warn if the module has already been imported under its normal name
|
||||||
|
existing = sys.modules.get(mod_name)
|
||||||
|
if existing is not None and not hasattr(existing, "__path__"):
|
||||||
|
from warnings import warn
|
||||||
|
msg = "{mod_name!r} found in sys.modules after import of " \
|
||||||
|
"package {pkg_name!r}, but prior to execution of " \
|
||||||
|
"{mod_name!r}; this may result in unpredictable " \
|
||||||
|
"behaviour".format(mod_name=mod_name, pkg_name=pkg_name)
|
||||||
|
warn(RuntimeWarning(msg))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
spec = importlib.util.find_spec(mod_name)
|
spec = importlib.util.find_spec(mod_name)
|
||||||
@ -121,7 +130,7 @@ def _get_module_details(mod_name, error=ImportError):
|
|||||||
# This hack fixes an impedance mismatch between pkgutil and
|
# This hack fixes an impedance mismatch between pkgutil and
|
||||||
# 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 module specification for {!r} ({}: {})"
|
||||||
raise error(msg.format(mod_name, type(ex).__name__, 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)
|
||||||
|
@ -425,8 +425,9 @@ class CmdLineTest(unittest.TestCase):
|
|||||||
# Exercise error reporting for various invalid package executions
|
# Exercise error reporting for various invalid package executions
|
||||||
tests = (
|
tests = (
|
||||||
('builtins', br'No code object available'),
|
('builtins', br'No code object available'),
|
||||||
('builtins.x', br'Error while finding spec.*AttributeError'),
|
('builtins.x', br'Error while finding module specification.*'
|
||||||
('builtins.x.y', br'Error while finding spec.*'
|
br'AttributeError'),
|
||||||
|
('builtins.x.y', br'Error while finding module specification.*'
|
||||||
br'ImportError.*No module named.*not a package'),
|
br'ImportError.*No module named.*not a package'),
|
||||||
('os.path', br'loader.*cannot handle'),
|
('os.path', br'loader.*cannot handle'),
|
||||||
('importlib', br'No module named.*'
|
('importlib', br'No module named.*'
|
||||||
@ -449,7 +450,8 @@ class CmdLineTest(unittest.TestCase):
|
|||||||
with open('test_pkg/__init__.pyc', 'wb'):
|
with open('test_pkg/__init__.pyc', 'wb'):
|
||||||
pass
|
pass
|
||||||
err = self.check_dash_m_failure('test_pkg')
|
err = self.check_dash_m_failure('test_pkg')
|
||||||
self.assertRegex(err, br'Error while finding spec.*'
|
self.assertRegex(err,
|
||||||
|
br'Error while finding module specification.*'
|
||||||
br'ImportError.*bad magic number')
|
br'ImportError.*bad magic number')
|
||||||
self.assertNotIn(b'is a package', err)
|
self.assertNotIn(b'is a package', err)
|
||||||
self.assertNotIn(b'Traceback', err)
|
self.assertNotIn(b'Traceback', err)
|
||||||
|
@ -7,6 +7,7 @@ import re
|
|||||||
import tempfile
|
import tempfile
|
||||||
import importlib, importlib.machinery, importlib.util
|
import importlib, importlib.machinery, importlib.util
|
||||||
import py_compile
|
import py_compile
|
||||||
|
import warnings
|
||||||
from test.support import (
|
from test.support import (
|
||||||
forget, make_legacy_pyc, unload, verbose, no_tracing,
|
forget, make_legacy_pyc, unload, verbose, no_tracing,
|
||||||
create_empty_file, temp_dir)
|
create_empty_file, temp_dir)
|
||||||
@ -246,7 +247,7 @@ class RunModuleTestCase(unittest.TestCase, CodeExecutionMixin):
|
|||||||
mod_fname)
|
mod_fname)
|
||||||
return pkg_dir, mod_fname, mod_name, mod_spec
|
return pkg_dir, mod_fname, mod_name, mod_spec
|
||||||
|
|
||||||
def _del_pkg(self, top, depth, mod_name):
|
def _del_pkg(self, top):
|
||||||
for entry in list(sys.modules):
|
for entry in list(sys.modules):
|
||||||
if entry.startswith("__runpy_pkg__"):
|
if entry.startswith("__runpy_pkg__"):
|
||||||
del sys.modules[entry]
|
del sys.modules[entry]
|
||||||
@ -320,7 +321,7 @@ class RunModuleTestCase(unittest.TestCase, CodeExecutionMixin):
|
|||||||
self._fix_ns_for_legacy_pyc(expected_ns, alter_sys)
|
self._fix_ns_for_legacy_pyc(expected_ns, alter_sys)
|
||||||
self.check_code_execution(create_ns, expected_ns)
|
self.check_code_execution(create_ns, expected_ns)
|
||||||
finally:
|
finally:
|
||||||
self._del_pkg(pkg_dir, depth, mod_name)
|
self._del_pkg(pkg_dir)
|
||||||
if verbose > 1: print("Module executed successfully")
|
if verbose > 1: print("Module executed successfully")
|
||||||
|
|
||||||
def _check_package(self, depth, alter_sys=False,
|
def _check_package(self, depth, alter_sys=False,
|
||||||
@ -361,7 +362,7 @@ class RunModuleTestCase(unittest.TestCase, CodeExecutionMixin):
|
|||||||
self._fix_ns_for_legacy_pyc(expected_ns, alter_sys)
|
self._fix_ns_for_legacy_pyc(expected_ns, alter_sys)
|
||||||
self.check_code_execution(create_ns, expected_ns)
|
self.check_code_execution(create_ns, expected_ns)
|
||||||
finally:
|
finally:
|
||||||
self._del_pkg(pkg_dir, depth, pkg_name)
|
self._del_pkg(pkg_dir)
|
||||||
if verbose > 1: print("Package executed successfully")
|
if verbose > 1: print("Package executed successfully")
|
||||||
|
|
||||||
def _add_relative_modules(self, base_dir, source, depth):
|
def _add_relative_modules(self, base_dir, source, depth):
|
||||||
@ -424,7 +425,7 @@ from ..uncle.cousin import nephew
|
|||||||
self.assertIn("nephew", d2)
|
self.assertIn("nephew", d2)
|
||||||
del d2 # Ensure __loader__ entry doesn't keep file open
|
del d2 # Ensure __loader__ entry doesn't keep file open
|
||||||
finally:
|
finally:
|
||||||
self._del_pkg(pkg_dir, depth, mod_name)
|
self._del_pkg(pkg_dir)
|
||||||
if verbose > 1: print("Module executed successfully")
|
if verbose > 1: print("Module executed successfully")
|
||||||
|
|
||||||
def test_run_module(self):
|
def test_run_module(self):
|
||||||
@ -447,7 +448,7 @@ from ..uncle.cousin import nephew
|
|||||||
result = self._make_pkg("", 1, "__main__")
|
result = self._make_pkg("", 1, "__main__")
|
||||||
pkg_dir, _, mod_name, _ = result
|
pkg_dir, _, mod_name, _ = result
|
||||||
mod_name = mod_name.replace(".__main__", "")
|
mod_name = mod_name.replace(".__main__", "")
|
||||||
self.addCleanup(self._del_pkg, pkg_dir, 1, mod_name)
|
self.addCleanup(self._del_pkg, pkg_dir)
|
||||||
init = os.path.join(pkg_dir, "__runpy_pkg__", "__init__.py")
|
init = os.path.join(pkg_dir, "__runpy_pkg__", "__init__.py")
|
||||||
|
|
||||||
exceptions = (ImportError, AttributeError, TypeError, ValueError)
|
exceptions = (ImportError, AttributeError, TypeError, ValueError)
|
||||||
@ -470,6 +471,31 @@ from ..uncle.cousin import nephew
|
|||||||
else:
|
else:
|
||||||
self.fail("Nothing raised; expected {}".format(name))
|
self.fail("Nothing raised; expected {}".format(name))
|
||||||
|
|
||||||
|
def test_submodule_imported_warning(self):
|
||||||
|
pkg_dir, _, mod_name, _ = self._make_pkg("", 1)
|
||||||
|
try:
|
||||||
|
__import__(mod_name)
|
||||||
|
with self.assertWarnsRegex(RuntimeWarning,
|
||||||
|
r"found in sys\.modules"):
|
||||||
|
run_module(mod_name)
|
||||||
|
finally:
|
||||||
|
self._del_pkg(pkg_dir)
|
||||||
|
|
||||||
|
def test_package_imported_no_warning(self):
|
||||||
|
pkg_dir, _, mod_name, _ = self._make_pkg("", 1, "__main__")
|
||||||
|
self.addCleanup(self._del_pkg, pkg_dir)
|
||||||
|
package = mod_name.replace(".__main__", "")
|
||||||
|
# No warning should occur if we only imported the parent package
|
||||||
|
__import__(package)
|
||||||
|
self.assertIn(package, sys.modules)
|
||||||
|
with warnings.catch_warnings():
|
||||||
|
warnings.simplefilter("error", RuntimeWarning)
|
||||||
|
run_module(package)
|
||||||
|
# But the warning should occur if we imported the __main__ submodule
|
||||||
|
__import__(mod_name)
|
||||||
|
with self.assertWarnsRegex(RuntimeWarning, r"found in sys\.modules"):
|
||||||
|
run_module(package)
|
||||||
|
|
||||||
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):
|
||||||
if verbose > 1: print("Testing package depth:", depth)
|
if verbose > 1: print("Testing package depth:", depth)
|
||||||
@ -524,7 +550,7 @@ from ..uncle.cousin import nephew
|
|||||||
try:
|
try:
|
||||||
self.check_code_execution(create_ns, expected_ns)
|
self.check_code_execution(create_ns, expected_ns)
|
||||||
finally:
|
finally:
|
||||||
self._del_pkg(pkg_dir, depth, mod_name)
|
self._del_pkg(pkg_dir)
|
||||||
|
|
||||||
def test_pkgutil_walk_packages(self):
|
def test_pkgutil_walk_packages(self):
|
||||||
# This is a dodgy hack to use the test_runpy infrastructure to test
|
# 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")
|
expected_modules.add(pkg_name + ".runpy_test")
|
||||||
pkg_dir, mod_fname, mod_name, mod_spec = (
|
pkg_dir, mod_fname, mod_name, mod_spec = (
|
||||||
self._make_pkg("", max_depth))
|
self._make_pkg("", max_depth))
|
||||||
self.addCleanup(self._del_pkg, pkg_dir, max_depth, mod_name)
|
self.addCleanup(self._del_pkg, pkg_dir)
|
||||||
for depth in range(2, max_depth+1):
|
for depth in range(2, max_depth+1):
|
||||||
self._add_relative_modules(pkg_dir, "", depth)
|
self._add_relative_modules(pkg_dir, "", depth)
|
||||||
for finder, mod_name, ispkg in pkgutil.walk_packages([pkg_dir]):
|
for finder, mod_name, ispkg in pkgutil.walk_packages([pkg_dir]):
|
||||||
|
@ -10,6 +10,10 @@ What's New in Python 3.6.0 beta 1
|
|||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #27487: Warn if a submodule argument to "python -m" or
|
||||||
|
runpy.run_module() is found in sys.modules after parent packages are
|
||||||
|
imported, but before the submodule is executed.
|
||||||
|
|
||||||
- Issue #27157: Make only type() itself accept the one-argument form.
|
- Issue #27157: Make only type() itself accept the one-argument form.
|
||||||
Patch by Eryk Sun and Emanuel Barry.
|
Patch by Eryk Sun and Emanuel Barry.
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user