Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(224)

Unified Diff: tools/telemetry/third_party/coverage/coverage/python.py

Issue 1366913004: Add coverage Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: tools/telemetry/third_party/coverage/coverage/python.py
diff --git a/tools/telemetry/third_party/coverage/coverage/python.py b/tools/telemetry/third_party/coverage/coverage/python.py
new file mode 100644
index 0000000000000000000000000000000000000000..33e6ec01045ebbf9aa5ba8bfd76a4768dcc2a148
--- /dev/null
+++ b/tools/telemetry/third_party/coverage/coverage/python.py
@@ -0,0 +1,192 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
+"""Python source expertise for coverage.py"""
+
+import os.path
+import zipimport
+
+from coverage import env, files
+from coverage.misc import contract, expensive, NoSource, join_regex
+from coverage.parser import PythonParser
+from coverage.phystokens import source_token_lines, source_encoding
+from coverage.plugin import FileReporter
+
+
+@contract(returns='bytes')
+def read_python_source(filename):
+ """Read the Python source text from `filename`.
+
+ Returns bytes.
+
+ """
+ with open(filename, "rb") as f:
+ return f.read().replace(b"\r\n", b"\n").replace(b"\r", b"\n")
+
+
+@contract(returns='unicode')
+def get_python_source(filename):
+ """Return the source code, as unicode."""
+ base, ext = os.path.splitext(filename)
+ if ext == ".py" and env.WINDOWS:
+ exts = [".py", ".pyw"]
+ else:
+ exts = [ext]
+
+ for ext in exts:
+ try_filename = base + ext
+ if os.path.exists(try_filename):
+ # A regular text file: open it.
+ source = read_python_source(try_filename)
+ break
+
+ # Maybe it's in a zip file?
+ source = get_zip_bytes(try_filename)
+ if source is not None:
+ break
+ else:
+ # Couldn't find source.
+ raise NoSource("No source for code: '%s'." % filename)
+
+ source = source.decode(source_encoding(source), "replace")
+
+ # Python code should always end with a line with a newline.
+ if source and source[-1] != '\n':
+ source += '\n'
+
+ return source
+
+
+@contract(returns='bytes|None')
+def get_zip_bytes(filename):
+ """Get data from `filename` if it is a zip file path.
+
+ Returns the bytestring data read from the zip file, or None if no zip file
+ could be found or `filename` isn't in it. The data returned will be
+ an empty string if the file is empty.
+
+ """
+ markers = ['.zip'+os.sep, '.egg'+os.sep]
+ for marker in markers:
+ if marker in filename:
+ parts = filename.split(marker)
+ try:
+ zi = zipimport.zipimporter(parts[0]+marker[:-1])
+ except zipimport.ZipImportError:
+ continue
+ try:
+ data = zi.get_data(parts[1])
+ except IOError:
+ continue
+ return data
+ return None
+
+
+class PythonFileReporter(FileReporter):
+ """Report support for a Python file."""
+
+ def __init__(self, morf, coverage=None):
+ self.coverage = coverage
+
+ if hasattr(morf, '__file__'):
+ filename = morf.__file__
+ else:
+ filename = morf
+
+ # .pyc files should always refer to a .py instead.
+ if filename.endswith(('.pyc', '.pyo')):
+ filename = filename[:-1]
+ elif filename.endswith('$py.class'): # Jython
+ filename = filename[:-9] + ".py"
+
+ super(PythonFileReporter, self).__init__(files.canonical_filename(filename))
+
+ if hasattr(morf, '__name__'):
+ name = morf.__name__
+ name = name.replace(".", os.sep) + ".py"
+ else:
+ name = files.relative_filename(filename)
+ self.relname = name
+
+ self._source = None
+ self._parser = None
+ self._statements = None
+ self._excluded = None
+
+ def relative_filename(self):
+ return self.relname
+
+ @property
+ def parser(self):
+ """Lazily create a :class:`PythonParser`."""
+ if self._parser is None:
+ self._parser = PythonParser(
+ filename=self.filename,
+ exclude=self.coverage._exclude_regex('exclude'),
+ )
+ return self._parser
+
+ @expensive
+ def lines(self):
+ """Return the line numbers of statements in the file."""
+ if self._statements is None:
+ self._statements, self._excluded = self.parser.parse_source()
+ return self._statements
+
+ @expensive
+ def excluded_lines(self):
+ """Return the line numbers of statements in the file."""
+ if self._excluded is None:
+ self._statements, self._excluded = self.parser.parse_source()
+ return self._excluded
+
+ def translate_lines(self, lines):
+ return self.parser.translate_lines(lines)
+
+ def translate_arcs(self, arcs):
+ return self.parser.translate_arcs(arcs)
+
+ @expensive
+ def no_branch_lines(self):
+ no_branch = self.parser.lines_matching(
+ join_regex(self.coverage.config.partial_list),
+ join_regex(self.coverage.config.partial_always_list)
+ )
+ return no_branch
+
+ @expensive
+ def arcs(self):
+ return self.parser.arcs()
+
+ @expensive
+ def exit_counts(self):
+ return self.parser.exit_counts()
+
+ @contract(returns='unicode')
+ def source(self):
+ if self._source is None:
+ self._source = get_python_source(self.filename)
+ return self._source
+
+ def should_be_python(self):
+ """Does it seem like this file should contain Python?
+
+ 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.
+
+ """
+ # Get the file extension.
+ _, ext = os.path.splitext(self.filename)
+
+ # Anything named *.py* should be Python.
+ if ext.startswith('.py'):
+ return True
+ # A file with no extension should be Python.
+ if not ext:
+ return True
+ # Everything else is probably not Python.
+ return False
+
+ def source_token_lines(self):
+ return source_token_lines(self.source())

Powered by Google App Engine
This is Rietveld 408576698