[Python-checkins] r52761 - sandbox/trunk/import_in_py/importer.py sandbox/trunk/import_in_py/mock_importer.py sandbox/trunk/import_in_py/test_importer.py

brett.cannon python-checkins at python.org
Thu Nov 16 01:20:04 CET 2006


Author: brett.cannon
Date: Thu Nov 16 01:20:03 2006
New Revision: 52761

Modified:
   sandbox/trunk/import_in_py/importer.py
   sandbox/trunk/import_in_py/mock_importer.py
   sandbox/trunk/import_in_py/test_importer.py
Log:
Finish filling in tests that required ability to read/write longs in
little-endian and fixing code accordingly.


Modified: sandbox/trunk/import_in_py/importer.py
==============================================================================
--- sandbox/trunk/import_in_py/importer.py	(original)
+++ sandbox/trunk/import_in_py/importer.py	Thu Nov 16 01:20:03 2006
@@ -152,8 +152,9 @@
 import imp
 import sys
 import marshal
-# XXX Following imports will eventually need to be removed since they involve
-# Python source.
+# XXX Following imports will eventually need to be removed since they are not
+# built-in modules.
+import errno
 import os
 import contextlib
 import py_compile
@@ -366,22 +367,24 @@
             return module
             
     def mod_time(self, path):
-        """Return the modification time for the specified path."""
-        return os.stat(path).st_mtime
+        """Return the modification time for the specified path as an integer."""
+        return int(os.stat(path).st_mtime)
         
     def split_path(self, path):
         """Split the specified path into a base path and the type of the
         path."""
         return os.path.splitext(path)
         
-    def create_path(self, base_path, type_):
+    def create_path(self, base_path, type_, must_exist=False):
         """Create a new path based on a base path and requested path type.
         
-        If the created path does not exist, return None.
+        If must_exist is True, the path must already exist.
         
         """
         path = base_path + type_
-        return path if os.path.exists(path) else None
+        if must_exist:
+            path = path if os.path.exists(path) else None
+        return path
         
     def read_data(self, path, binary=False):
         """Open the path and return the data read from it in the specified
@@ -392,8 +395,14 @@
         
     def write_data(self, data, path, binary=False):
         """Write data to a specified path as either binary or textual data."""
-        with open(path, 'wb' if binary else 'w') as data_file:
-            data_file.write(data)
+        try:
+            with open(path, 'wb' if binary else 'w') as data_file:
+                data_file.write(data)
+        except IOError, exc:
+            if exc.errno == errno.EACCES:
+                pass
+            else:
+                raise
 
 
 class PyPycHandler(object):
@@ -464,11 +473,12 @@
             Take in an opaque path object and split it into a base path and a
             string representing the type of the path (which should be in the
             'handles' attribute of the handler).
-        * create_path(base_path, type_)
+        * create_path(base_path, type_, must_exist)
             Create an opaque path object from a base path and the type of path
-            that is desired.
+            that is desired.  If must_exist is True the path must already
+            exist.
         * mod_time(path)
-            Return the last modification time for a path.
+            Return the last modification time for a path as an integer.
         * read_data(path, binary)
             Read the data from the specified path.  'binary' is a boolean that
             flags whether the data should be read as binary data or text data.
@@ -478,7 +488,7 @@
         
         """
         source_path = None
-        source_timstamp = None
+        source_timestamp = None
         bytecode_path = None
         module = self.new_module(mod_name)
         # __file__, __path__, and __loader__ *must* be set on the module before
@@ -499,7 +509,7 @@
             magic, pyc_timestamp, bytecode = self.parse_pyc(pyc_data)
             # Try to find corresponding source code.
             for source_handle in self.source_handles:
-                source_path = loader.create_path(base_path, source_handle)
+                source_path = loader.create_path(base_path, source_handle, True)
                 if source_path:
                     break
             try:
@@ -529,14 +539,15 @@
         code = self.code_from_source(source, source_path)
         # See if there is a corresponding path to bytecode.
         if not bytecode_path:
-            for bytecode_handle in self.bytecode_handles:
+            if self.bytecode_handles:
+                bytecode_handle = self.bytecode_handles[0]
                 bytecode_path = loader.create_path(base_path,
-                                                        bytecode_handle)
-                if bytecode_path:
-                    source_timestamp = loader.mod_time(source_path)
-                    break
+                                                    bytecode_handle)
+            source_timestamp = loader.mod_time(source_path)
         # If there is a possible path to bytecode, generate .pyc file.
         if bytecode_path:
+            if not source_timestamp:
+                source_timestamp = loader.mod_time(source_path)
             pyc = self.create_pyc(code, source_timestamp)
             loader.write_data(pyc, bytecode_path, True)
         exec code in module.__dict__

Modified: sandbox/trunk/import_in_py/mock_importer.py
==============================================================================
--- sandbox/trunk/import_in_py/mock_importer.py	(original)
+++ sandbox/trunk/import_in_py/mock_importer.py	Thu Nov 16 01:20:03 2006
@@ -2,6 +2,8 @@
 import marshal
 import imp
 from test import test_support
+# XXX for w_long and r_long
+from importer import w_long, r_long
 
 def log_call(method):
     """Log method calls to self.log."""
@@ -77,14 +79,14 @@
         code_object = compile(self.source, "<mock loader>", 'exec')
         bytecode = marshal.dumps(code_object)
         if good_magic:
-            pyc = str(imp.get_magic())
+            pyc = imp.get_magic()
         else:
-            pyc += str(imp.get_magic()-1)
+            magic = imp.get_magic()
+            pyc = magic[:3] + chr(ord(magic[3]) - 1)
         if good_timestamp:
