[pypy-commit] pypy default: replicate obscure CPython package loading behavior
gutworth
pypy.commits at gmail.com
Sun Jan 22 15:07:36 EST 2017
Author: Benjamin Peterson <benjamin at 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):
More information about the pypy-commit
mailing list