diff options
Diffstat (limited to 'coverage/plugin.py')
-rw-r--r-- | coverage/plugin.py | 116 |
1 files changed, 63 insertions, 53 deletions
diff --git a/coverage/plugin.py b/coverage/plugin.py index f4182b0f..1b098364 100644 --- a/coverage/plugin.py +++ b/coverage/plugin.py @@ -3,11 +3,8 @@ """Plugin interfaces for coverage.py""" -import os -import re - from coverage import files -from coverage.misc import _needs_to_implement +from coverage.misc import contract, _needs_to_implement class CoveragePlugin(object): @@ -154,42 +151,42 @@ class FileTracer(object): class FileReporter(object): """Support needed for files during the reporting phase.""" + def __init__(self, filename): - # TODO: document that this init happens. + """Simple initialization of a `FileReporter`. + + The `filename` argument is the path to the file being reported. This + will be available as the `.filename` attribute on the object. Other + method implementations on this base class rely on this attribute. + + """ self.filename = filename def __repr__(self): return "<{0.__class__.__name__} filename={0.filename!r}>".format(self) def relative_filename(self): - return files.relative_filename(self.filename) - - # Annoying comparison operators. Py3k wants __lt__ etc, and Py2k needs all - # of them defined. - - def __eq__(self, other): - return isinstance(other, FileReporter) and self.filename == other.filename + """Return the relative filename for this file. - def __ne__(self, other): - return not (self == other) + This file path will be displayed in reports. You only need to supply + this method if you have an unusual syntax for file paths. The default + implementation will supply the actual project-relative file path. - def __lt__(self, other): - return self.filename < other.filename - - def __le__(self, other): - return self.filename <= other.filename + """ + return files.relative_filename(self.filename) - def __gt__(self, other): - return self.filename > other.filename + def lines(self): + """Return a set of executable lines""" + _needs_to_implement(self, "lines") - def __ge__(self, other): - return self.filename >= other.filename + def excluded_lines(self): + return set() - def statements(self): - _needs_to_implement(self, "statements") + def arcs(self): + return [] - def excluded_statements(self): - return set([]) + def no_branch_lines(self): + return set() def translate_lines(self, lines): return set(lines) @@ -197,47 +194,60 @@ class FileReporter(object): def translate_arcs(self, arcs): return arcs - def no_branch_lines(self): - return set() - def exit_counts(self): return {} - def arcs(self): - return [] - + @contract(returns='unicode') def source(self): """Return the source for the code, a Unicode string.""" # A generic implementation: read the text of self.filename - with open(self.filename) as f: - return f.read() + with open(self.filename, "rb") as f: + return f.read().decode("utf8") def source_token_lines(self): - """Return the 'tokenized' text for the code.""" + """Generate a series of tokenized lines, one for each line in `source`. + + These tokens are used for syntax-colored reports. + + Each line is a list of pairs, each pair is a token:: + + [('key', 'def'), ('ws', ' '), ('nam', 'hello'), ('op', '('), ... ] + + Each pair has a token class, and the token text. The token classes are: + + * `'com'`: a comment + * `'key'`: a keyword + * `'nam'`: a name, or identifier + * `'num'`: a number + * `'op'`: an operator + * `'str'`: a string literal + * `'txt'`: some other kind of text + + If you concatenate all the token texts, and then join them with newlines, + you should have your original `source` back. + + """ # A generic implementation, each line is one "txt" token. for line in self.source().splitlines(): yield [('txt', line)] - def should_be_python(self): - """Does it seem like this file should contain Python? + # Annoying comparison operators. Py3k wants __lt__ etc, and Py2k needs all + # of them defined. - This is used to decide if a file reported as part of the execution of - a program was really likely to have contained Python in the first - place. - """ - return False + def __eq__(self, other): + return isinstance(other, FileReporter) and self.filename == other.filename - def flat_rootname(self): - """A base for a flat filename to correspond to this file. + def __ne__(self, other): + return not (self == other) - 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. + def __lt__(self, other): + return self.filename < other.filename - For example, the file a/b/c.py will return 'a_b_c_py' + def __le__(self, other): + return self.filename <= other.filename - You should not need to override this method. + def __gt__(self, other): + return self.filename > other.filename - """ - name = os.path.splitdrive(self.relative_filename())[1] - return re.sub(r"[\\/.:]", "_", name) + def __ge__(self, other): + return self.filename >= other.filename |