diff -r 9994e0172a0c Lib/runpy.py --- a/Lib/runpy.py Tue Mar 10 22:35:24 2015 +0100 +++ b/Lib/runpy.py Wed Mar 11 08:19:29 2015 +0000 @@ -107,7 +107,11 @@ # importlib, where the latter raises other errors for cases where # pkgutil previously raised ImportError msg = "Error while finding spec for {!r} ({}: {})" - raise ImportError(msg.format(mod_name, type(ex), ex)) from ex + msg = msg.format(mod_name, type(ex).__name__, ex) + if isinstance(ex, ImportError): + raise ImportError(msg, name=ex.name) from ex + else: + raise ImportError(msg) from ex if spec is None: raise ImportError("No module named %s" % mod_name) if spec.submodule_search_locations is not None: @@ -117,8 +121,12 @@ pkg_main_name = mod_name + ".__main__" return _get_module_details(pkg_main_name) except ImportError as e: - raise ImportError(("%s; %r is a package and cannot " + - "be directly executed") %(e, mod_name)) + if mod_name not in sys.modules: + raise # No module loaded; incorrect to say it is a package + # Assuming this error was raised by the "No module named . . ." + # case a few lines above + msg = "%s; %r is a package and cannot be directly executed" + raise ImportError(msg %(e, mod_name)) loader = spec.loader if loader is None: raise ImportError("%r is a namespace package and cannot be executed" diff -r 9994e0172a0c Lib/test/test_runpy.py --- a/Lib/test/test_runpy.py Tue Mar 10 22:35:24 2015 +0100 +++ b/Lib/test/test_runpy.py Wed Mar 11 08:19:29 2015 +0000 @@ -205,16 +205,18 @@ 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, source=""): os.mkdir(pkg_dir) if namespace: return None pkg_fname = os.path.join(pkg_dir, "__init__.py") - create_empty_file(pkg_fname) + with open(pkg_fname, "wt", encoding="ascii") as mod_file: + mod_file.write(source) return pkg_fname def _make_pkg(self, source, depth, mod_base="runpy_test", - *, namespace=False, parent_namespaces=False): + *, namespace=False, parent_namespaces=False, + init_source=""): # 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 " @@ -230,7 +232,8 @@ 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, + 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) @@ -424,6 +427,22 @@ self._del_pkg(pkg_dir, depth, mod_name) if verbose > 1: print("Module executed successfully") + def _test_package_bad_file(self, main="", init=""): + result = self._make_pkg(main, 1, "__main__", init_source=init) + pkg_dir, mod_fname, mod_name, mod_spec = result + mod_name = mod_name.replace(".__main__", "") + self.addCleanup(self._del_pkg, pkg_dir, 1, mod_name) + try: + run_module(mod_name) + except ImportError as err: + if verbose > 1: + print("ImportError:", err) + self.assertNotIn("is a package and cannot be directly executed", + format(err), + "Invalid exception error. Package is still executable") + else: + self.fail("Expected import error for " + mod_name) + def test_run_module(self): for depth in range(4): if verbose > 1: print("Testing package depth:", depth) @@ -439,6 +458,14 @@ 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(init=source) + + def test_run_package_bad_main(self): + source = "raise ImportError('Testing bad __main__.py file.', name='bad_main')" + self._test_package_bad_file(main=source) + def test_run_package_in_namespace_package(self): for depth in range(1, 4): if verbose > 1: print("Testing package depth:", depth)