-            pyc += str(1).zfill(4)
+            pyc += w_long(self.modification_time)
         else:
-            pyc += str(0).zfill(4)
-        # XXX Not proper until can marshal longs.
+            pyc += w_long(self.modification_time - 1)
         # Needed for read_data on .pyc path.
         self.pyc = pyc + bytecode
         self.log = []
@@ -141,13 +143,16 @@
         return path
     
     @log_call
-    def create_path(self, base, type_):
+    def create_path(self, base, type_, must_exist=False):
         """Create a tuple from 'base' and type_."""
         assert base == self.base_path
         assert type_ in (self.py_ext, self.pyc_ext)
 
-        if type_ not in (self.py_ext, self.pyc_ext):
-            return None
+        if must_exist:
+            if type_ not in (self.py_ext, self.pyc_ext):
+                return None
+            else:
+                return (base, type_)
         else:
             return (base, type_)
 
@@ -179,10 +184,9 @@
         assert self.pyc_ext
         assert path[1] == self.pyc_ext, "%s != %s" % (path[1], self.pyc_ext)
         assert binary
-        # XXX Assert proper magic number
-        # XXX Assert time stamp
-        # XXX mock
-        module = imp.new_module(self.module_name)
+        assert data[:4] == imp.get_magic()
+        assert w_long(self.modification_time) == data[4:8]
+        module = MockModule(self.module_name)
         code = marshal.loads(data[8:])
         exec code in module.__dict__
         assert self._verify_module(module, False)

Modified: sandbox/trunk/import_in_py/test_importer.py
==============================================================================
--- sandbox/trunk/import_in_py/test_importer.py	(original)
+++ sandbox/trunk/import_in_py/test_importer.py	Thu Nov 16 01:20:03 2006
@@ -468,6 +468,7 @@
         # Modification time for the passed-in path should match the file.
         true_mod_time = os.stat(self.file_path).st_mtime
         mod_time = self.loader.mod_time(self.file_path)
+        self.failUnless(isinstance(mod_time, (int, long)))
         self.failUnlessEqual(mod_time, true_mod_time)
         
     def test_split_path(self):
@@ -482,6 +483,9 @@
         path = self.loader.create_path(*self.loader.split_path(
                                                         self.file_path))
         self.failUnlessEqual(path, true_path)
+        self.failUnlessEqual(None, self.loader.create_path('sadfasdfd', 'aaa',
+                                                            True))
+        self.failUnlessEqual('ab', self.loader.create_path('a', 'b'))
         
     def test_read_data(self):
         # Should be able to read a file.
@@ -588,29 +592,37 @@
         # Bytecode should not be written.
         self.failUnless("write_data" not in loader.log)
     
-    def XXX_test_bad_magic_no_py(self):
+    def test_bad_magic_no_py(self):
         # ImportError should be raised when a .pyc has a bad magic number and
         # there is no corresponding .py file.
-        pass
+        loader = mock_importer.MockPyPycLoader.setup(good_magic=False,
+                                                        py_exists=False)
+        handler = loader._create_handler(importer.PyPycHandler)
+        self.failUnlessRaises(ImportError, loader._handle_pyc, handler)
         
-    def test_bad_timestamp_no_py(self):
-        # XXX Can't test until can unmarshal timestamp from pyc.
-        pass
-
     def test_bad_bytecode_no_py(self):
-        # XXX
+        # XXX Will bad bytecode lead to an ImportError?
         pass
         
     def test_bad_magic_w_py(self):
-        # XXX Can't test until can unmarhsal magic number from pyc.
-        pass
+        # A .pyc file with a bad magic number should lead to the .py file being
+        # used to generate a new .pyc.
+        loader = mock_importer.MockPyPycLoader.setup(good_magic=False)
+        handler = loader._create_handler(importer.PyPycHandler)
+        module = loader._handle_pyc(handler)
+        loader._verify_module(module)
+        self.failUnless("write_data" in loader.log)
         
-    def test_bad_magic_w_py(self):
-        # XXX Can't test until can unmarshal timestamp from pyc.
-        pass
+    def test_bad_timestamp_w_py(self):
+        # A .pyc file with a outdated timestamp should be regenerated.
+        loader = mock_importer.MockPyPycLoader.setup(good_timestamp=False)
+        handler = loader._create_handler(importer.PyPycHandler)
+        module = loader._handle_pyc(handler)
+        loader._verify_module(module)
+        self.failUnless("write_data" in loader.log)
 
     def test_bad_bytecode_w_py(self):
-        # XXX
+        # XXX Will the bytecode be recreated?
         pass
         
     def test_py_no_pyc(self):
@@ -1079,7 +1091,18 @@
         # Importing a .py file should work and generate a .pyc file.
         os.remove(self.pyc_path)
         module = self.import_(self.module_name)
-        # XXX Cannot fully test creation of bytecode files yet.
+        self.verify_module(module)
+        self.failUnless(os.path.exists(self.pyc_path))
+        with open(self.pyc_path, 'rb') as pyc_file:
+            data = pyc_file.read()
+        self.failUnlessEqual(data[:4], imp.get_magic())
+        py_mod = int(os.stat(self.py_path).st_mtime)
+        # XXX Using importer's r_long.
+        pyc_mod = importer.r_long(data[4:8])
+        self.failUnlessEqual(py_mod, pyc_mod)
+        code = marshal.loads(data[8:])
+        module = mock_importer.MockModule(self.module_name)
+        exec code in module.__dict__
         self.verify_module(module)
 
     def test_top_level_package(self):


More information about the Python-checkins mailing list