--- a/DebugClients/Python/coverage/plugin.py Fri Sep 02 19:08:02 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,399 +0,0 @@ -# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 -# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt - -"""Plugin interfaces for coverage.py""" - -from coverage import files -from coverage.misc import contract, _needs_to_implement - - -class CoveragePlugin(object): - """Base class for coverage.py plugins. - - To write a coverage.py plugin, create a module with a subclass of - :class:`CoveragePlugin`. You will override methods in your class to - participate in various aspects of coverage.py's processing. - - Currently the only plugin type is a file tracer, for implementing - measurement support for non-Python files. File tracer plugins implement - the :meth:`file_tracer` method to claim files and the :meth:`file_reporter` - method to report on those files. - - Any plugin can optionally implement :meth:`sys_info` to provide debugging - information about their operation. - - Coverage.py will store its own information on your plugin object, using - attributes whose names start with ``_coverage_``. Don't be startled. - - To register your plugin, define a function called `coverage_init` in your - module:: - - def coverage_init(reg, options): - reg.add_file_tracer(MyPlugin()) - - You use the `reg` parameter passed to your `coverage_init` function to - register your plugin object. It has one method, `add_file_tracer`, which - takes a newly created instance of your plugin. - - If your plugin takes options, the `options` parameter is a dictionary of - your plugin's options from the coverage.py configuration file. Use them - however you want to configure your object before registering it. - - """ - - def file_tracer(self, filename): # pylint: disable=unused-argument - """Get a :class:`FileTracer` object for a file. - - Every Python source file is offered to the plugin to give it a chance - to take responsibility for tracing the file. If your plugin can handle - the file, then return a :class:`FileTracer` object. Otherwise return - None. - - There is no way to register your plugin for particular files. Instead, - this method is invoked for all files, and the plugin decides whether it - can trace the file or not. Be prepared for `filename` to refer to all - kinds of files that have nothing to do with your plugin. - - The file name will be a Python file being executed. There are two - broad categories of behavior for a plugin, depending on the kind of - files your plugin supports: - - * Static file names: each of your original source files has been - converted into a distinct Python file. Your plugin is invoked with - the Python file name, and it maps it back to its original source - file. - - * Dynamic file names: all of your source files are executed by the same - Python file. In this case, your plugin implements - :meth:`FileTracer.dynamic_source_filename` to provide the actual - source file for each execution frame. - - `filename` is a string, the path to the file being considered. This is - the absolute real path to the file. If you are comparing to other - paths, be sure to take this into account. - - Returns a :class:`FileTracer` object to use to trace `filename`, or - None if this plugin cannot trace this file. - - """ - return None - - def file_reporter(self, filename): # pylint: disable=unused-argument - """Get the :class:`FileReporter` class to use for a file. - - This will only be invoked if `filename` returns non-None from - :meth:`file_tracer`. It's an error to return None from this method. - - Returns a :class:`FileReporter` object to use to report on `filename`. - - """ - _needs_to_implement(self, "file_reporter") - - def sys_info(self): - """Get a list of information useful for debugging. - - This method will be invoked for ``--debug=sys``. Your - plugin can return any information it wants to be displayed. - - Returns a list of pairs: `[(name, value), ...]`. - - """ - return [] - - -class FileTracer(object): - """Support needed for files during the execution phase. - - You may construct this object from :meth:`CoveragePlugin.file_tracer` any - way you like. A natural choice would be to pass the file name given to - `file_tracer`. - - `FileTracer` objects should only be created in the - :meth:`CoveragePlugin.file_tracer` method. - - See :ref:`howitworks` for details of the different coverage.py phases. - - """ - - def source_filename(self): - """The source file name for this file. - - This may be any file name you like. A key responsibility of a plugin - is to own the mapping from Python execution back to whatever source - file name was originally the source of the code. - - See :meth:`CoveragePlugin.file_tracer` for details about static and - dynamic file names. - - Returns the file name to credit with this execution. - - """ - _needs_to_implement(self, "source_filename") - - def has_dynamic_source_filename(self): - """Does this FileTracer have dynamic source file names? - - FileTracers can provide dynamically determined file names by - implementing :meth:`dynamic_source_filename`. Invoking that function - is expensive. To determine whether to invoke it, coverage.py uses the - result of this function to know if it needs to bother invoking - :meth:`dynamic_source_filename`. - - See :meth:`CoveragePlugin.file_tracer` for details about static and - dynamic file names. - - Returns True if :meth:`dynamic_source_filename` should be called to get - dynamic source file names. - - """ - return False - - def dynamic_source_filename(self, filename, frame): # pylint: disable=unused-argument - """Get a dynamically computed source file name. - - Some plugins need to compute the source file name dynamically for each - frame. - - This function will not be invoked if - :meth:`has_dynamic_source_filename` returns False. - - Returns the source file name for this frame, or None if this frame - shouldn't be measured. - - """ - return None - - def line_number_range(self, frame): - """Get the range of source line numbers for a given a call frame. - - The call frame is examined, and the source line number in the original - file is returned. The return value is a pair of numbers, the starting - line number and the ending line number, both inclusive. For example, - returning (5, 7) means that lines 5, 6, and 7 should be considered - executed. - - This function might decide that the frame doesn't indicate any lines - from the source file were executed. Return (-1, -1) in this case to - tell coverage.py that no lines should be recorded for this frame. - - """ - lineno = frame.f_lineno - return lineno, lineno - - -class FileReporter(object): - """Support needed for files during the analysis and reporting phases. - - See :ref:`howitworks` for details of the different coverage.py phases. - - `FileReporter` objects should only be created in the - :meth:`CoveragePlugin.file_reporter` method. - - There are many methods here, but only :meth:`lines` is required, to provide - the set of executable lines in the file. - - """ - - def __init__(self, filename): - """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): - """Get the relative file name for this file. - - This file path will be displayed in reports. The default - implementation will supply the actual project-relative file path. You - only need to supply this method if you have an unusual syntax for file - paths. - - """ - return files.relative_filename(self.filename) - - @contract(returns='unicode') - def source(self): - """Get the source for the file. - - Returns a Unicode string. - - The base implementation simply reads the `self.filename` file and - decodes it as UTF8. Override this method if your file isn't readable - as a text file, or if you need other encoding support. - - """ - with open(self.filename, "rb") as f: - return f.read().decode("utf8") - - def lines(self): - """Get the executable lines in this file. - - Your plugin must determine which lines in the file were possibly - executable. This method returns a set of those line numbers. - - Returns a set of line numbers. - - """ - _needs_to_implement(self, "lines") - - def excluded_lines(self): - """Get the excluded executable lines in this file. - - Your plugin can use any method it likes to allow the user to exclude - executable lines from consideration. - - Returns a set of line numbers. - - The base implementation returns the empty set. - - """ - return set() - - def translate_lines(self, lines): - """Translate recorded lines into reported lines. - - Some file formats will want to report lines slightly differently than - they are recorded. For example, Python records the last line of a - multi-line statement, but reports are nicer if they mention the first - line. - - Your plugin can optionally define this method to perform these kinds of - adjustment. - - `lines` is a sequence of integers, the recorded line numbers. - - Returns a set of integers, the adjusted line numbers. - - The base implementation returns the numbers unchanged. - - """ - return set(lines) - - def arcs(self): - """Get the executable arcs in this file. - - To support branch coverage, your plugin needs to be able to indicate - possible execution paths, as a set of line number pairs. Each pair is - a `(prev, next)` pair indicating that execution can transition from the - `prev` line number to the `next` line number. - - Returns a set of pairs of line numbers. The default implementation - returns an empty set. - - """ - return set() - - def no_branch_lines(self): - """Get the lines excused from branch coverage in this file. - - Your plugin can use any method it likes to allow the user to exclude - lines from consideration of branch coverage. - - Returns a set of line numbers. - - The base implementation returns the empty set. - - """ - return set() - - def translate_arcs(self, arcs): - """Translate recorded arcs into reported arcs. - - Similar to :meth:`translate_lines`, but for arcs. `arcs` is a set of - line number pairs. - - Returns a set of line number pairs. - - The default implementation returns `arcs` unchanged. - - """ - return arcs - - def exit_counts(self): - """Get a count of exits from that each line. - - To determine which lines are branches, coverage.py looks for lines that - have more than one exit. This function creates a dict mapping each - executable line number to a count of how many exits it has. - - To be honest, this feels wrong, and should be refactored. Let me know - if you attempt to implement this method in your plugin... - - """ - return {} - - def missing_arc_description(self, start, end, executed_arcs=None): # pylint: disable=unused-argument - """Provide an English sentence describing a missing arc. - - The `start` and `end` arguments are the line numbers of the missing - arc. Negative numbers indicate entering or exiting code objects. - - The `executed_arcs` argument is a set of line number pairs, the arcs - that were executed in this file. - - By default, this simply returns the string "Line {start} didn't jump - to {end}". - - """ - return "Line {start} didn't jump to line {end}".format(start=start, end=end) - - def source_token_lines(self): - """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. - - The default implementation simply returns each line tagged as - ``'txt'``. - - """ - for line in self.source().splitlines(): - yield [('txt', line)] - - # 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 - - def __ne__(self, other): - return not (self == other) - - def __lt__(self, other): - return self.filename < other.filename - - def __le__(self, other): - return self.filename <= other.filename - - def __gt__(self, other): - return self.filename > other.filename - - def __ge__(self, other): - return self.filename >= other.filename - -# -# eflag: FileType = Python2