| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -114,14 +114,23 @@ def _get_module_details(mod_name, error=ImportError): | |||
| 114 | 114 | if e.name is None or (e.name != pkg_name and | |
| 115 | 115 | not pkg_name.startswith(e.name + ".")): | |
| 116 | 116 | raise | |
| 117 | + # Warn if the module has already been imported under its normal name | ||
| 118 | + existing = sys.modules.get(mod_name) | ||
| 119 | + if existing is not None and not hasattr(existing, "__path__"): | ||
| 120 | + from warnings import warn | ||
| 121 | + msg = "{mod_name!r} found in sys.modules after import of " \ | ||
| 122 | + "package {pkg_name!r}, but prior to execution of " \ | ||
| 123 | + "{mod_name!r}; this may result in unpredictable " \ | ||
| 124 | + "behaviour".format(mod_name=mod_name, pkg_name=pkg_name) | ||
| 125 | + warn(RuntimeWarning(msg)) | ||
| 117 | 126 | ||
| 118 | 127 | try: | |
| 119 | 128 | spec = importlib.util.find_spec(mod_name) | |
| 120 | 129 | except (ImportError, AttributeError, TypeError, ValueError) as ex: | |
| 121 | 130 | # This hack fixes an impedance mismatch between pkgutil and | |
| 122 | 131 | # importlib, where the latter raises other errors for cases where | |
| 123 | 132 | # pkgutil previously raised ImportError | |
| 124 | - msg = "Error while finding spec for {!r} ({}: {})" | ||
| 133 | + msg = "Error while finding module specification for {!r} ({}: {})" | ||
| 125 | 134 | raise error(msg.format(mod_name, type(ex).__name__, ex)) from ex | |
| 126 | 135 | if spec is None: | |
| 127 | 136 | raise error("No module named %s" % mod_name) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -426,8 +426,9 @@ def test_dash_m_errors(self): | |||
| 426 | 426 | # Exercise error reporting for various invalid package executions | |
| 427 | 427 | tests = ( | |
| 428 | 428 | ('builtins', br'No code object available'), | |
| 429 | - ('builtins.x', br'Error while finding spec.*AttributeError'), | ||
| 430 | - ('builtins.x.y', br'Error while finding spec.*' | ||
| 429 | + ('builtins.x', br'Error while finding module specification.*' | ||
| 430 | + br'AttributeError'), | ||
| 431 | + ('builtins.x.y', br'Error while finding module specification.*' | ||
| 431 | 432 | br'ImportError.*No module named.*not a package'), | |
| 432 | 433 | ('os.path', br'loader.*cannot handle'), | |
| 433 | 434 | ('importlib', br'No module named.*' | |
@@ -450,7 +451,8 @@ def test_dash_m_bad_pyc(self): | |||
| 450 | 451 | with open('test_pkg/__init__.pyc', 'wb'): | |
| 451 | 452 | pass | |
| 452 | 453 | err = self.check_dash_m_failure('test_pkg') | |
| 453 | - self.assertRegex(err, br'Error while finding spec.*' | ||
| 454 | + self.assertRegex(err, | ||
| 455 | + br'Error while finding module specification.*' | ||
| 454 | 456 | br'ImportError.*bad magic number') | |
| 455 | 457 | self.assertNotIn(b'is a package', err) | |
| 456 | 458 | self.assertNotIn(b'Traceback', err) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -7,6 +7,7 @@ | |||
| 7 | 7 | import tempfile | |
| 8 | 8 | import importlib, importlib.machinery, importlib.util | |
| 9 | 9 | import py_compile | |
| 10 | + import warnings | ||
| 10 | 11 | from test.support import ( | |
| 11 | 12 | forget, make_legacy_pyc, unload, verbose, no_tracing, | |
| 12 | 13 | create_empty_file, temp_dir) | |
@@ -246,7 +247,7 @@ def _make_pkg(self, source, depth, mod_base="runpy_test", | |||
| 246 | 247 | mod_fname) | |
| 247 | 248 | return pkg_dir, mod_fname, mod_name, mod_spec | |
| 248 | 249 | ||
| 249 | - def _del_pkg(self, top, depth, mod_name): | ||
| 250 | + def _del_pkg(self, top): | ||
| 250 | 251 | for entry in list(sys.modules): | |
| 251 | 252 | if entry.startswith("__runpy_pkg__"): | |
| 252 | 253 | del sys.modules[entry] | |
@@ -320,7 +321,7 @@ def create_ns(init_globals): | |||
| 320 | 321 | self._fix_ns_for_legacy_pyc(expected_ns, alter_sys) | |
| 321 | 322 | self.check_code_execution(create_ns, expected_ns) | |
| 322 | 323 | finally: | |
| 323 | - self._del_pkg(pkg_dir, depth, mod_name) | ||
| 324 | + self._del_pkg(pkg_dir) | ||
| 324 | 325 | if verbose > 1: print("Module executed successfully") | |
| 325 | 326 | ||
| 326 | 327 | def _check_package(self, depth, alter_sys=False, | |
@@ -361,7 +362,7 @@ def create_ns(init_globals): | |||
| 361 | 362 | self._fix_ns_for_legacy_pyc(expected_ns, alter_sys) | |
| 362 | 363 | self.check_code_execution(create_ns, expected_ns) | |
| 363 | 364 | finally: | |
| 364 | - self._del_pkg(pkg_dir, depth, pkg_name) | ||
| 365 | + self._del_pkg(pkg_dir) | ||
| 365 | 366 | if verbose > 1: print("Package executed successfully") | |
| 366 | 367 | ||
| 367 | 368 | def _add_relative_modules(self, base_dir, source, depth): | |
@@ -424,7 +425,7 @@ def _check_relative_imports(self, depth, run_name=None): | |||
| 424 | 425 | self.assertIn("nephew", d2) | |
| 425 | 426 | del d2 # Ensure __loader__ entry doesn't keep file open | |
| 426 | 427 | finally: | |
| 427 | - self._del_pkg(pkg_dir, depth, mod_name) | ||
| 428 | + self._del_pkg(pkg_dir) | ||
| 428 | 429 | if verbose > 1: print("Module executed successfully") | |
| 429 | 430 | ||
| 430 | 431 | def test_run_module(self): | |
@@ -447,7 +448,7 @@ def test_run_package_init_exceptions(self): | |||
| 447 | 448 | result = self._make_pkg("", 1, "__main__") | |
| 448 | 449 | pkg_dir, _, mod_name, _ = result | |
| 449 | 450 | mod_name = mod_name.replace(".__main__", "") | |
| 450 | - self.addCleanup(self._del_pkg, pkg_dir, 1, mod_name) | ||
| 451 | + self.addCleanup(self._del_pkg, pkg_dir) | ||
| 451 | 452 | init = os.path.join(pkg_dir, "__runpy_pkg__", "__init__.py") | |
| 452 | 453 | ||
| 453 | 454 | exceptions = (ImportError, AttributeError, TypeError, ValueError) | |
@@ -470,6 +471,31 @@ def test_run_package_init_exceptions(self): | |||
| 470 | 471 | else: | |
| 471 | 472 | self.fail("Nothing raised; expected {}".format(name)) | |
| 472 | 473 | ||
| 474 | + def test_submodule_imported_warning(self): | ||
| 475 | + pkg_dir, _, mod_name, _ = self._make_pkg("", 1) | ||
| 476 | + try: | ||
| 477 | + __import__(mod_name) | ||
| 478 | + with self.assertWarnsRegex(RuntimeWarning, | ||
| 479 | + r"found in sys\.modules"): | ||
| 480 | + run_module(mod_name) | ||
| 481 | + finally: | ||
| 482 | + self._del_pkg(pkg_dir) | ||
| 483 | + | ||
| 484 | + def test_package_imported_no_warning(self): | ||
| 485 | + pkg_dir, _, mod_name, _ = self._make_pkg("", 1, "__main__") | ||
| 486 | + self.addCleanup(self._del_pkg, pkg_dir) | ||
| 487 | + package = mod_name.replace(".__main__", "") | ||
| 488 | + # No warning should occur if we only imported the parent package | ||
| 489 | + __import__(package) | ||
| 490 | + self.assertIn(package, sys.modules) | ||
| 491 | + with warnings.catch_warnings(): | ||
| 492 | + warnings.simplefilter("error", RuntimeWarning) | ||
| 493 | + run_module(package) | ||
| 494 | + # But the warning should occur if we imported the __main__ submodule | ||
| 495 | + __import__(mod_name) | ||
| 496 | + with self.assertWarnsRegex(RuntimeWarning, r"found in sys\.modules"): | ||
| 497 | + run_module(package) | ||
| 498 | + | ||
| 473 | 499 | def test_run_package_in_namespace_package(self): | |
| 474 | 500 | for depth in range(1, 4): | |
| 475 | 501 | if verbose > 1: print("Testing package depth:", depth) | |
@@ -524,7 +550,7 @@ def create_ns(init_globals): | |||
| 524 | 550 | try: | |
| 525 | 551 | self.check_code_execution(create_ns, expected_ns) | |
| 526 | 552 | finally: | |
| 527 | - self._del_pkg(pkg_dir, depth, mod_name) | ||
| 553 | + self._del_pkg(pkg_dir) | ||
| 528 | 554 | ||
| 529 | 555 | def test_pkgutil_walk_packages(self): | |
| 530 | 556 | # This is a dodgy hack to use the test_runpy infrastructure to test | |
@@ -548,7 +574,7 @@ def test_pkgutil_walk_packages(self): | |||
| 548 | 574 | expected_modules.add(pkg_name + ".runpy_test") | |
| 549 | 575 | pkg_dir, mod_fname, mod_name, mod_spec = ( | |
| 550 | 576 | self._make_pkg("", max_depth)) | |
| 551 | - self.addCleanup(self._del_pkg, pkg_dir, max_depth, mod_name) | ||
| 577 | + self.addCleanup(self._del_pkg, pkg_dir) | ||
| 552 | 578 | for depth in range(2, max_depth+1): | |
| 553 | 579 | self._add_relative_modules(pkg_dir, "", depth) | |
| 554 | 580 | for finder, mod_name, ispkg in pkgutil.walk_packages([pkg_dir]): | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -10,6 +10,10 @@ Release date: TBA | |||
| 10 | 10 | Core and Builtins | |
| 11 | 11 | ----------------- | |
| 12 | 12 | ||
| 13 | + - Issue #27487: Warn if a submodule argument to "python -m" or | ||
| 14 | + runpy.run_module() is found in sys.modules after parent packages are | ||
| 15 | + imported, but before the submodule is executed. | ||
| 16 | + | ||
| 13 | 17 | - Issue #27558: Fix a SystemError in the implementation of "raise" statement. | |
| 14 | 18 | In a brand new thread, raise a RuntimeError since there is no active | |
| 15 | 19 | exception to reraise. Patch written by Xiang Zhang. | |
| Back | FazBrowse Home | New Git URL |
0 commit comments