diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py --- a/Lib/test/test_runpy.py +++ b/Lib/test/test_runpy.py @@ -200,42 +200,49 @@ class RunModuleTestCase(unittest.TestCas self.expect_import_error(".howard") self.expect_import_error("..eaten") # Package without __main__.py self.expect_import_error("multiprocessing") def test_library_module(self): self.assertEqual(run_module("runpy")["__name__"], "runpy") - def _add_pkg_dir(self, pkg_dir, namespace=False): + def _add_pkg_dir(self, pkg_dir, namespace=False, write_source=False, + source=""): os.mkdir(pkg_dir) if namespace: return None pkg_fname = os.path.join(pkg_dir, "__init__.py") create_empty_file(pkg_fname) + if write_source: + mod_file = open(pkg_fname, "w") + mod_file.write(source) + mod_file.close() return pkg_fname def _make_pkg(self, source, depth, mod_base="runpy_test", - *, namespace=False, parent_namespaces=False): + *, namespace=False, parent_namespaces=False, + write_source_to_init=False): # Enforce a couple of internal sanity checks on test cases if (namespace or parent_namespaces) and not depth: raise RuntimeError("Can't mark top level module as a " "namespace package") pkg_name = "__runpy_pkg__" test_fname = mod_base+os.extsep+"py" pkg_dir = sub_dir = os.path.realpath(tempfile.mkdtemp()) if verbose > 1: print(" Package tree in:", sub_dir) sys.path.insert(0, pkg_dir) if verbose > 1: print(" Updated sys.path:", sys.path[0]) if depth: namespace_flags = [parent_namespaces] * depth namespace_flags[-1] = namespace for namespace_flag in namespace_flags: sub_dir = os.path.join(sub_dir, pkg_name) - pkg_fname = self._add_pkg_dir(sub_dir, namespace_flag) + pkg_fname = self._add_pkg_dir(sub_dir, namespace_flag, + write_source_to_init, source) if verbose > 1: print(" Next level in:", sub_dir) if verbose > 1: print(" Created:", pkg_fname) mod_fname = os.path.join(sub_dir, test_fname) mod_file = open(mod_fname, "w") mod_file.write(source) mod_file.close() if verbose > 1: print(" Created:", mod_fname) mod_name = (pkg_name+".")*depth + mod_base @@ -419,31 +426,56 @@ from ..uncle.cousin import nephew self.assertEqual(d2["__package__"], pkg_name) self.assertIn("sibling", d2) self.assertIn("nephew", d2) del d2 # Ensure __loader__ entry doesn't keep file open finally: self._del_pkg(pkg_dir, depth, mod_name) if verbose > 1: print("Module executed successfully") + def _test_package_bad_file(self, source, write_source=False): + pkg_dir, mod_fname, mod_name, mod_spec = ( + self._make_pkg(source, 1, "__main__", + write_source_to_init=write_source)) + mod_name = mod_name.replace(".__main__", "") + try: + run_module(mod_name) + except ImportError as err: + if verbose > 1: print("Exception:", str(err.args[0])) + self.assertNotRegex(err.args[0], + "is a package and cannot be directly executed", + "Invalid exception error. Package is still executable") + else: + self.fail("Expected import error for " + mod_name) + finally: + self._del_pkg(pkg_dir, 1, mod_name) + def test_run_module(self): for depth in range(4): if verbose > 1: print("Testing package depth:", depth) self._check_module(depth) def test_run_module_in_namespace_package(self): for depth in range(1, 4): if verbose > 1: print("Testing package depth:", depth) self._check_module(depth, namespace=True, parent_namespaces=True) def test_run_package(self): for depth in range(1, 4): if verbose > 1: print("Testing package depth:", depth) self._check_package(depth) + def test_run_package_bad_init(self): + source = "raise ImportError('Testing bad __init__.py file.', name='bad_init')" + self._test_package_bad_file(source, True) + + def test_run_package_bad_main(self): + source = "raise ImportError('Testing bad __main__.py file.', name='bad_main')" + self._test_package_bad_file(source, False) + def test_run_package_in_namespace_package(self): for depth in range(1, 4): if verbose > 1: print("Testing package depth:", depth) self._check_package(depth, parent_namespaces=True) def test_run_namespace_package(self): for depth in range(1, 4): if verbose > 1: print("Testing package depth:", depth)