diff options
Diffstat (limited to 'debian/patches/pep3147-stdlib')
-rw-r--r-- | debian/patches/pep3147-stdlib | 1440 |
1 files changed, 1440 insertions, 0 deletions
diff --git a/debian/patches/pep3147-stdlib b/debian/patches/pep3147-stdlib new file mode 100644 index 0000000..12c3076 --- /dev/null +++ b/debian/patches/pep3147-stdlib @@ -0,0 +1,1440 @@ +From: Stefano Rivera <stefanor@debian.org> +Date: Sat, 7 Oct 2017 09:38:57 +0200 +Subject: PEP3147 changes to lib-python + +Backported from cpython's PEP3147 commit + +Origin: cpython: http://hg.python.org/cpython/rev/7b69e630d237 +Author: Barry Warsaw <barry@python.org> +Author: Stefano Rivera <stefanor@debian.org> +Last-Update: 2013-02-23 +--- + lib-python/2.7/compileall.py | 67 ++++++++----- + lib-python/2.7/inspect.py | 1 + + lib-python/2.7/py_compile.py | 35 ++++--- + lib-python/2.7/pydoc.py | 3 +- + lib-python/2.7/runpy.py | 2 + + lib-python/2.7/site.py | 13 ++- + lib-python/2.7/test/script_helper.py | 23 ++--- + lib-python/2.7/test/test_cmd_line_script.py | 20 ++-- + lib-python/2.7/test/test_compileall.py | 61 +++++++++++- + lib-python/2.7/test/test_imp.py | 142 ++++++++++++++++++++++++++++ + lib-python/2.7/test/test_import.py | 65 +++++++------ + lib-python/2.7/test/test_pkg.py | 20 ++-- + lib-python/2.7/test/test_pkgimport.py | 20 ++-- + lib-python/2.7/test/test_py_compile.py | 5 +- + lib-python/2.7/test/test_pydoc.py | 3 +- + lib-python/2.7/test/test_runpy.py | 23 +++-- + lib-python/2.7/test/test_site.py | 47 ++++++--- + lib-python/2.7/test/test_support.py | 48 ++++++++-- + lib-python/2.7/test/test_traceback.py | 5 +- + lib-python/2.7/test/test_zipfile.py | 9 +- + lib-python/2.7/test/test_zipimport.py | 9 +- + lib-python/2.7/zipfile.py | 43 ++++++--- + 22 files changed, 499 insertions(+), 165 deletions(-) + +diff --git a/lib-python/2.7/compileall.py b/lib-python/2.7/compileall.py +index 5cfa8be..1418be2 100644 +--- a/lib-python/2.7/compileall.py ++++ b/lib-python/2.7/compileall.py +@@ -11,6 +11,7 @@ packages -- for now, you'll have to deal with packages separately.) + See module py_compile for details of the actual byte-compilation. + """ + import os ++import errno + import sys + import py_compile + import struct +@@ -19,7 +20,7 @@ import imp + __all__ = ["compile_dir","compile_file","compile_path"] + + def compile_dir(dir, maxlevels=10, ddir=None, +- force=0, rx=None, quiet=0): ++ force=False, rx=None, quiet=False, legacy=False): + """Byte-compile all modules in the given directory tree. + + Arguments (only dir is required): +@@ -28,8 +29,9 @@ def compile_dir(dir, maxlevels=10, ddir=None, + maxlevels: maximum recursion level (default 10) + ddir: the directory that will be prepended to the path to the + file as it is compiled into each byte-code file. +- force: if 1, force compilation, even if timestamps are up-to-date +- quiet: if 1, be quiet during compilation ++ force: if True, force compilation, even if timestamps are up-to-date ++ quiet: if True, be quiet during compilation ++ legacy: if True, produce legacy pyc paths instead of PEP 3147 paths + """ + if not quiet: + print 'Listing', dir, '...' +@@ -47,18 +49,20 @@ def compile_dir(dir, maxlevels=10, ddir=None, + else: + dfile = None + if not os.path.isdir(fullname): +- if not compile_file(fullname, ddir, force, rx, quiet): ++ if not compile_file(fullname, ddir, force, rx, quiet, legacy): + success = 0 + elif maxlevels > 0 and \ + name != os.curdir and name != os.pardir and \ + os.path.isdir(fullname) and \ +- not os.path.islink(fullname): ++ not os.path.islink(fullname) and \ ++ name != '__pycache__': + if not compile_dir(fullname, maxlevels - 1, dfile, force, rx, +- quiet): ++ quiet, legacy): + success = 0 + return success + +-def compile_file(fullname, ddir=None, force=0, rx=None, quiet=0): ++def compile_file(fullname, ddir=None, force=0, rx=None, quiet=False, ++ legacy=False): + """Byte-compile one file. + + Arguments (only fullname is required): +@@ -66,8 +70,9 @@ def compile_file(fullname, ddir=None, force=0, rx=None, quiet=0): + fullname: the file to byte-compile + ddir: if given, the directory name compiled in to the + byte-code file. +- force: if 1, force compilation, even if timestamps are up-to-date +- quiet: if 1, be quiet during compilation ++ force: if True, force compilation, even if timestamps are up-to-date ++ quiet: if True, be quiet during compilation ++ legacy: if True, produce legacy pyc paths instead of PEP 3147 paths + """ + success = 1 + name = os.path.basename(fullname) +@@ -82,11 +87,20 @@ def compile_file(fullname, ddir=None, force=0, rx=None, quiet=0): + if os.path.isfile(fullname): + head, tail = name[:-3], name[-3:] + if tail == '.py': ++ if legacy: ++ cfile = fullname + ('c' if __debug__ else 'o') ++ else: ++ cfile = imp.cache_from_source(fullname) ++ cache_dir = os.path.dirname(cfile) ++ try: ++ os.mkdir(cache_dir) ++ except OSError, error: ++ if error.errno != errno.EEXIST: ++ raise + if not force: + try: + mtime = int(os.stat(fullname).st_mtime) + expect = struct.pack('<4sl', imp.get_magic(), mtime) +- cfile = fullname + (__debug__ and 'c' or 'o') + with open(cfile, 'rb') as chandle: + actual = chandle.read(8) + if expect == actual: +@@ -96,7 +110,7 @@ def compile_file(fullname, ddir=None, force=0, rx=None, quiet=0): + if not quiet: + print 'Compiling', fullname, '...' + try: +- ok = py_compile.compile(fullname, None, dfile, True) ++ ok = py_compile.compile(fullname, cfile, dfile, True) + except py_compile.PyCompileError,err: + if quiet: + print 'Compiling', fullname, '...' +@@ -110,15 +124,17 @@ def compile_file(fullname, ddir=None, force=0, rx=None, quiet=0): + success = 0 + return success + +-def compile_path(skip_curdir=1, maxlevels=0, force=0, quiet=0): ++def compile_path(skip_curdir=1, maxlevels=0, force=False, quiet=False, ++ legacy=False): + """Byte-compile all module on sys.path. + + Arguments (all optional): + + skip_curdir: if true, skip current directory (default true) + maxlevels: max recursion level (default 0) +- force: as for compile_dir() (default 0) +- quiet: as for compile_dir() (default 0) ++ force: as for compile_dir() (default False) ++ quiet: as for compile_dir() (default False) ++ legacy: as for compile_dir() (default False) + """ + success = 1 + for dir in sys.path: +@@ -126,7 +142,8 @@ def compile_path(skip_curdir=1, maxlevels=0, force=0, quiet=0): + print 'Skipping current directory' + else: + success = success and compile_dir(dir, maxlevels, None, +- force, quiet=quiet) ++ force, quiet=quiet, ++ legacy=legacy) + return success + + def expand_args(args, flist): +@@ -152,7 +169,7 @@ def main(): + """Script main program.""" + import getopt + try: +- opts, args = getopt.getopt(sys.argv[1:], 'lfqd:x:i:') ++ opts, args = getopt.getopt(sys.argv[1:], 'lfqd:x:i:b') + except getopt.error, msg: + print msg + print "usage: python compileall.py [-l] [-f] [-q] [-d destdir] " \ +@@ -177,23 +194,26 @@ def main(): + print "-i file: add all the files and directories listed in file to " \ + "the list considered for" + print ' compilation; if "-", names are read from stdin' ++ print "-b: Produce legacy byte-compile file paths" + + sys.exit(2) + maxlevels = 10 + ddir = None +- force = 0 +- quiet = 0 ++ force = False ++ quiet = False + rx = None + flist = None ++ legacy = False + for o, a in opts: + if o == '-l': maxlevels = 0 + if o == '-d': ddir = a +- if o == '-f': force = 1 +- if o == '-q': quiet = 1 ++ if o == '-f': force = True ++ if o == '-q': quiet = True + if o == '-x': + import re + rx = re.compile(a) + if o == '-i': flist = a ++ if o == '-b': legacy = True + if ddir: + if len(args) != 1 and not os.path.isdir(args[0]): + print "-d destdir require exactly one directory argument" +@@ -210,13 +230,14 @@ def main(): + for arg in args: + if os.path.isdir(arg): + if not compile_dir(arg, maxlevels, ddir, +- force, rx, quiet): ++ force, rx, quiet, legacy): + success = 0 + else: +- if not compile_file(arg, ddir, force, rx, quiet): ++ if not compile_file(arg, ddir, force, rx, ++ quiet, legacy): + success = 0 + else: +- success = compile_path() ++ success = compile_path(legacy=legacy) + except KeyboardInterrupt: + print "\n[interrupted]" + success = 0 +diff --git a/lib-python/2.7/inspect.py b/lib-python/2.7/inspect.py +index 4335258..32d3ba3 100644 +--- a/lib-python/2.7/inspect.py ++++ b/lib-python/2.7/inspect.py +@@ -56,6 +56,7 @@ def ismodule(object): + """Return true if the object is a module. + + Module objects provide these attributes: ++ __cached__ pathname to byte compiled file + __doc__ documentation string + __file__ filename (missing for built-in modules)""" + return isinstance(object, types.ModuleType) +diff --git a/lib-python/2.7/py_compile.py b/lib-python/2.7/py_compile.py +index 8334ed9..9d0ad16 100644 +--- a/lib-python/2.7/py_compile.py ++++ b/lib-python/2.7/py_compile.py +@@ -4,6 +4,7 @@ This module has intimate knowledge of the format of .pyc files. + """ + + import __builtin__ ++import errno + import imp + import marshal + import os +@@ -71,20 +72,18 @@ def wr_long(f, x): + def compile(file, cfile=None, dfile=None, doraise=False): + """Byte-compile one Python source file to Python bytecode. + +- Arguments: +- +- file: source filename +- cfile: target filename; defaults to source with 'c' or 'o' appended +- ('c' normally, 'o' in optimizing mode, giving .pyc or .pyo) +- dfile: purported filename; defaults to source (this is the filename +- that will show up in error messages) +- doraise: flag indicating whether or not an exception should be +- raised when a compile error is found. If an exception +- occurs and this flag is set to False, a string +- indicating the nature of the exception will be printed, +- and the function will return to the caller. If an +- exception occurs and this flag is set to True, a +- PyCompileError exception will be raised. ++ :param file: The source file name. ++ :param cfile: The target byte compiled file name. When not given, this ++ defaults to the PEP 3147 location. ++ :param dfile: Purported file name, i.e. the file name that shows up in ++ error messages. Defaults to the source file name. ++ :param doraise: Flag indicating whether or not an exception should be ++ raised when a compile error is found. If an exception occurs and this ++ flag is set to False, a string indicating the nature of the exception ++ will be printed, and the function will return to the caller. If an ++ exception occurs and this flag is set to True, a PyCompileError ++ exception will be raised. ++ :return: Path to the resulting byte compiled file. + + Note that it isn't necessary to byte-compile Python modules for + execution efficiency -- Python itself byte-compiles a module when +@@ -119,7 +118,12 @@ def compile(file, cfile=None, dfile=None, doraise=False): + sys.stderr.write(py_exc.msg + '\n') + return + if cfile is None: +- cfile = file + (__debug__ and 'c' or 'o') ++ cfile = imp.cache_from_source(file) ++ try: ++ os.mkdir(os.path.dirname(cfile)) ++ except OSError, error: ++ if error.errno != errno.EEXIST: ++ raise + with open(cfile, 'wb') as fc: + fc.write('\0\0\0\0') + wr_long(fc, timestamp) +@@ -127,6 +131,7 @@ def compile(file, cfile=None, dfile=None, doraise=False): + fc.flush() + fc.seek(0, 0) + fc.write(MAGIC) ++ return cfile + + def main(args=None): + """Compile several source files. +diff --git a/lib-python/2.7/pydoc.py b/lib-python/2.7/pydoc.py +index de9ce1c..14ff9bb 100755 +--- a/lib-python/2.7/pydoc.py ++++ b/lib-python/2.7/pydoc.py +@@ -162,7 +162,8 @@ def visiblename(name, all=None, obj=None): + """Decide whether to show documentation on a variable.""" + # Certain special names are redundant. + _hidden_names = ('__builtins__', '__doc__', '__file__', '__path__', +- '__module__', '__name__', '__slots__', '__package__') ++ '__module__', '__name__', '__slots__', '__package__', ++ '__cached__') + if name in _hidden_names: return 0 + # Private names are hidden, but special names are displayed. + if name.startswith('__') and name.endswith('__'): return 1 +diff --git a/lib-python/2.7/runpy.py b/lib-python/2.7/runpy.py +index ad4d077..9c436bb 100644 +--- a/lib-python/2.7/runpy.py ++++ b/lib-python/2.7/runpy.py +@@ -67,6 +67,7 @@ def _run_code(code, run_globals, init_globals=None, + run_globals.update(init_globals) + run_globals.update(__name__ = mod_name, + __file__ = mod_fname, ++ __cached__ = None, + __loader__ = mod_loader, + __package__ = pkg_name) + exec code in run_globals +@@ -154,6 +155,7 @@ def _run_module_as_main(mod_name, alter_argv=True): + At the very least, these variables in __main__ will be overwritten: + __name__ + __file__ ++ __cached__ + __loader__ + __package__ + """ +diff --git a/lib-python/2.7/site.py b/lib-python/2.7/site.py +index 1a42691..37de98e 100644 +--- a/lib-python/2.7/site.py ++++ b/lib-python/2.7/site.py +@@ -85,8 +85,8 @@ def makepath(*paths): + return dir, os.path.normcase(dir) + + +-def abs__file__(): +- """Set all module' __file__ attribute to an absolute path""" ++def abs_paths(): ++ """Set all module __file__ and __cached__ attributes to an absolute path""" + for m in sys.modules.values(): + if hasattr(m, '__loader__'): + continue # don't mess with a PEP 302-supplied __file__ +@@ -97,6 +97,13 @@ def abs__file__(): + m.__file__ = new + except (AttributeError, OSError): + pass ++ try: ++ prev = m.__cached__ ++ new = os.path.abspath(m.__cached__) ++ if prev != new: ++ m.__cached__ = new ++ except (AttributeError, OSError): ++ pass + + + def removeduppaths(): +@@ -543,7 +550,7 @@ def main(): + global ENABLE_USER_SITE + + import_builtin_stuff() +- abs__file__() ++ abs_paths() + known_paths = removeduppaths() + if ENABLE_USER_SITE is None: + ENABLE_USER_SITE = check_enableusersite() +diff --git a/lib-python/2.7/test/script_helper.py b/lib-python/2.7/test/script_helper.py +index 6be47bd..28a73dd 100644 +--- a/lib-python/2.7/test/script_helper.py ++++ b/lib-python/2.7/test/script_helper.py +@@ -20,6 +20,9 @@ except ImportError: + + from test.test_support import strip_python_stderr + ++from imp import source_from_cache ++from test.test_support import make_legacy_pyc ++ + # Executing the interpreter in a subprocess + def _assert_python(expected_success, *args, **env_vars): + cmd_line = [sys.executable] +@@ -111,20 +114,18 @@ def make_script(script_dir, script_basename, source): + script_file.close() + return script_name + +-def compile_script(script_name): +- py_compile.compile(script_name, doraise=True) +- if __debug__: +- compiled_name = script_name + 'c' +- else: +- compiled_name = script_name + 'o' +- return compiled_name +- + def make_zip_script(zip_dir, zip_basename, script_name, name_in_zip=None): + zip_filename = zip_basename+os.extsep+'zip' + zip_name = os.path.join(zip_dir, zip_filename) + zip_file = zipfile.ZipFile(zip_name, 'w') + if name_in_zip is None: +- name_in_zip = os.path.basename(script_name) ++ parts = script_name.split(os.sep) ++ if len(parts) >= 2 and parts[-2] == '__pycache__': ++ legacy_pyc = make_legacy_pyc(source_from_cache(script_name)) ++ name_in_zip = os.path.basename(legacy_pyc) ++ script_name = legacy_pyc ++ else: ++ name_in_zip = os.path.basename(script_name) + zip_file.write(script_name, name_in_zip) + zip_file.close() + #if test.test_support.verbose: +@@ -147,8 +148,8 @@ def make_zip_pkg(zip_dir, zip_basename, pkg_name, script_basename, + script_name = make_script(zip_dir, script_basename, source) + unlink.append(script_name) + if compiled: +- init_name = compile_script(init_name) +- script_name = compile_script(script_name) ++ init_name = py_compile(init_name, doraise=True) ++ script_name = py_compile(script_name, doraise=True) + unlink.extend((init_name, script_name)) + pkg_names = [os.sep.join([pkg_name]*i) for i in range(1, depth+1)] + script_name_in_zip = os.path.join(pkg_names[-1], os.path.basename(script_name)) +diff --git a/lib-python/2.7/test/test_cmd_line_script.py b/lib-python/2.7/test/test_cmd_line_script.py +index 2e12ff2..5895285 100644 +--- a/lib-python/2.7/test/test_cmd_line_script.py ++++ b/lib-python/2.7/test/test_cmd_line_script.py +@@ -4,9 +4,10 @@ import contextlib + import unittest + import os + import os.path ++import py_compile + import test.test_support + from test.script_helper import (run_python, +- temp_dir, make_script, compile_script, ++ temp_dir, make_script, + assert_python_failure, make_pkg, + make_zip_script, make_zip_pkg) + +@@ -33,6 +34,7 @@ assertEqual(result, ['Top level assignment', 'Lower level reference']) + # Check population of magic variables + assertEqual(__name__, '__main__') + print '__file__==%r' % __file__ ++assertEqual(__cached__, None) + print '__package__==%r' % __package__ + # Check the sys module + import sys +@@ -106,7 +108,7 @@ class CmdLineTest(unittest.TestCase): + def test_script_compiled(self): + with temp_dir() as script_dir: + script_name = _make_test_script(script_dir, 'script') +- compiled_name = compile_script(script_name) ++ compiled_name = py_compile.compile(script_name, doraise=True) + os.remove(script_name) + self._check_script(compiled_name, compiled_name, compiled_name, None) + +@@ -120,9 +122,10 @@ class CmdLineTest(unittest.TestCase): + raise unittest.SkipTest("pypy won't load lone .pyc files") + with temp_dir() as script_dir: + script_name = _make_test_script(script_dir, '__main__') +- compiled_name = compile_script(script_name) ++ compiled_name = py_compile.compile(script_name, doraise=True) + os.remove(script_name) +- self._check_script(script_dir, compiled_name, script_dir, '') ++ pyc_file = test.test_support.make_legacy_pyc(script_name) ++ self._check_script(script_dir, pyc_file, script_dir, '') + + def test_directory_error(self): + with temp_dir() as script_dir: +@@ -138,7 +141,7 @@ class CmdLineTest(unittest.TestCase): + def test_zipfile_compiled(self): + with temp_dir() as script_dir: + script_name = _make_test_script(script_dir, '__main__') +- compiled_name = compile_script(script_name) ++ compiled_name = py_compile.compile(script_name, doraise=True) + zip_name, run_name = make_zip_script(script_dir, 'test_zip', compiled_name) + self._check_script(zip_name, run_name, zip_name, '') + +@@ -185,11 +188,12 @@ class CmdLineTest(unittest.TestCase): + pkg_dir = os.path.join(script_dir, 'test_pkg') + make_pkg(pkg_dir) + script_name = _make_test_script(pkg_dir, '__main__') +- compiled_name = compile_script(script_name) ++ compiled_name = py_compile.compile(script_name, doraise=True) + os.remove(script_name) ++ pyc_file = test.test_support.make_legacy_pyc(script_name) + launch_name = _make_launch_script(script_dir, 'launch', 'test_pkg') +- self._check_script(launch_name, compiled_name, +- compiled_name, 'test_pkg') ++ self._check_script(launch_name, pyc_file, ++ pyc_file, 'test_pkg') + + def test_package_error(self): + with temp_dir() as script_dir: +diff --git a/lib-python/2.7/test/test_compileall.py b/lib-python/2.7/test/test_compileall.py +index d3a26db..7fd44c5 100644 +--- a/lib-python/2.7/test/test_compileall.py ++++ b/lib-python/2.7/test/test_compileall.py +@@ -4,6 +4,8 @@ import os + import py_compile + import shutil + import struct ++import sys ++import subprocess + import tempfile + from test import test_support + import unittest +@@ -14,11 +16,11 @@ class CompileallTests(unittest.TestCase): + def setUp(self): + self.directory = tempfile.mkdtemp() + self.source_path = os.path.join(self.directory, '_test.py') +- self.bc_path = self.source_path + ('c' if __debug__ else 'o') ++ self.bc_path = imp.cache_from_source(self.source_path) + with open(self.source_path, 'w') as file: + file.write('x = 123\n') + self.source_path2 = os.path.join(self.directory, '_test2.py') +- self.bc_path2 = self.source_path2 + ('c' if __debug__ else 'o') ++ self.bc_path2 = imp.cache_from_source(self.source_path2) + shutil.copyfile(self.source_path, self.source_path2) + + def tearDown(self): +@@ -71,8 +73,61 @@ class CompileallTests(unittest.TestCase): + os.unlink(self.bc_path) + os.unlink(self.bc_path2) + ++class CommandLineTests(unittest.TestCase): ++ """Test some aspects of compileall's CLI.""" ++ ++ def setUp(self): ++ self.addCleanup(self._cleanup) ++ self.directory = tempfile.mkdtemp() ++ self.pkgdir = os.path.join(self.directory, 'foo') ++ os.mkdir(self.pkgdir) ++ # Touch the __init__.py and a package module. ++ with open(os.path.join(self.pkgdir, '__init__.py'), 'w'): ++ pass ++ with open(os.path.join(self.pkgdir, 'bar.py'), 'w'): ++ pass ++ sys.path.insert(0, self.directory) ++ ++ def _cleanup(self): ++ test_support.rmtree(self.directory) ++ assert sys.path[0] == self.directory, 'Missing path' ++ del sys.path[0] ++ ++ def test_pep3147_paths(self): ++ # Ensure that the default behavior of compileall's CLI is to create ++ # PEP 3147 pyc/pyo files. ++ retcode = subprocess.call( ++ (sys.executable, '-m', 'compileall', '-q', self.pkgdir)) ++ self.assertEqual(retcode, 0) ++ # Verify the __pycache__ directory contents. ++ cachedir = os.path.join(self.pkgdir, '__pycache__') ++ self.assertTrue(os.path.exists(cachedir)) ++ ext = ('pyc' if __debug__ else 'pyo') ++ expected = sorted(base.format(imp.get_tag(), ext) for base in ++ ('__init__.{}.{}', 'bar.{}.{}')) ++ self.assertEqual(sorted(os.listdir(cachedir)), expected) ++ # Make sure there are no .pyc files in the source directory. ++ self.assertFalse([pyc_file for pyc_file in os.listdir(self.pkgdir) ++ if pyc_file.endswith(ext)]) ++ ++ def test_legacy_paths(self): ++ # Ensure that with the proper switch, compileall leaves legacy ++ # pyc/pyo files, and no __pycache__ directory. ++ retcode = subprocess.call( ++ (sys.executable, '-m', 'compileall', '-b', '-q', self.pkgdir)) ++ self.assertEqual(retcode, 0) ++ # Verify the __pycache__ directory contents. ++ cachedir = os.path.join(self.pkgdir, '__pycache__') ++ self.assertFalse(os.path.exists(cachedir)) ++ ext = ('pyc' if __debug__ else 'pyo') ++ expected = [base.format(ext) for base in ('__init__.{}', 'bar.{}')] ++ expected.extend(['__init__.py', 'bar.py']) ++ expected.sort() ++ self.assertEqual(sorted(os.listdir(self.pkgdir)), expected) ++ ++ + def test_main(): +- test_support.run_unittest(CompileallTests) ++ test_support.run_unittest(CommandLineTests, CompileallTests) + + + if __name__ == "__main__": +diff --git a/lib-python/2.7/test/test_imp.py b/lib-python/2.7/test/test_imp.py +index 1bdc47a..341d36b 100644 +--- a/lib-python/2.7/test/test_imp.py ++++ b/lib-python/2.7/test/test_imp.py +@@ -1,4 +1,7 @@ + import imp ++import os ++import shutil ++import sys + import unittest + from test import test_support + +@@ -70,8 +73,147 @@ class ReloadTests(unittest.TestCase): + imp.reload(marshal) + + ++class PEP3147Tests(unittest.TestCase): ++ """Tests of PEP 3147.""" ++ ++ tag = imp.get_tag() ++ ++ def test_cache_from_source(self): ++ # Given the path to a .py file, return the path to its PEP 3147 ++ # defined .pyc file (i.e. under __pycache__). ++ self.assertEqual( ++ imp.cache_from_source('/foo/bar/baz/qux.py', True), ++ '/foo/bar/baz/__pycache__/qux.{}.pyc'.format(self.tag)) ++ ++ def test_cache_from_source_optimized(self): ++ # Given the path to a .py file, return the path to its PEP 3147 ++ # defined .pyo file (i.e. under __pycache__). ++ if test_support.check_impl_detail(pypy=True): ++ # PyPy doesn't support .pyo, so we expect .pyc ++ extension = 'pyc' ++ else: ++ extension = 'pyo' ++ self.assertEqual( ++ imp.cache_from_source('/foo/bar/baz/qux.py', False), ++ '/foo/bar/baz/__pycache__/qux.{}.{}'.format(self.tag, extension)) ++ ++ def test_cache_from_source_cwd(self): ++ self.assertEqual(imp.cache_from_source('foo.py', True), ++ os.sep.join(('__pycache__', ++ 'foo.{}.pyc'.format(self.tag)))) ++ ++ def test_cache_from_source_override(self): ++ # When debug_override is not None, it can be any true-ish or false-ish ++ # value. ++ if test_support.check_impl_detail(pypy=True): ++ # PyPy doesn't support .pyo, so we expect .pyc ++ extension = 'pyc' ++ else: ++ extension = 'pyo' ++ self.assertEqual( ++ imp.cache_from_source('/foo/bar/baz.py', []), ++ '/foo/bar/__pycache__/baz.{}.pyc'.format(self.tag)) ++ self.assertEqual( ++ imp.cache_from_source('/foo/bar/baz.py', [17]), ++ '/foo/bar/__pycache__/baz.{}.{}'.format(self.tag, extension)) ++ # However if the bool-ishness can't be determined, the exception ++ # propagates. ++ class Bearish: ++ def __bool__(self): raise RuntimeError ++ ++ if test_support.check_impl_detail(pypy=True): ++ # Pypy doesn't even determine bool-ishness ++ try: ++ imp.cache_from_source('/foo/bar/baz.py', Bearish()) ++ except RuntimeError: ++ pass ++ else: ++ self.assertRaises( ++ RuntimeError, ++ imp.cache_from_source, '/foo/bar/baz.py', Bearish()) ++ ++ @unittest.skipIf(os.altsep is None, ++ 'test meaningful only where os.altsep is defined') ++ def test_altsep_cache_from_source(self): ++ # Windows path and PEP 3147. ++ self.assertEqual( ++ imp.cache_from_source('\\foo\\bar\\baz\\qux.py', True), ++ '\\foo\\bar\\baz\\__pycache__\\qux.{}.pyc'.format(self.tag)) ++ ++ @unittest.skipIf(os.altsep is None, ++ 'test meaningful only where os.altsep is defined') ++ def test_altsep_and_sep_cache_from_source(self): ++ # Windows path and PEP 3147 where altsep is right of sep. ++ self.assertEqual( ++ imp.cache_from_source('\\foo\\bar/baz\\qux.py', True), ++ '\\foo\\bar/baz\\__pycache__\\qux.{}.pyc'.format(self.tag)) ++ ++ @unittest.skipIf(os.altsep is None, ++ 'test meaningful only where os.altsep is defined') ++ def test_sep_altsep_and_sep_cache_from_source(self): ++ # Windows path and PEP 3147 where sep is right of altsep. ++ self.assertEqual( ++ imp.cache_from_source('\\foo\\bar\\baz/qux.py', True), ++ '\\foo\\bar\\baz/__pycache__/qux.{}.pyc'.format(self.tag)) ++ ++ def test_source_from_cache(self): ++ # Given the path to a PEP 3147 defined .pyc file, return the path to ++ # its source. This tests the good path. ++ self.assertEqual(imp.source_from_cache( ++ '/foo/bar/baz/__pycache__/qux.{}.pyc'.format(self.tag)), ++ '/foo/bar/baz/qux.py') ++ ++ def test_source_from_cache_bad_path(self): ++ # When the path to a pyc file is not in PEP 3147 format, a ValueError ++ # is raised. ++ self.assertRaises( ++ ValueError, imp.source_from_cache, '/foo/bar/bazqux.pyc') ++ ++ def test_source_from_cache_no_slash(self): ++ # No slashes at all in path -> ValueError ++ self.assertRaises( ++ ValueError, imp.source_from_cache, 'foo.cpython-32.pyc') ++ ++ def test_source_from_cache_too_few_dots(self): ++ # Too few dots in final path component -> ValueError ++ self.assertRaises( ++ ValueError, imp.source_from_cache, '__pycache__/foo.pyc') ++ ++ def test_source_from_cache_too_many_dots(self): ++ # Too many dots in final path component -> ValueError ++ self.assertRaises( ++ ValueError, imp.source_from_cache, ++ '__pycache__/foo.cpython-32.foo.pyc') ++ ++ def test_source_from_cache_no__pycache__(self): ++ # Another problem with the path -> ValueError ++ self.assertRaises( ++ ValueError, imp.source_from_cache, ++ '/foo/bar/foo.cpython-32.foo.pyc') ++ ++ def test_package___file__(self): ++ # Test that a package's __file__ points to the right source directory. ++ os.mkdir('pep3147') ++ sys.path.insert(0, os.curdir) ++ def cleanup(): ++ if sys.path[0] == os.curdir: ++ del sys.path[0] ++ shutil.rmtree('pep3147') ++ self.addCleanup(cleanup) ++ # Touch the __init__.py file. ++ with open('pep3147/__init__.py', 'w'): ++ pass ++ m = __import__('pep3147') ++ # Ensure we load the pyc file. ++ test_support.forget('pep3147') ++ m = __import__('pep3147') ++ self.assertEqual(m.__file__, ++ os.sep.join(('.', 'pep3147', '__init__.py'))) ++ ++ + def test_main(): + tests = [ ++ PEP3147Tests, + ReloadTests, + LockTests, + ] +diff --git a/lib-python/2.7/test/test_import.py b/lib-python/2.7/test/test_import.py +index 716f8e0..0618068 100644 +--- a/lib-python/2.7/test/test_import.py ++++ b/lib-python/2.7/test/test_import.py +@@ -13,7 +13,8 @@ import shutil + + from test.test_support import (unlink, TESTFN, unload, run_unittest, rmtree, + is_jython, check_warnings, EnvironmentVarGuard, +- impl_detail, check_impl_detail) ++ impl_detail, check_impl_detail, forget, ++ make_legacy_pyc, temp_umask) + from test import symlink_support + from test import script_helper + +@@ -35,6 +36,11 @@ def chmod_files(name): + def remove_files(name): + for f in _files(name): + unlink(f) ++ try: ++ shutil.rmtree('__pycache__') ++ except OSError, error: ++ if error.errno != errno.ENOENT: ++ raise + + + class ImportTests(unittest.TestCase): +@@ -95,9 +101,9 @@ class ImportTests(unittest.TestCase): + except ImportError, err: + self.fail("import from .pyc/.pyo failed: %s" % err) + finally: ++ forget(TESTFN) + unlink(pyc) + unlink(pyo) +- unload(TESTFN) + + sys.path.insert(0, os.curdir) + try: +@@ -115,28 +121,26 @@ class ImportTests(unittest.TestCase): + def test_execute_bit_not_copied(self): + # Issue 6070: under posix .pyc files got their execute bit set if + # the .py file had the execute bit set, but they aren't executable. +- oldmask = os.umask(022) +- sys.path.insert(0, os.curdir) +- try: +- fname = TESTFN + os.extsep + "py" +- f = open(fname, 'w').close() +- os.chmod(fname, (stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH | +- stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)) +- __import__(TESTFN) +- fn = fname + 'c' +- if not os.path.exists(fn): +- fn = fname + 'o' ++ with temp_umask(022): ++ sys.path.insert(0, os.curdir) ++ try: ++ fname = TESTFN + os.extsep + "py" ++ f = open(fname, 'w').close() ++ os.chmod(fname, (stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH | ++ stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)) ++ __import__(TESTFN) ++ fn = imp.cache_from_source(fname) + if not os.path.exists(fn): + self.fail("__import__ did not result in creation of " + "either a .pyc or .pyo file") +- s = os.stat(fn) +- self.assertEqual(stat.S_IMODE(s.st_mode), +- stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH) +- finally: +- os.umask(oldmask) +- remove_files(TESTFN) +- unload(TESTFN) +- del sys.path[0] ++ s = os.stat(fn) ++ self.assertEqual( ++ stat.S_IMODE(s.st_mode), ++ stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH) ++ finally: ++ del sys.path[0] ++ remove_files(TESTFN) ++ unload(TESTFN) + + @unittest.skipIf(sys.dont_write_bytecode, + "test meaningful only when writing bytecode") +@@ -205,12 +209,14 @@ class ImportTests(unittest.TestCase): + f.write('"",\n') + f.write(']') + +- # Compile & remove .py file, we only need .pyc (or .pyo). ++ # Compile & remove .py file, we only need .pyc (or .pyo), but that ++ # must be relocated to the PEP 3147 bytecode-only location. + with open(filename, 'r') as f: + py_compile.compile(filename) + if check_impl_detail(pypy=False): + # pypy refuses to import a .pyc if the .py does not exist + unlink(filename) ++ make_legacy_pyc(filename) + + # Need to be able to load from current dir. + sys.path.append('') +@@ -345,7 +351,7 @@ class ImportTests(unittest.TestCase): + sys.path.insert(0, os.curdir) + try: + source = TESTFN + ".py" +- compiled = source + ('c' if __debug__ else 'o') ++ compiled = imp.cache_from_source(source) + with open(source, 'w') as f: + pass + try: +@@ -440,6 +446,7 @@ class PycRewritingTests(unittest.TestCase): + import sys + code_filename = sys._getframe().f_code.co_filename + module_filename = __file__ ++module_pyc_filename = __cached__ + constant = 1 + def func(): + pass +@@ -447,7 +454,7 @@ func_filename = func.func_code.co_filename + """ + dir_name = os.path.abspath(TESTFN) + file_name = os.path.join(dir_name, module_name) + os.extsep + "py" +- compiled_name = file_name + ("c" if __debug__ else "o") ++ compiled_name = imp.cache_from_source(file_name) + + def setUp(self): + self.sys_path = sys.path[:] +@@ -475,19 +482,22 @@ func_filename = func.func_code.co_filename + def test_basics(self): + mod = self.import_module() + self.assertEqual(mod.module_filename, self.file_name) ++ self.assertEqual(mod.module_pyc_filename, self.compiled_name) + self.assertEqual(mod.code_filename, self.file_name) + self.assertEqual(mod.func_filename, self.file_name) + del sys.modules[self.module_name] + mod = self.import_module() ++ self.assertEqual(mod.module_filename, self.file_name) + if not sys.dont_write_bytecode: +- self.assertEqual(mod.module_filename, self.compiled_name) ++ self.assertEqual(mod.module_pyc_filename, self.compiled_name) + self.assertEqual(mod.code_filename, self.file_name) + self.assertEqual(mod.func_filename, self.file_name) + + def test_incorrect_code_name(self): + py_compile.compile(self.file_name, dfile="another_module.py") + mod = self.import_module() +- self.assertEqual(mod.module_filename, self.compiled_name) ++ self.assertEqual(mod.module_filename, self.file_name) ++ self.assertEqual(mod.module_pyc_filename, self.compiled_name) + self.assertEqual(mod.code_filename, self.file_name) + self.assertEqual(mod.func_filename, self.file_name) + +@@ -496,8 +506,9 @@ func_filename = func.func_code.co_filename + target = "another_module.py" + py_compile.compile(self.file_name, dfile=target) + os.remove(self.file_name) ++ pyc_file = make_legacy_pyc(self.file_name) + mod = self.import_module() +- self.assertEqual(mod.module_filename, self.compiled_name) ++ self.assertEqual(mod.module_filename, pyc_file) + self.assertEqual(mod.code_filename, target) + self.assertEqual(mod.func_filename, target) + +diff --git a/lib-python/2.7/test/test_pkg.py b/lib-python/2.7/test/test_pkg.py +index 5f1659b..853069a 100644 +--- a/lib-python/2.7/test/test_pkg.py ++++ b/lib-python/2.7/test/test_pkg.py +@@ -194,14 +194,14 @@ class Test(unittest.TestCase): + + import t5 + self.assertEqual(fixdir(dir(t5)), +- ['__doc__', '__file__', '__name__', ++ ['__cached__', '__doc__', '__file__', '__name__', + '__package__', '__path__', 'foo', 'string', 't5']) + self.assertEqual(fixdir(dir(t5.foo)), +- ['__doc__', '__file__', '__name__', '__package__', +- 'string']) ++ ['__cached__', '__doc__', '__file__', '__name__', ++ '__package__', 'string']) + self.assertEqual(fixdir(dir(t5.string)), +- ['__doc__', '__file__', '__name__','__package__', +- 'spam']) ++ ['__cached__', '__doc__', '__file__', '__name__', ++ '__package__', 'spam']) + + def test_6(self): + hier = [ +@@ -216,13 +216,13 @@ class Test(unittest.TestCase): + + import t6 + self.assertEqual(fixdir(dir(t6)), +- ['__all__', '__doc__', '__file__', ++ ['__all__', '__cached__', '__doc__', '__file__', + '__name__', '__package__', '__path__']) + s = """ + import t6 + from t6 import * + self.assertEqual(fixdir(dir(t6)), +- ['__all__', '__doc__', '__file__', ++ ['__all__', '__cached__', '__doc__', '__file__', + '__name__', '__package__', '__path__', + 'eggs', 'ham', 'spam']) + self.assertEqual(dir(), ['eggs', 'ham', 'self', 'spam', 't6']) +@@ -250,18 +250,18 @@ class Test(unittest.TestCase): + t7, sub, subsub = None, None, None + import t7 as tas + self.assertEqual(fixdir(dir(tas)), +- ['__doc__', '__file__', '__name__', ++ ['__cached__', '__doc__', '__file__', '__name__', + '__package__', '__path__']) + self.assertFalse(t7) + from t7 import sub as subpar + self.assertEqual(fixdir(dir(subpar)), +- ['__doc__', '__file__', '__name__', ++ ['__cached__', '__doc__', '__file__', '__name__', + '__package__', '__path__']) + self.assertFalse(t7) + self.assertFalse(sub) + from t7.sub import subsub as subsubsub + self.assertEqual(fixdir(dir(subsubsub)), +- ['__doc__', '__file__', '__name__', ++ ['__cached__', '__doc__', '__file__', '__name__', + '__package__', '__path__', 'spam']) + self.assertFalse(t7) + self.assertFalse(sub) +diff --git a/lib-python/2.7/test/test_pkgimport.py b/lib-python/2.7/test/test_pkgimport.py +index 30d48cd..490060f 100644 +--- a/lib-python/2.7/test/test_pkgimport.py ++++ b/lib-python/2.7/test/test_pkgimport.py +@@ -1,5 +1,6 @@ +-import os, sys, string, random, tempfile, unittest ++import os, sys, shutil, string, random, tempfile, unittest + ++from imp import cache_from_source + from test.test_support import run_unittest + + class TestImport(unittest.TestCase): +@@ -27,22 +28,17 @@ class TestImport(unittest.TestCase): + self.module_path = os.path.join(self.package_dir, 'foo'+os.extsep+'py') + + def tearDown(self): +- for file in os.listdir(self.package_dir): +- os.remove(os.path.join(self.package_dir, file)) +- os.rmdir(self.package_dir) +- os.rmdir(self.test_dir) ++ shutil.rmtree(self.test_dir) + self.assertNotEqual(sys.path.count(self.test_dir), 0) + sys.path.remove(self.test_dir) + self.remove_modules() + + def rewrite_file(self, contents): +- for extension in "co": +- compiled_path = self.module_path + extension +- if os.path.exists(compiled_path): +- os.remove(compiled_path) +- f = open(self.module_path, 'w') +- f.write(contents) +- f.close() ++ compiled_path = cache_from_source(self.module_path) ++ if os.path.exists(compiled_path): ++ os.remove(compiled_path) ++ with open(self.module_path, 'w') as f: ++ f.write(contents) + + def test_package_import__semantics(self): + +diff --git a/lib-python/2.7/test/test_py_compile.py b/lib-python/2.7/test/test_py_compile.py +index 5ec523a..eff87df 100644 +--- a/lib-python/2.7/test/test_py_compile.py ++++ b/lib-python/2.7/test/test_py_compile.py +@@ -12,7 +12,7 @@ class PyCompileTests(unittest.TestCase): + def setUp(self): + self.directory = tempfile.mkdtemp() + self.source_path = os.path.join(self.directory, '_test.py') +- self.pyc_path = self.source_path + 'c' ++ self.pyc_path = imp.cache_from_source(self.source_path) + self.cwd_drive = os.path.splitdrive(os.getcwd())[0] + # In these tests we compute relative paths. When using Windows, the + # current working directory path and the 'self.source_path' might be +@@ -35,9 +35,10 @@ class PyCompileTests(unittest.TestCase): + self.assertTrue(os.path.exists(self.pyc_path)) + + def test_cwd(self): ++ pyc_file = imp.cache_from_source(os.path.basename(self.source_path)) + with support.change_cwd(self.directory): + py_compile.compile(os.path.basename(self.source_path), +- os.path.basename(self.pyc_path)) ++ pyc_file) + self.assertTrue(os.path.exists(self.pyc_path)) + + def test_relative_path(self): +diff --git a/lib-python/2.7/test/test_pydoc.py b/lib-python/2.7/test/test_pydoc.py +index 0e9f5f3..58c5781 100644 +--- a/lib-python/2.7/test/test_pydoc.py ++++ b/lib-python/2.7/test/test_pydoc.py +@@ -6,6 +6,7 @@ import re + import py_compile + import pydoc + import contextlib ++import imp + import inspect + import keyword + import pkgutil +@@ -418,7 +419,7 @@ foo = 1 + def test_synopsis_sourceless_empty_doc(self): + with test.test_support.temp_cwd() as test_dir: + init_path = os.path.join(test_dir, 'foomod42.py') +- cached_path = os.path.join(test_dir, 'foomod42.pyc') ++ cached_path = imp.cache_from_source(init_path) + with open(init_path, 'w') as fobj: + fobj.write("foo = 1") + py_compile.compile(init_path) +diff --git a/lib-python/2.7/test/test_runpy.py b/lib-python/2.7/test/test_runpy.py +index b635c1d..a45f9be 100644 +--- a/lib-python/2.7/test/test_runpy.py ++++ b/lib-python/2.7/test/test_runpy.py +@@ -5,8 +5,9 @@ import os.path + import sys + import re + import tempfile +-from test.test_support import verbose, run_unittest, forget, check_impl_detail +-from test.script_helper import (temp_dir, make_script, compile_script, ++import py_compile ++from test.test_support import verbose, run_unittest, forget, check_impl_detail, make_legacy_pyc ++from test.script_helper import (temp_dir, make_script, + make_pkg, make_zip_script, make_zip_pkg) + + if check_impl_detail(pypy=True): +@@ -50,6 +51,7 @@ class RunModuleCodeTest(unittest.TestCase): + self.assertEqual(d["result"], self.expected_result) + self.assertIs(d["__name__"], None) + self.assertIs(d["__file__"], None) ++ self.assertIs(d["__cached__"], None) + self.assertIs(d["__loader__"], None) + self.assertIs(d["__package__"], None) + self.assertIs(d["run_argv0"], saved_argv0) +@@ -78,6 +80,7 @@ class RunModuleCodeTest(unittest.TestCase): + self.assertTrue(d2["run_name_in_sys_modules"]) + self.assertTrue(d2["module_in_sys_modules"]) + self.assertIs(d2["__file__"], file) ++ self.assertIs(d2["__cached__"], None) + self.assertIs(d2["run_argv0"], file) + self.assertIs(d2["__loader__"], loader) + self.assertIs(d2["__package__"], package) +@@ -177,6 +180,7 @@ class RunModuleTest(unittest.TestCase): + __import__(mod_name) + os.remove(mod_fname) + if not sys.dont_write_bytecode: ++ make_legacy_pyc(mod_fname) + if verbose: print "Running from compiled:", mod_name + d2 = run_module(mod_name) # Read from bytecode + self.assertIn("x", d2) +@@ -201,6 +205,7 @@ class RunModuleTest(unittest.TestCase): + __import__(mod_name) + os.remove(mod_fname) + if not sys.dont_write_bytecode: ++ make_legacy_pyc(mod_fname) + if verbose: print "Running from compiled:", pkg_name + d2 = run_module(pkg_name) # Read from bytecode + self.assertIn("x", d2) +@@ -257,6 +262,7 @@ from ..uncle.cousin import nephew + __import__(mod_name) + os.remove(mod_fname) + if not sys.dont_write_bytecode: ++ make_legacy_pyc(mod_fname) + if verbose: print "Running from compiled:", mod_name + d2 = run_module(mod_name, run_name=run_name) # Read from bytecode + self.assertIn("__package__", d2) +@@ -348,6 +354,7 @@ argv0 = sys.argv[0] + result = run_path(script_name) + self.assertEqual(result["__name__"], expected_name) + self.assertEqual(result["__file__"], expected_file) ++ self.assertEqual(result["__cached__"], None) + self.assertIn("argv0", result) + self.assertEqual(result["argv0"], expected_argv0) + self.assertEqual(result["__package__"], expected_package) +@@ -367,7 +374,7 @@ argv0 = sys.argv[0] + with temp_dir() as script_dir: + mod_name = 'script' + script_name = self._make_test_script(script_dir, mod_name) +- compiled_name = compile_script(script_name) ++ compiled_name = py_compile.compile(script_name, doraise=True) + os.remove(script_name) + self._check_script(compiled_name, "<run_path>", compiled_name, + compiled_name, None) +@@ -385,9 +392,10 @@ argv0 = sys.argv[0] + with temp_dir() as script_dir: + mod_name = '__main__' + script_name = self._make_test_script(script_dir, mod_name) +- compiled_name = compile_script(script_name) ++ compiled_name = py_compile.compile(script_name, doraise=True) + os.remove(script_name) +- self._check_script(script_dir, "<run_path>", compiled_name, ++ legacy_pyc = make_legacy_pyc(script_name) ++ self._check_script(script_dir, "<run_path>", legacy_pyc, + script_dir, '') + + def test_directory_error(self): +@@ -408,8 +416,9 @@ argv0 = sys.argv[0] + with temp_dir() as script_dir: + mod_name = '__main__' + script_name = self._make_test_script(script_dir, mod_name) +- compiled_name = compile_script(script_name) +- zip_name, fname = make_zip_script(script_dir, 'test_zip', compiled_name) ++ compiled_name = py_compile.compile(script_name, doraise=True) ++ zip_name, fname = make_zip_script(script_dir, 'test_zip', ++ compiled_name) + self._check_script(zip_name, "<run_path>", fname, zip_name, '') + + def test_zipfile_error(self): +diff --git a/lib-python/2.7/test/test_site.py b/lib-python/2.7/test/test_site.py +index de3f28b..02331be 100644 +--- a/lib-python/2.7/test/test_site.py ++++ b/lib-python/2.7/test/test_site.py +@@ -318,19 +318,40 @@ class ImportSideEffectTests(unittest.TestCase): + """Restore sys.path""" + sys.path[:] = self.sys_path + +- def test_abs__file__(self): +- # Make sure all imported modules have their __file__ attribute +- # as an absolute path. +- # Handled by abs__file__() +- site.abs__file__() +- for module in (sys, os, __builtin__): +- try: +- self.assertTrue(os.path.isabs(module.__file__), repr(module)) +- except AttributeError: +- continue +- # We could try everything in sys.modules; however, when regrtest.py +- # runs something like test_frozen before test_site, then we will +- # be testing things loaded *after* test_site did path normalization ++ def test_abs_paths(self): ++ # Make sure all imported modules have their __file__ and __cached__ ++ # attributes as absolute paths. Arranging to put the Lib directory on ++ # PYTHONPATH would cause the os module to have a relative path for ++ # __file__ if abs_paths() does not get run. sys and builtins (the ++ # only other modules imported before site.py runs) do not have ++ # __file__ or __cached__ because they are built-in. ++ parent = os.path.relpath(os.path.dirname(os.__file__)) ++ env = os.environ.copy() ++ env['PYTHONPATH'] = parent ++ # We use uuid rather than os, as os isn't modified in pypy ++ # and so not in the same path as test_site ++ command = 'import uuid; print uuid.__file__, uuid.__cached__' ++ # First, prove that with -S (no 'import site'), the paths are ++ # relative. ++ proc = subprocess.Popen([sys.executable, '-S', '-c', command], ++ env=env, ++ stdout=subprocess.PIPE, ++ stderr=subprocess.PIPE) ++ stdout, stderr = proc.communicate() ++ self.assertEqual(proc.returncode, 0) ++ os__file__, os__cached__ = stdout.split() ++ self.assertFalse(os.path.isabs(os__file__)) ++ self.assertFalse(os.path.isabs(os__cached__)) ++ # Now, with 'import site', it works. ++ proc = subprocess.Popen([sys.executable, '-c', command], ++ env=env, ++ stdout=subprocess.PIPE, ++ stderr=subprocess.PIPE) ++ stdout, stderr = proc.communicate() ++ self.assertEqual(proc.returncode, 0) ++ os__file__, os__cached__ = stdout.split() ++ self.assertTrue(os.path.isabs(os__file__)) ++ self.assertTrue(os.path.isabs(os__cached__)) + + def test_no_duplicate_paths(self): + # No duplicate paths should exist in sys.path +diff --git a/lib-python/2.7/test/test_support.py b/lib-python/2.7/test/test_support.py +index 258b339..0e34980 100644 +--- a/lib-python/2.7/test/test_support.py ++++ b/lib-python/2.7/test/test_support.py +@@ -18,6 +18,7 @@ import unittest + import importlib + import UserDict + import re ++import imp + import time + import struct + import sysconfig +@@ -36,7 +37,7 @@ __all__ = ["Error", "TestFailed", "ResourceDenied", "import_module", + "open_urlresource", "check_warnings", "check_py3k_warnings", + "CleanImport", "EnvironmentVarGuard", "captured_output", + "captured_stdout", "TransientResource", "transient_internet", +- "run_with_locale", "set_memlimit", "bigmemtest", "bigaddrspacetest", ++ "run_with_locale", "set_memlimit", "temp_umask", "bigmemtest", "bigaddrspacetest", + "BasicTestRunner", "run_unittest", "run_doctest", "threading_setup", + "threading_cleanup", "reap_threads", "start_threads", "cpython_only", + "check_impl_detail", "get_attribute", "py3k_bytes", +@@ -292,16 +293,37 @@ def rmtree(path): + if e.errno not in (errno.ENOENT, errno.ESRCH): + raise + ++def make_legacy_pyc(source): ++ """Move a PEP 3147 pyc/pyo file to its legacy pyc/pyo location. ++ ++ The choice of .pyc or .pyo extension is done based on the __debug__ flag ++ value. ++ ++ :param source: The file system path to the source file. The source file ++ does not need to exist, however the PEP 3147 pyc file must exist. ++ :return: The file system path to the legacy pyc file. ++ """ ++ pyc_file = imp.cache_from_source(source) ++ up_one = os.path.dirname(os.path.abspath(source)) ++ legacy_pyc = os.path.join(up_one, source + ('c' if __debug__ else 'o')) ++ os.rename(pyc_file, legacy_pyc) ++ return legacy_pyc ++ + def forget(modname): +- '''"Forget" a module was ever imported by removing it from sys.modules and +- deleting any .pyc and .pyo files.''' ++ """'Forget' a module was ever imported. ++ ++ This removes the module from sys.modules and deletes any PEP 3147 or ++ legacy .pyc and .pyo files. ++ """ + unload(modname) + for dirname in sys.path: +- unlink(os.path.join(dirname, modname + os.extsep + 'pyc')) +- # Deleting the .pyo file cannot be within the 'try' for the .pyc since +- # the chance exists that there is no .pyc (and thus the 'try' statement +- # is exited) but there is a .pyo file. +- unlink(os.path.join(dirname, modname + os.extsep + 'pyo')) ++ source = os.path.join(dirname, modname + os.extsep + 'py') ++ # It doesn't matter if they exist or not, unlink all possible ++ # combinations of PEP 3147 and legacy pyc and pyo files. ++ unlink(source + 'c') ++ unlink(source + 'o') ++ unlink(imp.cache_from_source(source, debug_override=True)) ++ unlink(imp.cache_from_source(source, debug_override=False)) + + # Check whether a gui is actually available + def _is_gui_available(): +@@ -765,6 +787,16 @@ def temp_cwd(name='tempcwd', quiet=False): + rmtree(name) + + ++@contextlib.contextmanager ++def temp_umask(umask): ++ """Context manager that temporarily sets the process umask.""" ++ oldmask = os.umask(umask) ++ try: ++ yield ++ finally: ++ os.umask(oldmask) ++ ++ + def findfile(file, here=None, subdir=None): + """Try to find a file on sys.path and the working directory. If it is not + found the argument passed to the function is returned (this does not +diff --git a/lib-python/2.7/test/test_traceback.py b/lib-python/2.7/test/test_traceback.py +index c8ade06..7635579 100644 +--- a/lib-python/2.7/test/test_traceback.py ++++ b/lib-python/2.7/test/test_traceback.py +@@ -1,6 +1,7 @@ + """Test cases for traceback module""" + + from StringIO import StringIO ++import shutil + import sys + import unittest + from imp import reload +@@ -114,9 +115,7 @@ def test(): + self.assertEqual(src, 'raise NotImplementedError') + finally: + sys.path[:] = savedpath +- for f in os.listdir(testdir): +- os.unlink(os.path.join(testdir, f)) +- os.rmdir(testdir) ++ shutil.rmtree(testdir) + + err = self.get_exception_format(self.syntax_error_bad_indentation2, + IndentationError) +diff --git a/lib-python/2.7/test/test_zipfile.py b/lib-python/2.7/test/test_zipfile.py +index 9c63aeb..a084019 100644 +--- a/lib-python/2.7/test/test_zipfile.py ++++ b/lib-python/2.7/test/test_zipfile.py +@@ -6,6 +6,7 @@ except ImportError: + + import os + import io ++import imp + import sys + import time + import struct +@@ -836,7 +837,13 @@ class PyZipFileTests(unittest.TestCase): + with zipfile.PyZipFile(TemporaryFile(), "w") as zipfp: + fn = __file__ + if fn.endswith('.pyc') or fn.endswith('.pyo'): +- fn = fn[:-1] ++ path_split = fn.split(os.sep) ++ if os.altsep is not None: ++ path_split.extend(fn.split(os.altsep)) ++ if '__pycache__' in path_split: ++ fn = imp.source_from_cache(fn) ++ else: ++ fn = fn[:-1] + + zipfp.writepy(fn) + +diff --git a/lib-python/2.7/test/test_zipimport.py b/lib-python/2.7/test/test_zipimport.py +index a66738a..da8c38e 100644 +--- a/lib-python/2.7/test/test_zipimport.py ++++ b/lib-python/2.7/test/test_zipimport.py +@@ -43,17 +43,14 @@ NOW = time.time() + test_pyc = make_pyc(test_co, NOW) + + +-if __debug__: +- pyc_ext = ".pyc" +-else: +- pyc_ext = ".pyo" +- +- + TESTMOD = "ziptestmodule" + TESTPACK = "ziptestpackage" + TESTPACK2 = "ziptestpackage2" + TEMP_ZIP = os.path.abspath("junk95142" + os.extsep + "zip") + ++pyc_file = imp.cache_from_source(TESTMOD + '.py') ++pyc_ext = ('.pyc' if __debug__ else '.pyo') ++ + + class UncompressedZipImportTestCase(ImportHooksBaseTestCase): + +diff --git a/lib-python/2.7/zipfile.py b/lib-python/2.7/zipfile.py +index a16d860..2198048 100644 +--- a/lib-python/2.7/zipfile.py ++++ b/lib-python/2.7/zipfile.py +@@ -3,6 +3,7 @@ Read and write ZIP files. + """ + import struct, os, time, sys, shutil + import binascii, cStringIO, stat ++import imp + import io + import re + import string +@@ -1457,22 +1458,42 @@ class PyZipFile(ZipFile): + file_py = pathname + ".py" + file_pyc = pathname + ".pyc" + file_pyo = pathname + ".pyo" +- if os.path.isfile(file_pyo) and \ +- os.stat(file_pyo).st_mtime >= os.stat(file_py).st_mtime: +- fname = file_pyo # Use .pyo file +- elif not os.path.isfile(file_pyc) or \ +- os.stat(file_pyc).st_mtime < os.stat(file_py).st_mtime: ++ pycache_pyc = imp.cache_from_source(file_py, True) ++ pycache_pyo = imp.cache_from_source(file_py, False) ++ if (os.path.isfile(file_pyo) and ++ os.stat(file_pyo).st_mtime >= os.stat(file_py).st_mtime): ++ # Use .pyo file. ++ arcname = fname = file_pyo ++ elif (os.path.isfile(file_pyc) and ++ os.stat(file_pyc).st_mtime >= os.stat(file_py).st_mtime): ++ # Use .pyc file. ++ arcname = fname = file_pyc ++ elif (os.path.isfile(pycache_pyc) and ++ os.stat(pycache_pyc).st_mtime >= os.stat(file_py).st_mtime): ++ # Use the __pycache__/*.pyc file, but write it to the legacy pyc ++ # file name in the archive. ++ fname = pycache_pyc ++ arcname = file_pyc ++ elif (os.path.isfile(pycache_pyo) and ++ os.stat(pycache_pyo).st_mtime >= os.stat(file_py).st_mtime): ++ # Use the __pycache__/*.pyo file, but write it to the legacy pyo ++ # file name in the archive. ++ fname = pycache_pyo ++ arcname = file_pyo ++ else: ++ # Compile py into PEP 3147 pyc file. + import py_compile + if self.debug: + print "Compiling", file_py + try: +- py_compile.compile(file_py, file_pyc, None, True) +- except py_compile.PyCompileError,err: ++ py_compile.compile(file_py, doraise=True) ++ except py_compile.PyCompileError, error: + print err.msg +- fname = file_pyc +- else: +- fname = file_pyc +- archivename = os.path.split(fname)[1] ++ fname = file_py ++ else: ++ fname = (pycache_pyc if __debug__ else pycache_pyo) ++ arcname = (file_pyc if __debug__ else file_pyo) ++ archivename = os.path.split(arcname)[1] + if basename: + archivename = "%s/%s" % (basename, archivename) + return (fname, archivename) |