summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2013-09-29 11:19:37 -0400
committerNed Batchelder <ned@nedbatchelder.com>2013-09-29 11:19:37 -0400
commit01d21468e0974cacdea73751270bd3b92376dd80 (patch)
tree28ffe1cd23a5867d36e26ab359ec6ff8b0f901ea
parentb9f30deffb0bf011e1a2b8d2ffc4887b3893ea8b (diff)
downloadpython-coveragepy-01d21468e0974cacdea73751270bd3b92376dd80.tar.gz
Properly report .pyw files. #261.
-rw-r--r--CHANGES.txt7
-rw-r--r--coverage/results.py48
-rw-r--r--tests/test_summary.py21
3 files changed, 66 insertions, 10 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 795bc65..10ad0b2 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -15,6 +15,8 @@ Change history for Coverage.py
- Coverage can now run .pyc files directly, closing `issue 264`_.
+- Coverage properly supports .pyw files, fixing `issue 261`_.
+
- Omitting files within a tree specified with the ``source`` option would
cause them to be incorrectly marked as unexecuted, as described in
`issue 218`_. This is now fixed.
@@ -31,12 +33,12 @@ Change history for Coverage.py
changed, measurement is likely wrong: None." This fixes `issue 164`_.
- Static files necessary for HTML reports are found in system-installed places,
- to ease OS-level packaging of coverage.py. Closes `issue 259`.
+ to ease OS-level packaging of coverage.py. Closes `issue 259`_.
- Source files with encoding declarations, but a blank first line, were not
decoded properly. Now they are. Thanks, Roger Hu.
-- The source kit now includes the `__main__.py` file in the root coverage
+- The source kit now includes the ``__main__.py`` file in the root coverage
directory, fixing `issue 255`_.
.. _issue 92: https://bitbucket.org/ned/coveragepy/issue/92/finally-clauses-arent-treated-properly-in
@@ -47,6 +49,7 @@ Change history for Coverage.py
.. _issue 218: https://bitbucket.org/ned/coveragepy/issue/218/run-command-does-not-respect-the-omit-flag
.. _issue 255: https://bitbucket.org/ned/coveragepy/issue/255/directory-level-__main__py-not-included-in
.. _issue 259: https://bitbucket.org/ned/coveragepy/issue/259/allow-use-of-system-installed-third-party
+.. _issue 261: https://bitbucket.org/ned/coveragepy/issue/261/pyw-files-arent-reported-properly
.. _issue 264: https://bitbucket.org/ned/coveragepy/issue/264/coverage-wont-run-pyc-files
.. _issue 267: https://bitbucket.org/ned/coveragepy/issue/267/relative-path-aliases-dont-work
diff --git a/coverage/results.py b/coverage/results.py
index 77ff2a2..2d13e81 100644
--- a/coverage/results.py
+++ b/coverage/results.py
@@ -15,16 +15,10 @@ class Analysis(object):
self.code_unit = code_unit
self.filename = self.code_unit.filename
- ext = os.path.splitext(self.filename)[1]
- source = None
- if ext == '.py':
- if not os.path.exists(self.filename):
- source = self.coverage.file_locator.get_zip_data(self.filename)
- if not source:
- raise NoSource("No source for code: '%s'" % self.filename)
+ actual_filename, source = self.find_source(self.filename)
self.parser = CodeParser(
- text=source, filename=self.filename,
+ text=source, filename=actual_filename,
exclude=self.coverage._exclude_regex('exclude')
)
self.statements, self.excluded = self.parser.parse_source()
@@ -59,6 +53,44 @@ class Analysis(object):
n_missing_branches=n_missing_branches,
)
+ def find_source(self, filename):
+ """Find the source for `filename`.
+
+ Returns two values: the actual filename, and the source.
+
+ The source returned depends on which of these cases holds:
+
+ * The filename seems to be a non-source file: returns None
+
+ * The filename is a source file, and actually exists: returns None.
+
+ * The filename is a source file, and is in a zip file or egg:
+ returns the source.
+
+ * The filename is a source file, but couldn't be found: raises
+ `NoSource`.
+
+ """
+ source = None
+
+ base, ext = os.path.splitext(filename)
+ TRY_EXTS = {
+ '.py': ['.py', '.pyw'],
+ '.pyw': ['.pyw'],
+ }
+ try_exts = TRY_EXTS.get(ext)
+ if not try_exts:
+ return filename, None
+
+ for try_ext in try_exts:
+ try_filename = base + try_ext
+ if os.path.exists(try_filename):
+ return try_filename, None
+ source = self.coverage.file_locator.get_zip_data(try_filename)
+ if source:
+ return try_filename, source
+ raise NoSource("No source for code: '%s'" % filename)
+
def missing_formatted(self):
"""The missing line numbers, formatted nicely.
diff --git a/tests/test_summary.py b/tests/test_summary.py
index f842677..d61c1bf 100644
--- a/tests/test_summary.py
+++ b/tests/test_summary.py
@@ -230,6 +230,27 @@ class SummaryTest(CoverageTest):
self.assertIn("TheCode", report)
self.assertNotIn("thecode", report)
+ if sys.platform == 'win32':
+ def test_pyw_files(self):
+ # https://bitbucket.org/ned/coveragepy/issue/261
+ self.make_file("start.pyw", """\
+ import mod
+ print("In start.pyw")
+ """)
+ self.make_file("mod.pyw", """\
+ print("In mod.pyw")
+ """)
+ cov = coverage.coverage()
+ cov.start()
+ import start # pragma: nested
+ cov.stop() # pragma: nested
+
+ report = self.get_report(cov)
+ self.assertNotIn("NoSource", report)
+ report = report.splitlines()
+ self.assertIn("start 2 0 100%", report)
+ self.assertIn("mod 1 0 100%", report)
+
class SummaryTest2(CoverageTest):
"""Another bunch of summary tests."""