[pypy-commit] pypy default: Write a hack to distinguish between "true built-in modules" and
arigo
noreply at buildbot.pypy.org
Fri Dec 9 18:19:06 CET 2011
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r50328:a72429e0e0ed
Date: 2011-12-09 18:18 +0100
http://bitbucket.org/pypy/pypy/changeset/a72429e0e0ed/
Log: Write a hack to distinguish between "true built-in modules" and
"pseudo-extension built-in modules". The latters are the ones that
are extension modules in CPython. We list the formers explicitly.
True built-in modules are treated like CPython treats built-in
modules, i.e. they always shadow any xx.py. The pseudo-extension
built-in modules are treated like CPython treats extension modules,
and are only found in sys.path order for the fake entry
'.../lib_pypy/__extensions__' which we put just before 'lib_pypy'
and the 'lib-python' entries.
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -487,6 +487,16 @@
'parser', 'fcntl', '_codecs', 'binascii'
]
+ # These modules are treated like CPython treats built-in modules,
+ # i.e. they always shadow any xx.py. The other modules are treated
+ # like CPython treats extension modules, and are loaded in sys.path
+ # order by the fake entry '.../lib_pypy/__extensions__'.
+ MODULES_THAT_ALWAYS_SHADOW = dict.fromkeys([
+ '__builtin__', '__pypy__', '_ast', '_codecs', '_sre', '_warnings',
+ '_weakref', 'errno', 'exceptions', 'gc', 'imp', 'marshal',
+ 'posix', 'nt', 'pwd', 'signal', 'sys', 'thread', 'zipimport',
+ ], None)
+
def make_builtins(self):
"NOT_RPYTHON: only for initializing the space."
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
@@ -483,10 +483,20 @@
# XXX Check for frozen modules?
# when w_path is a string
+ delayed_builtin = None
+ w_lib_extensions = None
+
if w_path is None:
# check the builtin modules
if modulename in space.builtin_modules:
- return FindInfo(C_BUILTIN, modulename, None)
+ delayed_builtin = FindInfo(C_BUILTIN, modulename, None)
+ # a "real builtin module xx" shadows every file "xx.py" there
+ # could possibly be; a "pseudo-extension module" does not, and
+ # is only loaded at the point in sys.path where we find
+ # '.../lib_pypy/__extensions__'.
+ if modulename in space.MODULES_THAT_ALWAYS_SHADOW:
+ return delayed_builtin
+ w_lib_extensions = space.sys.get_state(space).w_lib_extensions
w_path = space.sys.get('path')
# XXX check frozen modules?
@@ -495,6 +505,9 @@
if w_path is not None:
for w_pathitem in space.unpackiterable(w_path):
# sys.path_hooks import hook
+ if (w_lib_extensions is not None and
+ space.is_w(w_pathitem, w_lib_extensions)):
+ return delayed_builtin
if use_loader:
w_loader = find_in_path_hooks(space, w_modulename, w_pathitem)
if w_loader:
@@ -527,7 +540,7 @@
# Out of file descriptors.
# not found
- return None
+ return delayed_builtin
def _prepare_module(space, w_mod, filename, pkgdir):
w = space.wrap
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
@@ -38,6 +38,8 @@
test_reload = "def test():\n raise ValueError\n",
infinite_reload = "import infinite_reload; reload(infinite_reload)",
del_sys_module = "import sys\ndel sys.modules['del_sys_module']\n",
+ itertools = "hello_world = 42\n",
+ gc = "should_never_be_seen = 42\n",
)
root.ensure("notapackage", dir=1) # empty, no __init__.py
setuppkg("pkg",
@@ -147,6 +149,7 @@
class AppTestImport:
def setup_class(cls): # interpreter-level
+ cls.space = gettestobjspace(usemodules=['itertools'])
cls.saved_modules = _setup(cls.space)
#XXX Compile class
@@ -571,6 +574,47 @@
else:
assert False, 'should not work'
+ def test_shadow_builtin(self):
+ # 'import gc' is supposed to always find the built-in module;
+ # like CPython, it is a built-in module, so it shadows everything,
+ # even though there is a gc.py.
+ import sys
+ assert 'gc' not in sys.modules
+ import gc
+ assert not hasattr(gc, 'should_never_be_seen')
+ assert '(built-in)' in repr(gc)
+ del sys.modules['gc']
+
+ def test_shadow_extension_1(self):
+ # 'import itertools' is supposed to find itertools.py if there is
+ # one in sys.path.
+ import sys
+ assert 'itertools' not in sys.modules
+ import itertools
+ assert hasattr(itertools, 'hello_world')
+ assert not hasattr(itertools, 'count')
+ assert '(built-in)' not in repr(itertools)
+ del sys.modules['itertools']
+
+ def test_shadow_extension_2(self):
+ # 'import itertools' is supposed to find the built-in module even
+ # if there is also one in sys.path as long as it is *after* the
+ # special entry '.../lib_pypy/__extensions__'. (Note that for now
+ # there is one in lib_pypy/itertools.py, which should not be seen
+ # either; hence the (built-in) test below.)
+ import sys
+ assert 'itertools' not in sys.modules
+ sys.path.append(sys.path.pop(0))
+ try:
+ import itertools
+ assert not hasattr(itertools, 'hello_world')
+ assert hasattr(itertools, 'izip')
+ assert '(built-in)' in repr(itertools)
+ finally:
+ sys.path.insert(0, sys.path.pop())
+ del sys.modules['itertools']
+
+
class TestAbi:
def test_abi_tag(self):
space1 = gettestobjspace(soabi='TEST')
diff --git a/pypy/module/sys/__init__.py b/pypy/module/sys/__init__.py
--- a/pypy/module/sys/__init__.py
+++ b/pypy/module/sys/__init__.py
@@ -170,3 +170,7 @@
def get_flag(self, name):
space = self.space
return space.int_w(space.getattr(self.get('flags'), space.wrap(name)))
+
+ def get_state(self, space):
+ from pypy.module.sys import state
+ return state.get(space)
diff --git a/pypy/module/sys/state.py b/pypy/module/sys/state.py
--- a/pypy/module/sys/state.py
+++ b/pypy/module/sys/state.py
@@ -24,7 +24,7 @@
# Initialize the default path
pypydir = os.path.dirname(os.path.abspath(pypy.__file__))
srcdir = os.path.dirname(pypydir)
- path = getinitialpath(srcdir)
+ path = getinitialpath(self, srcdir)
self.w_path = space.newlist([space.wrap(p) for p in path])
def checkdir(path):
@@ -35,7 +35,7 @@
platform = sys.platform
-def getinitialpath(prefix):
+def getinitialpath(state, prefix):
from pypy.module.sys.version import CPYTHON_VERSION
dirname = '%d.%d' % (CPYTHON_VERSION[0],
CPYTHON_VERSION[1])
@@ -49,6 +49,12 @@
checkdir(lib_pypy)
importlist = []
+ #
+ if state is not None: # 'None' for testing only
+ lib_extensions = os.path.join(lib_pypy, '__extensions__')
+ state.w_lib_extensions = state.space.wrap(lib_extensions)
+ importlist.append(lib_extensions)
+ #
importlist.append(lib_pypy)
importlist.append(python_std_lib_modified)
importlist.append(python_std_lib)
@@ -71,7 +77,7 @@
@unwrap_spec(srcdir=str)
def pypy_initial_path(space, srcdir):
try:
- path = getinitialpath(srcdir)
+ path = getinitialpath(get(space), srcdir)
except OSError:
return space.w_None
else:
diff --git a/pypy/module/sys/test/test_initialpath.py b/pypy/module/sys/test/test_initialpath.py
--- a/pypy/module/sys/test/test_initialpath.py
+++ b/pypy/module/sys/test/test_initialpath.py
@@ -13,7 +13,7 @@
def test_stdlib_in_prefix(tmpdir):
dirs = build_hierarchy(tmpdir)
- path = getinitialpath(str(tmpdir))
+ path = getinitialpath(None, str(tmpdir))
# we get at least 'dirs', and maybe more (e.g. plat-linux2)
assert path[:len(dirs)] == map(str, dirs)
@@ -21,7 +21,7 @@
lib_pypy, lib_python_modified, lib_python = build_hierarchy(tmpdir)
lib_tk_modified = lib_python_modified.join('lib-tk')
lib_tk = lib_python.join('lib-tk')
- path = getinitialpath(str(tmpdir))
+ path = getinitialpath(None, str(tmpdir))
i = path.index(str(lib_tk_modified))
j = path.index(str(lib_tk))
assert i < j
More information about the pypy-commit
mailing list