summaryrefslogtreecommitdiff
path: root/debian/patches/pep3147-core
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2019-12-02 13:09:17 +0300
committerIgor Pashev <pashev.igor@gmail.com>2019-12-02 13:09:17 +0300
commit38fde63f74091af1f6a0d485474769bb6b4f17ce (patch)
tree1317a1fa2ef61c710ff5c653f43c0af8bb164ca6 /debian/patches/pep3147-core
downloadpypy-debian.tar.gz
Import pypy (7.2.0+dfsg-1)debian/7.2.0+dfsg-1debian
Diffstat (limited to 'debian/patches/pep3147-core')
-rw-r--r--debian/patches/pep3147-core831
1 files changed, 831 insertions, 0 deletions
diff --git a/debian/patches/pep3147-core b/debian/patches/pep3147-core
new file mode 100644
index 0000000..44fbc17
--- /dev/null
+++ b/debian/patches/pep3147-core
@@ -0,0 +1,831 @@
+From: Stefano Rivera <stefanor@debian.org>
+Date: Sat, 7 Oct 2017 09:38:57 +0200
+Subject: PEP3147 support
+
+Tests modified from Barry Warsaw's PEP3147 cpython support.
+
+Forwarded: no
+Last-Update: 2013-02-23
+---
+ pypy/config/pypyoption.py | 5 +
+ pypy/doc/interpreter.rst | 1 +
+ pypy/interpreter/app_main.py | 1 +
+ pypy/interpreter/main.py | 1 +
+ pypy/interpreter/test/test_main.py | 11 +
+ pypy/module/imp/importing.py | 81 +++++-
+ pypy/module/imp/interp_imp.py | 12 +
+ pypy/module/imp/moduledef.py | 3 +
+ pypy/module/imp/test/test_app.py | 7 +-
+ pypy/module/imp/test/test_import.py | 323 ++++++++++++++++++++++--
+ pypy/module/zipimport/test/test_undocumented.py | 23 +-
+ 11 files changed, 430 insertions(+), 38 deletions(-)
+
+diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
+index 9c627a9..52db19f 100644
+--- a/pypy/config/pypyoption.py
++++ b/pypy/config/pypyoption.py
+@@ -151,6 +151,11 @@ pypy_optiondescription = OptionDescription("objspace", "Object Space Options", [
+ cmdline="--soabi",
+ default=None),
+
++ StrOption("magic_tag",
++ "Tag to differentiate .pyc files for different Python interpreters",
++ cmdline="--magic_tag",
++ default=None),
++
+ BoolOption("honor__builtins__",
+ "Honor the __builtins__ key of a module dictionary",
+ default=False),
+diff --git a/pypy/doc/interpreter.rst b/pypy/doc/interpreter.rst
+index 57b5207..7f32dfd 100644
+--- a/pypy/doc/interpreter.rst
++++ b/pypy/doc/interpreter.rst
+@@ -239,6 +239,7 @@ attributes:
+
+ * ``__doc__`` the docstring of the module
+ * ``__file__`` the source filename from which this module was instantiated
++* ``__cached__`` the filename for the byte-compiled cache of this module
+ * ``__path__`` state used for relative imports
+
+ Apart from the basic Module used for importing
+diff --git a/pypy/interpreter/app_main.py b/pypy/interpreter/app_main.py
+index ec5dcab..d9f154d 100755
+--- a/pypy/interpreter/app_main.py
++++ b/pypy/interpreter/app_main.py
+@@ -742,6 +742,7 @@ def run_command_line(interactive,
+ # on the command-line.
+ filename = sys.argv[0]
+ mainmodule.__file__ = filename
++ mainmodule.__cached__ = None
+ sys.path.insert(0, sys.pypy_resolvedirof(filename))
+ # assume it's a pyc file only if its name says so.
+ # CPython goes to great lengths to detect other cases
+diff --git a/pypy/interpreter/main.py b/pypy/interpreter/main.py
+index e1141a5..24f58b7 100644
+--- a/pypy/interpreter/main.py
++++ b/pypy/interpreter/main.py
+@@ -43,6 +43,7 @@ def _run_eval_string(source, filename, space, eval):
+ space.setitem(w_globals, space.newtext('__builtins__'), space.builtin)
+ if filename is not None:
+ space.setitem(w_globals, space.newtext('__file__'), space.newtext(filename))
++ space.setitem(w_globals, space.newtext('__cached__'), space.w_None)
+
+ retval = pycode.exec_code(space, w_globals, w_globals)
+ if eval:
+diff --git a/pypy/interpreter/test/test_main.py b/pypy/interpreter/test/test_main.py
+index dc7e536..54eebe2 100644
+--- a/pypy/interpreter/test/test_main.py
++++ b/pypy/interpreter/test/test_main.py
+@@ -13,6 +13,12 @@ def main():
+ main()
+ """
+
++test__file__code = """
++assert __file__ is not None
++assert __cached__ is None
++print len('hello world')
++"""
++
+ # On module test we want to ensure that the called module __name__ is
+ # '__main__' and argv is set as expected.
+ testmodulecode = """
+@@ -39,12 +45,14 @@ def checkoutput(space, expected_output, f, *args):
+ assert capturefn.read(mode='rU') == expected_output
+
+ testfn = udir.join('tmp_hello_world.py')
++test__file__fn = udir.join('test__file__.py')
+ testmodule = 'tmp_hello_module'
+ testpackage = 'tmp_package'
+
+ class TestMain:
+ def setup_class(cls):
+ testfn.write(testcode, 'w')
++ test__file__fn.write(test__file__code, 'w')
+ udir.join(testmodule + '.py').write(testmodulecode, 'w')
+ udir.ensure(testpackage, '__init__.py')
+ udir.join(testpackage, testmodule + '.py').write(testmodulecode, 'w')
+@@ -78,3 +86,6 @@ class TestMain:
+ testmodule, ['hello world'])
+ checkoutput(self.space, testresultoutput, main.run_module,
+ testpackage + '.' + testmodule, ['hello world'])
++
++ def test__file__file(self):
++ checkoutput(self.space, testresultoutput, main.run_file, str(test__file__fn))
+diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py
+index 24e5b31..12635cb 100644
+--- a/pypy/module/imp/importing.py
++++ b/pypy/module/imp/importing.py
+@@ -12,7 +12,7 @@ from pypy.interpreter.baseobjspace import W_Root, CannotHaveLock
+ from pypy.interpreter.eval import Code
+ from pypy.interpreter.pycode import PyCode
+ from pypy.interpreter.streamutil import wrap_streamerror
+-from rpython.rlib import streamio, jit
++from rpython.rlib import rstring, streamio, jit
+ from rpython.rlib.streamio import StreamErrors
+ from rpython.rlib.objectmodel import we_are_translated, specialize
+ from pypy.module.sys.version import PYPY_VERSION
+@@ -40,6 +40,7 @@ SO = '.pyd' if _WIN32 else '.so'
+ # split the two usages again.
+ #DEFAULT_SOABI = 'pypy-%d%d' % PYPY_VERSION[:2]
+ DEFAULT_SOABI = 'pypy-41'
++DEFAULT_MAGIC_TAG = DEFAULT_SOABI
+
+ @specialize.memo()
+ def get_so_extension(space):
+@@ -605,6 +606,7 @@ def find_module(space, modulename, w_modulename, partname, w_path,
+ def _prepare_module(space, w_mod, filename, pkgdir):
+ space.sys.setmodule(w_mod)
+ space.setattr(w_mod, space.newtext('__file__'), space.newtext(filename))
++ space.setattr(w_mod, space.newtext('__cached__'), space.w_None)
+ space.setattr(w_mod, space.newtext('__doc__'), space.w_None)
+ if pkgdir is not None:
+ space.setattr(w_mod, space.newtext('__path__'), space.newlist([space.newtext(pkgdir)]))
+@@ -885,6 +887,65 @@ def get_pyc_magic(space):
+
+ return default_magic
+
++def get_pyc_tag(space):
++ """Return the tag used in __pycache__ filenames"""
++ # XXX CPython testing hack: use the default
++ if not we_are_translated():
++ return DEFAULT_MAGIC_TAG
++
++ if space.config.objspace.magic_tag is not None:
++ magic_tag = space.config.objspace.magic_tag
++ else:
++ magic_tag = DEFAULT_MAGIC_TAG
++ return magic_tag
++
++def make_compiled_pathname(space, pathname):
++ """
++ The PEP 3147 path to the byte-compiled file associated with the source path
++ """
++ pathname = rstring.assert_str0(pathname)
++
++ index = pathname.rfind(os.sep)
++ if index < 0:
++ pycachedir = '__pycache__'
++ basename = pathname
++ else:
++ pycachedir = pathname[:index + 1] + '__pycache__'
++ basename = pathname[index + 1:]
++
++ index = basename.rfind('.')
++ if index > 0:
++ basename = basename[:index + 1]
++
++ filename = basename + get_pyc_tag(space) + '.pyc'
++ cpathname = os.path.join(pycachedir, filename)
++ return cpathname
++
++def make_source_pathname(space, cpathname):
++ """
++ Given the path to a PEP 3147 file name, return the associated source code
++ file path.
++ """
++ cpathname = rstring.assert_str0(cpathname)
++
++ index = cpathname.rfind(os.sep)
++ if index < 0:
++ raise OperationError(space.w_ValueError, space.newtext(
++ "Not a PEP 3147 pyc path: %s" % cpathname))
++ pycachedir = cpathname[:index]
++ filename = cpathname[index + 1:]
++
++ index = pycachedir.rfind(os.sep)
++ extension = '.' + get_pyc_tag(space) + '.pyc'
++ ext_index = len(filename) - len(extension)
++ if (index < 0 or pycachedir[index + 1:] != '__pycache__'
++ or not filename.endswith(extension)
++ or ext_index < 0):
++ raise OperationError(space.w_ValueError, space.newtext(
++ "Not a PEP 3147 pyc path: %s" % cpathname))
++ basedir = pycachedir[:index]
++ basename = filename[:ext_index]
++ return os.path.join(basedir, basename + '.py')
+
+ def parse_source_module(space, pathname, source):
+ """ Parse a source file and return the corresponding code object """
+@@ -927,7 +988,7 @@ def load_source_module(space, w_modulename, w_mod, pathname, source, fd,
+ src_stat = os.fstat(fd)
+ except OSError as e:
+ raise wrap_oserror(space, e, pathname) # better report this error
+- cpathname = pathname + 'c'
++ cpathname = make_compiled_pathname(space, pathname)
+ mtime = int(src_stat[stat.ST_MTIME])
+ mode = src_stat[stat.ST_MODE]
+ stream = check_compiled_module(space, cpathname, mtime)
+@@ -939,7 +1000,7 @@ def load_source_module(space, w_modulename, w_mod, pathname, source, fd,
+ _wrap_readall(space, stream))
+ finally:
+ _close_ignore(stream)
+- space.setattr(w_mod, space.newtext('__file__'), space.newtext(cpathname))
++ space.setattr(w_mod, space.newtext('__file__'), space.newtext(pathname))
+ else:
+ code_w = parse_source_module(space, pathname, source)
+
+@@ -955,6 +1016,7 @@ def load_source_module(space, w_modulename, w_mod, pathname, source, fd,
+ if optimize >= 2:
+ code_w.remove_docstrings(space)
+
++ space.setattr(w_mod, space.newtext('__cached__'), space.newtext(cpathname))
+ update_code_filenames(space, code_w, pathname)
+ return exec_code_module(space, w_mod, code_w, w_modulename,
+ check_afterwards=check_afterwards)
+@@ -1117,6 +1179,19 @@ def write_compiled_module(space, co, cpathname, src_mode, src_mtime):
+ raise
+ #print "Problem while marshalling %s, skipping" % cpathname
+ return
++
++ # Create PEP3147 __pycache__ dir if necessary
++ index = cpathname.rfind(os.sep)
++ if index < 0:
++ return
++ pycachedir = cpathname[:index]
++ if not os.path.isdir(pycachedir):
++ mode = src_mode | 0755
++ try:
++ os.mkdir(pycachedir, mode)
++ except OSError:
++ return
++
+ #
+ # Careful here: we must not crash nor leave behind something that looks
+ # too much like a valid pyc file but really isn't one.
+diff --git a/pypy/module/imp/interp_imp.py b/pypy/module/imp/interp_imp.py
+index 09127ab..7d133f5 100644
+--- a/pypy/module/imp/interp_imp.py
++++ b/pypy/module/imp/interp_imp.py
+@@ -36,6 +36,18 @@ def get_magic(space):
+ d = x & 0xff
+ return space.newbytes(chr(a) + chr(b) + chr(c) + chr(d))
+
++def get_tag(space):
++ return space.newtext(importing.get_pyc_tag(space))
++
++@unwrap_spec(path='fsencode')
++def cache_from_source(space, path, w_debug_override=None):
++ # w_debug_override is ignored, pypy doesn't support __debug__
++ return space.newtext(importing.make_compiled_pathname(space, path))
++
++@unwrap_spec(path='fsencode')
++def source_from_cache(space, path):
++ return space.newtext(importing.make_source_pathname(space, path))
++
+ def get_file(space, w_file, filename, filemode):
+ if space.is_none(w_file):
+ try:
+diff --git a/pypy/module/imp/moduledef.py b/pypy/module/imp/moduledef.py
+index 39b577a..fb1023a 100644
+--- a/pypy/module/imp/moduledef.py
++++ b/pypy/module/imp/moduledef.py
+@@ -17,6 +17,9 @@ class Module(MixedModule):
+ 'get_suffixes': 'interp_imp.get_suffixes',
+
+ 'get_magic': 'interp_imp.get_magic',
++ 'get_tag': 'interp_imp.get_tag',
++ 'cache_from_source': 'interp_imp.cache_from_source',
++ 'source_from_cache': 'interp_imp.source_from_cache',
+ 'find_module': 'interp_imp.find_module',
+ 'load_module': 'interp_imp.load_module',
+ 'load_source': 'interp_imp.load_source',
+diff --git a/pypy/module/imp/test/test_app.py b/pypy/module/imp/test/test_app.py
+index f095168..70c0a00 100644
+--- a/pypy/module/imp/test/test_app.py
++++ b/pypy/module/imp/test/test_app.py
+@@ -150,6 +150,7 @@ class AppTestImpModule:
+
+ def test_rewrite_pyc_check_code_name(self):
+ # This one is adapted from cpython's Lib/test/test_import.py
++ from imp import cache_from_source
+ from os import chmod
+ from os.path import join
+ from sys import modules, path
+@@ -159,6 +160,7 @@ class AppTestImpModule:
+ import sys
+ code_filename = sys._getframe().f_code.co_filename
+ module_filename = __file__
++ module_bytefilename = __cached__
+ constant = 1
+ def func():
+ pass
+@@ -170,7 +172,7 @@ class AppTestImpModule:
+ file_name = join(dir_name, module_name + '.py')
+ with open(file_name, "wb") as f:
+ f.write(code)
+- compiled_name = file_name + ("c" if __debug__ else "o")
++ compiled_name = cache_from_source(file_name)
+ chmod(file_name, 0777)
+
+ # Setup
+@@ -188,7 +190,8 @@ class AppTestImpModule:
+ try:
+ # Ensure proper results
+ assert mod != orig_module
+- assert mod.module_filename == compiled_name
++ assert mod.module_filename == file_name
++ assert mod.module_bytefilename == compiled_name
+ assert mod.code_filename == file_name
+ assert mod.func_filename == file_name
+ finally:
+diff --git a/pypy/module/imp/test/test_import.py b/pypy/module/imp/test/test_import.py
+index a7b92a0..e5851ea 100644
+--- a/pypy/module/imp/test/test_import.py
++++ b/pypy/module/imp/test/test_import.py
+@@ -8,7 +8,7 @@ from rpython.rlib import streamio
+ from pypy.tool.option import make_config
+ from pypy.tool.pytest.objspace import maketestobjspace
+ import pytest
+-import sys, os
++import shutil, sys, os
+ import tempfile, marshal
+
+ from pypy.module.imp import importing
+@@ -107,12 +107,18 @@ def setup_directory_structure(space):
+
+ # create compiled/x.py and a corresponding pyc file
+ p = setuppkg("compiled", x = "x = 84")
++ try:
++ p.mkdir('__pycache__')
++ except py.error.EEXIST:
++ pass
++ cpathname = p.join('__pycache__').join(
++ 'x.' + importing.get_pyc_tag(space) + '.pyc')
+ if conftest.option.runappdirect:
+ 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])
+- p.join("x.pyc").write(imp.get_magic() + s2 + s3, mode='wb')
++ cpathname.write(imp.get_magic() + s2 + s3, mode='wb')
+ else:
+ w = space.wrap
+ w_modname = w("compiled.x")
+@@ -127,8 +133,9 @@ def setup_directory_structure(space):
+ stream.close()
+ if not space.config.translation.sandbox:
+ # also create a lone .pyc file
+- p.join('lone.pyc').write(p.join('x.pyc').read(mode='rb'),
+- mode='wb')
++
++ p.join(importing.make_compiled_pathname(space, 'lone.py')
++ ).write(cpathname.read(mode='rb'), mode='wb')
+
+ # create a .pyw file
+ p = setuppkg("windows", x = "x = 78")
+@@ -873,6 +880,8 @@ def _testfilesource(source="x=42"):
+
+ class TestPycStuff:
+ # ___________________ .pyc related stuff _________________
++ def setup_class(cls):
++ cls.tag = importing.get_pyc_tag(cls.space)
+
+ def test_check_compiled_module(self):
+ space = self.space
+@@ -1013,7 +1022,8 @@ class TestPycStuff:
+ ret = space.int_w(w_ret)
+ assert ret == 42
+
+- cpathname = udir.join('test.pyc')
++ cpathname = importing.make_compiled_pathname(space, 'test.py')
++ cpathname = udir.join(cpathname)
+ assert cpathname.check()
+ cpathname.remove()
+
+@@ -1031,7 +1041,8 @@ class TestPycStuff:
+ write_pyc=False)
+ finally:
+ stream.close()
+- cpathname = udir.join('test.pyc')
++ cpathname = importing.make_compiled_pathname(space, 'test.py')
++ cpathname = udir.join(cpathname)
+ assert not cpathname.check()
+
+ def test_load_source_module_dont_write_bytecode(self):
+@@ -1051,7 +1062,8 @@ class TestPycStuff:
+ space.setattr(space.sys, space.wrap('dont_write_bytecode'),
+ space.w_False)
+ stream.close()
+- cpathname = udir.join('test.pyc')
++ cpathname = importing.make_compiled_pathname(space, 'test.py')
++ cpathname = udir.join(cpathname)
+ assert not cpathname.check()
+
+ def test_load_source_module_syntaxerror(self):
+@@ -1071,7 +1083,8 @@ class TestPycStuff:
+ pass
+ stream.close()
+
+- cpathname = udir.join('test.pyc')
++ cpathname = importing.make_compiled_pathname(space, 'test.py')
++ cpathname = udir.join(cpathname)
+ assert not cpathname.check()
+
+ def test_load_source_module_importerror(self):
+@@ -1092,7 +1105,8 @@ class TestPycStuff:
+ stream.close()
+
+ # And the .pyc has been generated
+- cpathname = udir.join('test.pyc')
++ cpathname = importing.make_compiled_pathname(space, 'test.py')
++ cpathname = udir.join(cpathname)
+ assert cpathname.check()
+
+ def test_write_compiled_module(self):
+@@ -1109,7 +1123,8 @@ class TestPycStuff:
+ pycode = w_ret
+ assert type(pycode) is pypy.interpreter.pycode.PyCode
+
+- cpathname = str(udir.join('cpathname.pyc'))
++ cpathname = importing.make_compiled_pathname(space, 'cpathname.py')
++ cpathname = str(udir.join(cpathname))
+ mode = 0777
+ mtime = 12345
+ importing.write_compiled_module(space,
+@@ -1181,6 +1196,271 @@ class TestPycStuff:
+ finally:
+ stream.close()
+
++ def test_make_compiled_pathname(self):
++ # Given the path to a .py file, return the path to its PEP 3147
++ # defined .pyc file (i.e. under __pycache__).
++ cpathname = importing.make_compiled_pathname(self.space,
++ '/foo/bar/baz/qux.py')
++ expected = '/foo/bar/baz/__pycache__/qux.%s.pyc' % self.tag
++ assert cpathname == expected
++
++ def test_make_compiled_pathname_cwd(self):
++ cpathname = importing.make_compiled_pathname(self.space, 'foo.py')
++ expected = os.sep.join(('__pycache__', 'foo.%s.pyc' % self.tag))
++ assert cpathname == expected
++
++ @pytest.mark.skipif('os.altsep is None')
++ def test_altsep_make_compiled_pathname(self):
++ # Windows path and PEP 3147.
++ cpathname = importing.make_compiled_pathname(self.space,
++ '\\foo\\bar\\baz\\qux.py')
++ expected = '\\foo\\bar\\baz\\__pycache__\\qux.%s.pyc' % self.tag
++ assert cpathname == expected
++
++ @pytest.mark.skipif('os.altsep is None')
++ def test_altsep_and_sep_make_compiled_pathname(self):
++ # Windows path and PEP 3147 where altsep is right of sep.
++ cpathname = importing.make_compiled_pathname(self.space,
++ '\\foo\\bar/baz\\qux.py')
++ expected = '\\foo\\bar/baz\\__pycache__\\qux.%s.pyc' % self.tag
++ assert cpathname == expected
++
++ @pytest.mark.skipif('os.altsep is None')
++ def test_sep_altsep_and_sep_make_compiled_pathname(self):
++ # Windows path and PEP 3147 where sep is right of altsep.
++ cpathname = importing.make_compiled_pathname(self.space,
++ '\\foo\\bar\\baz/qux.py')
++ expected = '\\foo\\bar\\baz/__pycache__/qux.%s.pyc' % self.tag
++ assert cpathname == expected
++
++ def test_make_source_pathname(self):
++ # Given the path to a PEP 3147 defined .pyc file, return the path to
++ # its source. This tests the good path.
++ pathname = importing.make_source_pathname(self.space,
++ '/foo/bar/baz/__pycache__/qux.%s.pyc' % self.tag)
++ assert pathname == '/foo/bar/baz/qux.py'
++
++ def test_make_source_pathname_bad_path(self):
++ # When the path to a pyc file is not in PEP 3147 format, a ValueError
++ # is raised.
++ try:
++ importing.make_source_pathname(self.space, '/foo/bar/bazqux.pyc')
++ except OperationError, e:
++ if not e.match(self.space, self.space.w_ValueError):
++ raise
++ else:
++ raise Exception("Should have raised ValueError")
++
++ def test_make_source_pathname_no_slash(self):
++ # No slashes at all in path -> ValueError
++ try:
++ importing.make_source_pathname(self.space, 'foo.%s.pyc' % self.tag)
++ except OperationError, e:
++ if not e.match(self.space, self.space.w_ValueError):
++ raise
++ else:
++ raise Exception("Should have raised ValueError")
++
++ def test_make_source_pathname_too_few_dots(self):
++ # Too few dots in final path component -> ValueError
++ try:
++ importing.make_source_pathname(self.space, '__pycache__/foo.pyc')
++ except OperationError, e:
++ if not e.match(self.space, self.space.w_ValueError):
++ raise
++ else:
++ raise Exception("Should have raised ValueError")
++
++ def test_make_source_pathname_too_many_dots(self):
++ # Too many dots in final path component -> ValueError
++ pathname = '__pycache__/foo.%s.foo.pyc' % self.tag
++ try:
++ importing.make_source_pathname(self.space, pathname)
++ except OperationError, e:
++ if not e.match(self.space, self.space.w_ValueError):
++ raise
++ else:
++ raise Exception("Should have raised ValueError")
++
++ def test_make_source_pathname_no__pycache__(self):
++ # Another problem with the path -> ValueError
++ pathname = '/foo/bar/foo.%s.foo.pyc' % self.tag
++ try:
++ importing.make_source_pathname(self.space, pathname)
++ except OperationError, e:
++ if not e.match(self.space, self.space.w_ValueError):
++ raise
++ else:
++ raise Exception("Should have raised ValueError")
++
++
++class AppTestPEP3147Pyc(object):
++ def test_package___file__(self):
++ import os, sys, shutil
++ # Test that a package's __file__ points to the right source directory.
++ try:
++ os.mkdir('pep3147')
++ sys.path.insert(0, os.curdir)
++ # Touch the __init__.py file.
++ with open('pep3147/__init__.py', 'w'):
++ pass
++ m = __import__('pep3147')
++ # Ensure we load the pyc file.
++ del sys.modules['pep3147']
++ m = __import__('pep3147')
++ assert m.__file__ == os.sep.join(('.', 'pep3147', '__init__.py'))
++ finally:
++ if sys.path[0] == os.curdir:
++ del sys.path[0]
++ shutil.rmtree('pep3147')
++
++
++class AppTestPycache(object):
++ # Test the various PEP 3147 related behaviors.
++
++ def setup_class(cls):
++ space = cls.space
++
++ cls.module = '_app_test_pycache'
++ cls.filename = cls.module + '.py'
++ cls.w_module = space.wrap(cls.module)
++ cls.w_filename = space.wrap(cls.filename)
++ cls.w_tag = space.wrap(importing.get_pyc_tag(space))
++
++ def setup_method(cls, method):
++ if os.path.exists('__pycache__'):
++ shutil.rmtree('__pycache__')
++ if os.path.exists(cls.filename):
++ os.unlink(cls.filename)
++
++ with open(cls.filename, 'w') as fp:
++ print >> fp, '# This is a test file written by test_import.py'
++
++ def teardown_method(cls, method):
++ if os.path.exists('__pycache__'):
++ shutil.rmtree('__pycache__')
++ if os.path.exists(cls.filename):
++ os.unlink(cls.filename)
++
++ def test_import_pyc_path(self):
++ import sys, os
++ sys.path.insert(0, '.')
++ try:
++ assert not os.path.exists('__pycache__')
++ __import__(self.module)
++ assert os.path.exists('__pycache__')
++ assert os.path.exists(os.path.join(
++ '__pycache__', '%s.%s.pyc' % (self.module, self.tag)))
++ finally:
++ del sys.path[0]
++ sys.modules.pop(self.module, None)
++
++ @pytest.mark.skipif('os.name != "posix"')
++ def test_unwritable_directory(self):
++ # When the umask causes the new __pycache__ directory to be
++ # unwritable, the import still succeeds but no .pyc file is written.
++ import os, sys
++ sys.path.insert(0, '.')
++ try:
++ oldmask = os.umask(0222)
++ try:
++ __import__(self.module)
++ finally:
++ os.umask(oldmask)
++ assert os.path.exists('__pycache__')
++ assert not os.path.exists(os.path.join(
++ '__pycache__', '%s.%s.pyc' % (self.module, self.tag)))
++ finally:
++ del sys.path[0]
++ sys.modules.pop(self.module, None)
++
++ def test_missing_source(self):
++ # With PEP 3147 cache layout, removing the source but leaving the pyc
++ # file does not satisfy the import.
++ import imp, os, sys
++ sys.path.insert(0, '.')
++ try:
++ __import__(self.module)
++ pyc_file = imp.cache_from_source(self.filename)
++ assert os.path.exists(pyc_file)
++ os.remove(self.filename)
++ del sys.modules[self.module]
++ try:
++ __import__(self.module)
++ except ImportError:
++ pass
++ else:
++ raise "Expected ImportError to be raised"
++ finally:
++ del sys.path[0]
++ sys.modules.pop(self.module, None)
++
++ def test___cached__(self):
++ # Modules now also have an __cached__ that points to the pyc file.
++ import imp, os, sys
++ sys.path.insert(0, '.')
++ try:
++ m = __import__(self.module)
++ pyc_file = imp.cache_from_source(self.filename)
++ assert m.__cached__ == os.path.join(os.curdir, pyc_file)
++ finally:
++ del sys.path[0]
++ sys.modules.pop(self.module, None)
++
++ def test_package___cached__(self):
++ # Like test___cached__ but for packages.
++ import imp, os, shutil, sys
++ sys.path.insert(0, '.')
++ try:
++ os.mkdir('_test_pep3147')
++ # Touch the __init__.py
++ with open(os.path.join('_test_pep3147', '__init__.py'), 'w'):
++ pass
++ with open(os.path.join('_test_pep3147', 'foo.py'), 'w'):
++ pass
++ m = __import__('_test_pep3147.foo')
++ init_pyc = imp.cache_from_source(
++ os.path.join('_test_pep3147', '__init__.py'))
++ assert m.__cached__ == os.path.join(os.curdir, init_pyc)
++ foo_pyc = imp.cache_from_source(os.path.join('_test_pep3147',
++ 'foo.py'))
++ assert (sys.modules['_test_pep3147.foo'].__cached__
++ == os.path.join(os.curdir, foo_pyc))
++ finally:
++ shutil.rmtree('_test_pep3147')
++ del sys.path[0]
++ sys.modules.pop('_test_pep3147.foo', None)
++ sys.modules.pop('_test_pep3147', None)
++
++ def test_package___cached___from_pyc(self):
++ # Like test___cached__ but ensuring __cached__ when imported from a
++ # PEP 3147 pyc file.
++ import imp, os, shutil, sys
++ sys.path.insert(0, '.')
++ try:
++ os.mkdir('_test_pep3147')
++ # Touch the __init__.py
++ with open(os.path.join('_test_pep3147', '__init__.py'), 'w'):
++ pass
++ with open(os.path.join('_test_pep3147', 'foo.py'), 'w'):
++ pass
++ m = __import__('_test_pep3147.foo')
++ del sys.modules['_test_pep3147.foo']
++ del sys.modules['_test_pep3147']
++ m = __import__('_test_pep3147.foo')
++ init_pyc = imp.cache_from_source(
++ os.path.join('_test_pep3147', '__init__.py'))
++ assert m.__cached__ == os.path.join(os.curdir, init_pyc)
++ foo_pyc = imp.cache_from_source(os.path.join('_test_pep3147',
++ 'foo.py'))
++ assert (sys.modules['_test_pep3147.foo'].__cached__
++ == os.path.join(os.curdir, foo_pyc))
++ finally:
++ shutil.rmtree('_test_pep3147')
++ del sys.path[0]
++ sys.modules.pop('_test_pep3147.foo', None)
++ sys.modules.pop('_test_pep3147', None)
++
+
+ def test_PYTHONPATH_takes_precedence(space):
+ if sys.platform == "win32":
+@@ -1486,24 +1766,21 @@ class AppTestWriteBytecode(object):
+ def test_default(self):
+ import os.path
+ from test_bytecode import a
+- assert a.__file__.endswith('a.py')
+- assert os.path.exists(a.__file__ + 'c') == (not self.sandbox)
++ assert os.path.exists(a.__cached__) == (not self.sandbox)
+
+ def test_write_bytecode(self):
+ import os.path
+ import sys
+ sys.dont_write_bytecode = False
+ from test_bytecode import b
+- assert b.__file__.endswith('b.py')
+- assert os.path.exists(b.__file__ + 'c')
++ assert os.path.exists(b.__cached__)
+
+ def test_dont_write_bytecode(self):
+ import os.path
+ import sys
+ sys.dont_write_bytecode = True
+ from test_bytecode import c
+- assert c.__file__.endswith('c.py')
+- assert not os.path.exists(c.__file__ + 'c')
++ assert not os.path.exists(c.__cached__)
+
+
+ class AppTestWriteBytecodeSandbox(AppTestWriteBytecode):
+@@ -1523,25 +1800,21 @@ class _AppTestLonePycFileBase(object):
+
+ def test_import_possibly_from_pyc(self):
+ from compiled import x
+- assert x.__file__.endswith('x.pyc')
++ assert x.__file__.endswith('x.py')
++ assert x.__cached__.endswith('.pyc')
+ try:
+ from compiled import lone
+ except ImportError:
+- assert not self.lonepycfiles, "should have found 'lone.pyc'"
++ assert not self.lonepycfiles, "should have found 'lone.TAG.pyc'"
+ else:
+- assert self.lonepycfiles, "should not have found 'lone.pyc'"
+- assert lone.__file__.endswith('lone.pyc')
++ assert self.lonepycfiles, "should not have found 'lone.TAG.pyc'"
++ assert lone.__cached__.endswith('.pyc')
+
+ class AppTestNoLonePycFile(_AppTestLonePycFileBase):
+ spaceconfig = {
+ "objspace.lonepycfiles": False
+ }
+
+-class AppTestLonePycFile(_AppTestLonePycFileBase):
+- spaceconfig = {
+- "objspace.lonepycfiles": True
+- }
+-
+
+ class AppTestMultithreadedImp(object):
+ spaceconfig = dict(usemodules=['thread', 'time'])
+diff --git a/pypy/module/zipimport/test/test_undocumented.py b/pypy/module/zipimport/test/test_undocumented.py
+index 7271f20..44f47c7 100644
+--- a/pypy/module/zipimport/test/test_undocumented.py
++++ b/pypy/module/zipimport/test/test_undocumented.py
+@@ -31,12 +31,11 @@ class AppTestZipImport:
+ Clears zipimport._zip_directory_cache.
+
+ """
+- import zipimport, os, shutil, zipfile, py_compile
++ import zipimport, os, shutil, zipfile, py_compile, imp
+ example_code = 'attr = None'
+ TESTFN = '@test'
+ zipimport._zip_directory_cache.clear()
+ zip_path = TESTFN + '.zip'
+- bytecode_suffix = 'c'# if __debug__ else 'o'
+ zip_file = zipfile.ZipFile(zip_path, 'w')
+ for path in created_paths:
+ if os.sep in path:
+@@ -53,13 +52,13 @@ class AppTestZipImport:
+ zip_file.write(code_path)
+ if bytecode:
+ py_compile.compile(code_path, doraise=True)
+- zip_file.write(code_path + bytecode_suffix)
++ bytecode_path = imp.cache_from_source(code_path)
++ zip_file.write(bytecode_path)
+ zip_file.close()
+ return os.path.abspath(zip_path)
+
+ def w_cleanup_zipfile(self, created_paths):
+- import os, shutil
+- bytecode_suffix = 'c'# if __debug__ else 'o'
++ import os, shutil, imp
+ zip_path = '@test.zip'
+ for path in created_paths:
+ if os.sep in path:
+@@ -67,9 +66,17 @@ class AppTestZipImport:
+ if os.path.exists(directory):
+ shutil.rmtree(directory)
+ else:
+- for suffix in ('.py', '.py' + bytecode_suffix):
+- if os.path.exists(path + suffix):
+- os.unlink(path + suffix)
++ source_file = path + '.py'
++ if os.path.exists(source_file):
++ os.unlink(source_file)
++ bytecode_file = imp.cache_from_source(source_file)
++ if os.path.exists(bytecode_file):
++ os.unlink(bytecode_file)
++ try:
++ os.rmdir(os.path.dirname(bytecode_file))
++ except OSError:
++ pass
++
+ os.unlink(zip_path)
+
+ def test_inheritance(self):