Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r86650:9332dfa6e22e Date: 2016-08-28 21:08 +0200 http://bitbucket.org/pypy/pypy/changeset/9332dfa6e22e/
Log: Issue #2382: fixed the import logic. The main difference is that if we call an import hook via sys.meta_path, it succeeds (a bit brokenly, like CPython) even if the load_module() method doesn't add the module in sys.modules. diff --git a/pypy/module/cpyext/import_.py b/pypy/module/cpyext/import_.py --- a/pypy/module/cpyext/import_.py +++ b/pypy/module/cpyext/import_.py @@ -123,5 +123,4 @@ pathname = code.co_filename w_mod = importing.add_module(space, w_name) space.setattr(w_mod, space.wrap('__file__'), space.wrap(pathname)) - importing.exec_code_module(space, w_mod, code) - return w_mod + return importing.exec_code_module(space, w_mod, code, w_name) diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -597,6 +597,11 @@ @jit.dont_look_inside def load_module(space, w_modulename, find_info, reuse=False): + """Like load_module() in CPython's import.c, this will normally + make a module object, store it in sys.modules, execute code in it, + and then fetch it again from sys.modules. But this logic is not + used if we're calling a PEP302 loader. + """ if find_info is None: return @@ -625,17 +630,15 @@ try: if find_info.modtype == PY_SOURCE: - load_source_module( + return load_source_module( space, w_modulename, w_mod, find_info.filename, find_info.stream.readall(), find_info.stream.try_to_find_file_descriptor()) - return w_mod elif find_info.modtype == PY_COMPILED: magic = _r_long(find_info.stream) timestamp = _r_long(find_info.stream) - load_compiled_module(space, w_modulename, w_mod, find_info.filename, + return load_compiled_module(space, w_modulename, w_mod, find_info.filename, magic, timestamp, find_info.stream.readall()) - return w_mod elif find_info.modtype == PKG_DIRECTORY: w_path = space.newlist([space.wrap(find_info.filename)]) space.setattr(w_mod, space.wrap('__path__'), w_path) @@ -644,14 +647,13 @@ if find_info is None: return w_mod try: - load_module(space, w_modulename, find_info, reuse=True) + w_mod = load_module(space, w_modulename, find_info, + reuse=True) finally: try: find_info.stream.close() except StreamErrors: pass - # fetch the module again, in case of "substitution" - w_mod = check_sys_modules(space, w_modulename) return w_mod elif find_info.modtype == C_EXTENSION and has_so_extension(space): load_c_extension(space, find_info.filename, space.str_w(w_modulename)) @@ -677,13 +679,6 @@ try: if find_info: w_mod = load_module(space, w_modulename, find_info) - try: - w_mod = space.getitem(space.sys.get("modules"), - w_modulename) - except OperationError as oe: - if not oe.match(space, space.w_KeyError): - raise - raise OperationError(space.w_ImportError, w_modulename) if w_parent is not None: space.setattr(w_parent, space.wrap(partname), w_mod) return w_mod @@ -875,20 +870,32 @@ pycode = ec.compiler.compile(source, pathname, 'exec', 0) return pycode -def exec_code_module(space, w_mod, code_w): +def exec_code_module(space, w_mod, code_w, w_modulename, check_afterwards=True): + """ + Execute a code object in the module's dict. Returns + 'sys.modules[modulename]', which must exist. + """ w_dict = space.getattr(w_mod, space.wrap('__dict__')) space.call_method(w_dict, 'setdefault', space.wrap('__builtins__'), space.wrap(space.builtin)) code_w.exec_code(space, w_dict, w_dict) + if check_afterwards: + w_mod = check_sys_modules(space, w_modulename) + if w_mod is None: + raise oefmt(space.w_ImportError, + "Loaded module %R not found in sys.modules", + w_modulename) + return w_mod + @jit.dont_look_inside def load_source_module(space, w_modulename, w_mod, pathname, source, fd, - write_pyc=True): + write_pyc=True, check_afterwards=True): """ - Load a source module from a given file and return its module - object. + Load a source module from a given file. Returns the result + of sys.modules[modulename], which must exist. """ w = space.wrap @@ -927,9 +934,8 @@ code_w.remove_docstrings(space) update_code_filenames(space, code_w, pathname) - exec_code_module(space, w_mod, code_w) - - return w_mod + return exec_code_module(space, w_mod, code_w, w_modulename, + check_afterwards=check_afterwards) def update_code_filenames(space, code_w, pathname, oldname=None): assert isinstance(code_w, PyCode) @@ -1012,10 +1018,10 @@ @jit.dont_look_inside def load_compiled_module(space, w_modulename, w_mod, cpathname, magic, - timestamp, source): + timestamp, source, check_afterwards=True): """ - Load a module from a compiled file, execute it, and return its - module object. + Load a module from a compiled file and execute it. Returns + 'sys.modules[modulename]', which must exist. """ log_pyverbose(space, 1, "import %s # compiled from %s\n" % (space.str_w(w_modulename), cpathname)) @@ -1032,9 +1038,8 @@ if optimize >= 2: code_w.remove_docstrings(space) - exec_code_module(space, w_mod, code_w) - - return w_mod + return exec_code_module(space, w_mod, code_w, w_modulename, + check_afterwards=check_afterwards) def open_exclusive(space, cpathname, mode): try: diff --git a/pypy/module/imp/interp_imp.py b/pypy/module/imp/interp_imp.py --- a/pypy/module/imp/interp_imp.py +++ b/pypy/module/imp/interp_imp.py @@ -98,33 +98,35 @@ w_mod = space.wrap(Module(space, w_modulename)) importing._prepare_module(space, w_mod, filename, None) - importing.load_source_module( + w_mod = importing.load_source_module( space, w_modulename, w_mod, filename, stream.readall(), stream.try_to_find_file_descriptor()) if space.is_none(w_file): stream.close() return w_mod -@unwrap_spec(filename='str0') -def _run_compiled_module(space, w_modulename, filename, w_file, w_module): +@unwrap_spec(filename='str0', check_afterwards=int) +def _run_compiled_module(space, w_modulename, filename, w_file, w_module, + check_afterwards=False): # the function 'imp._run_compiled_module' is a pypy-only extension stream = get_file(space, w_file, filename, 'rb') magic = importing._r_long(stream) timestamp = importing._r_long(stream) - importing.load_compiled_module( + w_mod = importing.load_compiled_module( space, w_modulename, w_module, filename, magic, timestamp, - stream.readall()) + stream.readall(), check_afterwards=check_afterwards) if space.is_none(w_file): stream.close() + return w_mod @unwrap_spec(filename='str0') def load_compiled(space, w_modulename, filename, w_file=None): w_mod = space.wrap(Module(space, w_modulename)) importing._prepare_module(space, w_mod, filename, None) - _run_compiled_module(space, w_modulename, filename, w_file, w_mod) - return w_mod + return _run_compiled_module(space, w_modulename, filename, w_file, w_mod, + check_afterwards=True) @unwrap_spec(filename=str) def load_dynamic(space, w_modulename, filename, w_file=None): diff --git a/pypy/module/imp/test/test_import.py b/pypy/module/imp/test/test_import.py --- a/pypy/module/imp/test/test_import.py +++ b/pypy/module/imp/test/test_import.py @@ -118,7 +118,7 @@ filename = str(p.join("x.py")) stream = streamio.open_file_as_stream(filename, "r") try: - importing.load_source_module( + _load_source_module( space, w_modname, w(importing.Module(space, w_modname)), filename, stream.readall(), stream.try_to_find_file_descriptor()) @@ -139,6 +139,15 @@ return str(root) +def _load_source_module(space, w_modname, w_mod, *args, **kwds): + kwds.setdefault('check_afterwards', False) + return importing.load_source_module(space, w_modname, w_mod, *args, **kwds) + +def _load_compiled_module(space, w_modname, w_mod, *args, **kwds): + kwds.setdefault('check_afterwards', False) + return importing.load_compiled_module(space, w_modname, w_mod, + *args, **kwds) + def _setup(space): dn = setup_directory_structure(space) @@ -887,8 +896,7 @@ w_mod = space.wrap(Module(space, w_modulename)) magic = importing._r_long(stream) timestamp = importing._r_long(stream) - w_ret = importing.load_compiled_module(space, - w_modulename, + w_ret = _load_compiled_module(space, w_modulename, w_mod, cpathname, magic, @@ -946,7 +954,7 @@ pathname = _testfilesource() stream = streamio.open_file_as_stream(pathname, "r") try: - w_ret = importing.load_source_module( + w_ret = _load_source_module( space, w_modulename, w_mod, pathname, stream.readall(), stream.try_to_find_file_descriptor()) @@ -968,7 +976,7 @@ pathname = _testfilesource() stream = streamio.open_file_as_stream(pathname, "r") try: - w_ret = importing.load_source_module( + w_ret = _load_source_module( space, w_modulename, w_mod, pathname, stream.readall(), stream.try_to_find_file_descriptor(), @@ -987,7 +995,7 @@ try: space.setattr(space.sys, space.wrap('dont_write_bytecode'), space.w_True) - w_ret = importing.load_source_module( + w_ret = _load_source_module( space, w_modulename, w_mod, pathname, stream.readall(), stream.try_to_find_file_descriptor()) @@ -1006,7 +1014,7 @@ pathname = _testfilesource(source="<Syntax Error>") stream = streamio.open_file_as_stream(pathname, "r") try: - w_ret = importing.load_source_module( + w_ret = _load_source_module( space, w_modulename, w_mod, pathname, stream.readall(), stream.try_to_find_file_descriptor()) @@ -1026,7 +1034,7 @@ pathname = _testfilesource(source="a = unknown_name") stream = streamio.open_file_as_stream(pathname, "r") try: - w_ret = importing.load_source_module( + w_ret = _load_source_module( space, w_modulename, w_mod, pathname, stream.readall(), stream.try_to_find_file_descriptor()) @@ -1114,7 +1122,7 @@ magic = importing._r_long(stream) timestamp = importing._r_long(stream) space2.raises_w(space2.w_ImportError, - importing.load_compiled_module, + _load_compiled_module, space2, w_modulename, w_mod, @@ -1326,10 +1334,7 @@ # use an import hook that doesn't update sys.modules, then the # import succeeds; but at the same time, you can have the same # result without an import hook (see test_del_from_sys_modules) - # and then the import fails. This looks like even more mess - # to replicate, so we ignore it until someone really hits this - # case... - skip("looks like an inconsistency in CPython") + # and then the import fails. Mess mess mess. class ImportHook(object): def find_module(self, fullname, path=None): diff --git a/pypy/module/zipimport/interp_zipimport.py b/pypy/module/zipimport/interp_zipimport.py --- a/pypy/module/zipimport/interp_zipimport.py +++ b/pypy/module/zipimport/interp_zipimport.py @@ -152,8 +152,7 @@ importing._prepare_module(space, w_mod, real_name, pkgpath) co_filename = self.make_co_filename(filename) code_w = importing.parse_source_module(space, co_filename, buf) - importing.exec_code_module(space, w_mod, code_w) - return w_mod + return importing.exec_code_module(space, w_mod, code_w, w(modname)) def _parse_mtime(self, space, filename): w = space.wrap @@ -205,10 +204,10 @@ real_name = self.filename + os.path.sep + self.corr_zname(filename) space.setattr(w_mod, w('__loader__'), space.wrap(self)) importing._prepare_module(space, w_mod, real_name, pkgpath) - result = importing.load_compiled_module(space, w(modname), w_mod, + w_result = importing.load_compiled_module(space, w(modname), w_mod, filename, magic, timestamp, buf) - return result + return w_result def have_modulefile(self, space, filename): if ZIPSEP != os.path.sep: _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit