diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2016-05-08 08:25:46 -0400 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2016-05-08 08:25:46 -0400 |
commit | b918987030fadd52f47cb8b2067e54c59a73d794 (patch) | |
tree | 8c0a85e120b165218bdc90398f92612ec49ad9c5 | |
parent | 36d94fb250dcc838a0fd8f83bb8a6ad53665cb37 (diff) | |
download | python-coveragepy-git-b918987030fadd52f47cb8b2067e54c59a73d794.tar.gz |
Don't get confused by namespace packages #456
-rw-r--r-- | CHANGES.rst | 5 | ||||
-rw-r--r-- | coverage/python.py | 9 | ||||
-rw-r--r-- | tests/test_api.py | 21 |
3 files changed, 34 insertions, 1 deletions
diff --git a/CHANGES.rst b/CHANGES.rst index c007a235..a6f0efa4 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -42,12 +42,17 @@ Unreleased - Officially support PyPy 5.1, which required no changes, just updates to the docs. +- It's never been possible to pass a namespace module to one of the analysis + functions, but now at least we raise a more specific error message, rather + than getting confused. (`issue 456`_) + - Make a small tweak to how we compare threads, to avoid buggy custom comparison code in thread classes. (`issue 245`_) .. _issue 90: https://bitbucket.org/ned/coveragepy/issues/90/lambda-expression-confuses-branch .. _issue 245: https://bitbucket.org/ned/coveragepy/issues/245/change-solution-for-issue-164 .. _issue 440: https://bitbucket.org/ned/coveragepy/issues/440/yielded-twisted-failure-marked-as-missed +.. _issue 456: https://bitbucket.org/ned/coveragepy/issues/456/coverage-breaks-with-implicit-namespaces .. _issue 460: https://bitbucket.org/ned/coveragepy/issues/460/confusing-html-report-for-certain-partial .. _issue 469: https://bitbucket.org/ned/coveragepy/issues/469/strange-1-line-number-in-branch-coverage .. _issue 472: https://bitbucket.org/ned/coveragepy/issues/472/html-report-indents-incorrectly-for-one diff --git a/coverage/python.py b/coverage/python.py index 0cd2181c..8e98bea8 100644 --- a/coverage/python.py +++ b/coverage/python.py @@ -4,10 +4,13 @@ """Python source expertise for coverage.py""" import os.path +import types import zipimport from coverage import env, files -from coverage.misc import contract, expensive, NoSource, join_regex, isolate_module +from coverage.misc import ( + contract, CoverageException, expensive, NoSource, join_regex, isolate_module, +) from coverage.parser import PythonParser from coverage.phystokens import source_token_lines, source_encoding from coverage.plugin import FileReporter @@ -94,6 +97,10 @@ class PythonFileReporter(FileReporter): if hasattr(morf, '__file__'): filename = morf.__file__ + elif isinstance(morf, types.ModuleType): + # A module should have had .__file__, otherwise we can't use it. + # This could be a PEP-420 namespace package. + raise CoverageException("Module {0} has no file".format(morf)) else: filename = morf diff --git a/tests/test_api.py b/tests/test_api.py index 3ea5b3ef..4c038519 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -9,6 +9,7 @@ import sys import textwrap import coverage +from coverage import env from coverage.backward import StringIO from coverage.misc import CoverageException @@ -322,6 +323,26 @@ class ApiTest(CoverageTest): self.assert_exists(".coverage.foo") +class NamespaceModuleTest(CoverageTest): + """Test PEP-420 namespace modules.""" + + def setUp(self): + super(NamespaceModuleTest, self).setUp() + if env.PYVERSION < (3, 3): + self.skip("Python before 3.3 doesn't have namespace packages") + + def test_explicit_namespace_module(self): + self.make_file("namespace/package/module.py", "VAR = 1\n") + self.make_file("main.py", "import namespace\n") + + cov = coverage.Coverage() + self.start_import_stop(cov, "main") + + with self.assertRaisesRegex(CoverageException, r"Module .* has no file"): + cov.analysis(sys.modules['namespace']) + + + class UsingModulesMixin(object): """A mixin for importing modules from test/modules and test/moremodules.""" |