DebugClients/Python/coverage/codeunit.py

changeset 31
744cd0b4b8cd
parent 0
de9c2efb9d02
child 32
01f04fbc1842
--- a/DebugClients/Python/coverage/codeunit.py	Thu Jan 07 13:42:05 2010 +0000
+++ b/DebugClients/Python/coverage/codeunit.py	Thu Jan 07 13:42:51 2010 +0000
@@ -2,60 +2,67 @@
 
 import glob, os
 
+from coverage.backward import string_class, StringIO
+from coverage.misc import CoverageException
+
+
 def code_unit_factory(morfs, file_locator, omit_prefixes=None):
     """Construct a list of CodeUnits from polymorphic inputs.
-    
+
     `morfs` is a module or a filename, or a list of same.
     `file_locator` is a FileLocator that can help resolve filenames.
     `omit_prefixes` is a list of prefixes.  CodeUnits that match those prefixes
     will be omitted from the list.
-    
+
     Returns a list of CodeUnit objects.
-    
+
     """
 
     # Be sure we have a list.
     if not isinstance(morfs, (list, tuple)):
         morfs = [morfs]
-    
+
     # On Windows, the shell doesn't expand wildcards.  Do it here.
     globbed = []
     for morf in morfs:
-        if isinstance(morf, basestring) and ('?' in morf or '*' in morf):
+        if isinstance(morf, string_class) and ('?' in morf or '*' in morf):
             globbed.extend(glob.glob(morf))
         else:
             globbed.append(morf)
     morfs = globbed
 
     code_units = [CodeUnit(morf, file_locator) for morf in morfs]
-    
+
     if omit_prefixes:
+        assert not isinstance(omit_prefixes, string_class) # common mistake
         prefixes = [file_locator.abs_file(p) for p in omit_prefixes]
         filtered = []
         for cu in code_units:
             for prefix in prefixes:
-                if cu.name.startswith(prefix):
+                if cu.filename.startswith(prefix):
                     break
             else:
                 filtered.append(cu)
-    
+
         code_units = filtered
 
     return code_units
 
 
-class CodeUnit:
+class CodeUnit(object):
     """Code unit: a filename or module.
-    
+
     Instance attributes:
-    
+
     `name` is a human-readable name for this code unit.
     `filename` is the os path from which we can read the source.
     `relative` is a boolean.
-    
+
     """
 
     def __init__(self, morf, file_locator):
+        self.file_locator = file_locator
+
         if hasattr(morf, '__file__'):
             f = morf.__file__
         else:
@@ -63,14 +70,14 @@
         # .pyc files should always refer to a .py instead.
         if f.endswith('.pyc'):
             f = f[:-1]
-        self.filename = file_locator.canonical_filename(f)
+        self.filename = self.file_locator.canonical_filename(f)
 
         if hasattr(morf, '__name__'):
             n = modname = morf.__name__
             self.relative = True
         else:
             n = os.path.splitext(morf)[0]
-            rel = file_locator.relative_filename(n)
+            rel = self.file_locator.relative_filename(n)
             if os.path.isabs(n):
                 self.relative = (rel != n)
             else:
@@ -83,18 +90,36 @@
     def __repr__(self):
         return "<CodeUnit name=%r filename=%r>" % (self.name, self.filename)
 
-    def __cmp__(self, other):
-        return cmp(self.name, other.name)
+    # Annoying comparison operators. Py3k wants __lt__ etc, and Py2k needs all
+    # of them defined.
+
+    def __lt__(self, other):
+        return self.name < other.name
+
+    def __le__(self, other):
+        return self.name <= other.name
+
+    def __eq__(self, other):
+        return self.name == other.name
+
+    def __ne__(self, other):
+        return self.name != other.name
+
+    def __gt__(self, other):
+        return self.name > other.name
+
+    def __ge__(self, other):
+        return self.name >= other.name
 
     def flat_rootname(self):
         """A base for a flat filename to correspond to this code unit.
-        
+
         Useful for writing files about the code where you want all the files in
         the same directory, but need to differentiate same-named files from
         different directories.
-        
+
         For example, the file a/b/c.py might return 'a_b_c'
-        
+
         """
         if self.modname:
             return self.modname.replace('.', '_')
@@ -104,4 +129,16 @@
 
     def source_file(self):
         """Return an open file for reading the source of the code unit."""
-        return open(self.filename)
+        if os.path.exists(self.filename):
+            # A regular text file: open it.
+            return open(self.filename)
+
+        # Maybe it's in a zip file?
+        source = self.file_locator.get_zip_data(self.filename)
+        if source is not None:
+            return StringIO(source)
+
+        # Couldn't find source.
+        raise CoverageException(
+            "No source for code %r." % self.filename
+            )

eric ide

mercurial