DebugClients/Python/coverage/codeunit.py

changeset 4491
0d8612e24fef
parent 4487
4ba7a8ab24f2
parent 4490
3f58261e7bb1
child 4492
1a958c27b767
equal deleted inserted replaced
4487:4ba7a8ab24f2 4491:0d8612e24fef
1 """Code unit (module) handling for Coverage."""
2
3 import glob, os, sys
4
5 from .backward import open_source, string_class, StringIO
6 from .misc import CoverageException
7
8
9 def code_unit_factory(morfs, file_locator):
10 """Construct a list of CodeUnits from polymorphic inputs.
11
12 `morfs` is a module or a filename, or a list of same.
13
14 `file_locator` is a FileLocator that can help resolve filenames.
15
16 Returns a list of CodeUnit objects.
17
18 """
19 # Be sure we have a list.
20 if not isinstance(morfs, (list, tuple)):
21 morfs = [morfs]
22
23 # On Windows, the shell doesn't expand wildcards. Do it here.
24 globbed = []
25 for morf in morfs:
26 if isinstance(morf, string_class) and ('?' in morf or '*' in morf):
27 globbed.extend(glob.glob(morf))
28 else:
29 globbed.append(morf)
30 morfs = globbed
31
32 code_units = [CodeUnit(morf, file_locator) for morf in morfs]
33
34 return code_units
35
36
37 class CodeUnit(object):
38 """Code unit: a filename or module.
39
40 Instance attributes:
41
42 `name` is a human-readable name for this code unit.
43 `filename` is the os path from which we can read the source.
44 `relative` is a boolean.
45
46 """
47 def __init__(self, morf, file_locator):
48 self.file_locator = file_locator
49
50 if hasattr(morf, '__file__'):
51 f = morf.__file__
52 else:
53 f = morf
54 # .pyc files should always refer to a .py instead.
55 if f.endswith('.pyc') or f.endswith('.pyo'):
56 f = f[:-1]
57 elif f.endswith('$py.class'): # Jython
58 f = f[:-9] + ".py"
59 self.filename = self.file_locator.canonical_filename(f)
60 if isinstance(self.filename, unicode):
61 self.filename = self.filename.encode(sys.getfilesystemencoding())
62
63 if hasattr(morf, '__name__'):
64 n = modname = morf.__name__
65 self.relative = True
66 else:
67 n = os.path.splitext(morf)[0]
68 rel = self.file_locator.relative_filename(n)
69 if isinstance(rel, unicode):
70 rel = rel.encode(sys.getfilesystemencoding())
71 if os.path.isabs(n):
72 self.relative = (rel != n)
73 else:
74 self.relative = True
75 n = rel
76 modname = None
77 self.name = n
78 self.modname = modname
79
80 def __repr__(self):
81 return "<CodeUnit name=%r filename=%r>" % (self.name, self.filename)
82
83 # Annoying comparison operators. Py3k wants __lt__ etc, and Py2k needs all
84 # of them defined.
85
86 def __lt__(self, other):
87 return self.name < other.name
88 def __le__(self, other):
89 return self.name <= other.name
90 def __eq__(self, other):
91 return self.name == other.name
92 def __ne__(self, other):
93 return self.name != other.name
94 def __gt__(self, other):
95 return self.name > other.name
96 def __ge__(self, other):
97 return self.name >= other.name
98
99 def flat_rootname(self):
100 """A base for a flat filename to correspond to this code unit.
101
102 Useful for writing files about the code where you want all the files in
103 the same directory, but need to differentiate same-named files from
104 different directories.
105
106 For example, the file a/b/c.py might return 'a_b_c'
107
108 """
109 if self.modname:
110 return self.modname.replace('.', '_')
111 else:
112 root = os.path.splitdrive(self.name)[1]
113 return root.replace('\\', '_').replace('/', '_').replace('.', '_')
114
115 def source_file(self):
116 """Return an open file for reading the source of the code unit."""
117 if os.path.exists(self.filename):
118 # A regular text file: open it.
119 return open_source(self.filename)
120
121 # Maybe it's in a zip file?
122 source = self.file_locator.get_zip_data(self.filename)
123 if source is not None:
124 return StringIO(source)
125
126 # Couldn't find source.
127 raise CoverageException(
128 "No source for code '%s'." % self.filename
129 )
130
131 def should_be_python(self):
132 """Does it seem like this file should contain Python?
133
134 This is used to decide if a file reported as part of the exection of
135 a program was really likely to have contained Python in the first
136 place.
137
138 """
139 # Get the file extension.
140 _, ext = os.path.splitext(self.filename)
141
142 # Anything named *.py* should be Python.
143 if ext.startswith('.py'):
144 return True
145 # A file with no extension should be Python.
146 if not ext:
147 return True
148 # Everything else is probably not Python.
149 return False
150
151 #
152 # eflag: FileType = Python2

eric ide

mercurial