Author: Benjamin Peterson <benja...@python.org> Branch: Changeset: r89693:b289308aa50b Date: 2017-01-22 12:04 -0800 http://bitbucket.org/pypy/pypy/changeset/b289308aa50b/
Log: replicate obscure CPython package loading behavior 1. When searching for an __init__ file, CPython checks for __init__.py and __init__.py[co] but not __init__.so or __init__.pyw. 2. CPython considers any __init__\.py[oc]? entry it can stat successfully to qualify a directory as a package. This means __init__.py need not be a regular file and may be something weird like /dev/null (a character device). The behavior is less strange in Python 3, where __init__.py are required to be real files. 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 @@ -64,13 +64,26 @@ space.call_method(w_stderr, "write", space.wrap(message)) def file_exists(path): - """Tests whether the given path is an existing regular file.""" + "Test whether the given path is an existing regular file." return os.path.isfile(path) and case_ok(path) +def path_exists(path): + "Test whether the given path exists." + return os.path.exists(path) and case_ok(path) + def has_so_extension(space): return (space.config.objspace.usemodules.cpyext or space.config.objspace.usemodules._cffi_backend) +def has_init_module(space, filepart): + "Return True if the directory filepart qualifies as a package." + init = os.path.join(filepart, "__init__") + if path_exists(init + ".py"): + return True + if space.config.objspace.lonepycfiles and path_exists(init + ".pyc"): + return True + return False + def find_modtype(space, filepart): """Check which kind of module to import for the given filepart, which is a path without extension. Returns PY_SOURCE, PY_COMPILED or @@ -565,9 +578,7 @@ filepart = os.path.join(path, partname) log_pyverbose(space, 2, "# trying %s" % (filepart,)) if os.path.isdir(filepart) and case_ok(filepart): - initfile = os.path.join(filepart, '__init__') - modtype, _, _ = find_modtype(space, initfile) - if modtype in (PY_SOURCE, PY_COMPILED): + if has_init_module(space, filepart): return FindInfo(PKG_DIRECTORY, filepart, None) else: msg = ("Not importing directory '%s' missing __init__.py" % 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 @@ -108,7 +108,7 @@ # create compiled/x.py and a corresponding pyc file p = setuppkg("compiled", x = "x = 84") if conftest.option.runappdirect: - import marshal, stat, struct, os, imp + import marshal, stat, struct, imp code = py.code.Source(p.join("x.py").read()).compile() s3 = marshal.dumps(code) s2 = struct.pack("<i", os.stat(str(p.join("x.py")))[stat.ST_MTIME]) @@ -138,6 +138,15 @@ pass p.join('x.py').rename(p.join('x.pyw')) + if hasattr(p, "mksymlinkto"): + p = root.join("devnullpkg") + p.ensure(dir=True) + p.join("__init__.py").mksymlinkto(os.devnull) + + p = root.join("onlypyw") + p.ensure(dir=True) + p.join("__init__.pyw") + return str(root) def _load_source_module(space, w_modname, w_mod, *args, **kwds): @@ -795,6 +804,15 @@ reload(sys) assert not output + def test_dir_with_only_pyw(self): + def imp(): + import onlypyw + raises(ImportError, imp) + + @pytest.mark.skipif(not hasattr(py.path.local, "mksymlinkto"), reason="requires symlinks") + def test_dev_null_init_file(self): + import devnullpkg + class TestAbi: def test_abi_tag(self): _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit