diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2017-05-04 21:18:43 -0400 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2017-05-04 21:18:43 -0400 |
commit | 403e51068a123733740a094e40cdd31ceb5e7c61 (patch) | |
tree | a27d665d77aeea97cec1d45e932347969dbc1930 | |
parent | 67f905e4b7002d71d7ab33b87089a876eb4ef66c (diff) | |
download | python-coveragepy-git-403e51068a123733740a094e40cdd31ceb5e7c61.tar.gz |
Don't warn that namespace packages have no code. #572
--HG--
extra : amend_source : 68f6e0ab140e77ede11bb40dc2ac515cfb6f2333
-rw-r--r-- | CHANGES.rst | 4 | ||||
-rw-r--r-- | coverage/control.py | 44 | ||||
-rw-r--r-- | tests/modules/namespace_420/sub1/__init__.py | 4 | ||||
-rw-r--r-- | tests/moremodules/namespace_420/sub2/__init__.py | 4 | ||||
-rw-r--r-- | tests/test_api.py | 17 |
5 files changed, 57 insertions, 16 deletions
diff --git a/CHANGES.rst b/CHANGES.rst index 4aac4a4f..fd2d7b8c 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -14,6 +14,9 @@ Unreleased instead of the correct ``pkg/__init__.py``. This is now fixed, closing `issue 526`_. Thanks, Dirk Thomas. +- Namespace packages are no longer warned as having no code, as described in + `issue 572`_. + - Code that uses ``sys.settrace(sys.gettrace())`` in a file that wasn't being coverage-measured would prevent correct coverage measurement in following code. An example of this was running doctests programmatically, as described @@ -26,6 +29,7 @@ Unreleased fail under Python 2, as reported in `issue 573`_. This is now fixed. .. _issue 526: https://bitbucket.org/ned/coveragepy/issues/526/generated-xml-invalid-paths-for-cobertura +.. _issue 572: https://bitbucket.org/ned/coveragepy/issues/572/no-python-source-warning-for-namespace .. _issue 573: https://bitbucket.org/ned/coveragepy/issues/573/cant-generate-xml-report-if-some-source .. _issue 575: https://bitbucket.org/ned/coveragepy/issues/575/running-doctest-prevents-complete-coverage diff --git a/coverage/control.py b/coverage/control.py index fb033610..2cbe491b 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -837,18 +837,7 @@ class Coverage(object): # then we never encountered those packages. if self._warn_unimported_source: for pkg in self.source_pkgs_unmatched: - if pkg not in sys.modules: - self._warn("Module %s was never imported." % pkg, slug="module-not-imported") - elif not ( - hasattr(sys.modules[pkg], '__file__') and - os.path.exists(sys.modules[pkg].__file__) - ): - self._warn("Module %s has no Python source." % pkg, slug="module-not-python") - else: - self._warn( - "Module %s was previously imported, but not measured." % pkg, - slug="module-not-measured", - ) + self._warn_about_unmeasured_code(pkg) # Find out if we got any data. if not self.data and self._warn_no_data: @@ -869,6 +858,37 @@ class Coverage(object): if self.config.note: self.data.add_run_info(note=self.config.note) + def _warn_about_unmeasured_code(self, pkg): + """Warn about a package or module that we never traced. + + `pkg` is a string, the name of the package or module. + + """ + mod = sys.modules.get(pkg) + if mod is None: + self._warn("Module %s was never imported." % pkg, slug="module-not-imported") + return + + is_namespace = hasattr(mod, '__path__') and not hasattr(mod, '__file__') + has_file = hasattr(mod, '__file__') and os.path.exists(mod.__file__) + + if is_namespace: + # A namespace package. It's OK for this not to have been traced, + # since there is no code directly in it. + return + + if not has_file: + self._warn("Module %s has no Python source." % pkg, slug="module-not-python") + return + + # The module was in sys.modules, and seems like a module with code, but + # we never measured it. I guess that means it was imported before + # coverage even started. + self._warn( + "Module %s was previously imported, but not measured." % pkg, + slug="module-not-measured", + ) + def _find_plugin_files(self, src_dir): """Get executable files from the plugins.""" for plugin in self.plugins: diff --git a/tests/modules/namespace_420/sub1/__init__.py b/tests/modules/namespace_420/sub1/__init__.py new file mode 100644 index 00000000..94bb2959 --- /dev/null +++ b/tests/modules/namespace_420/sub1/__init__.py @@ -0,0 +1,4 @@ +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt + +sub1 = "namespace_420 sub1" diff --git a/tests/moremodules/namespace_420/sub2/__init__.py b/tests/moremodules/namespace_420/sub2/__init__.py new file mode 100644 index 00000000..0839688c --- /dev/null +++ b/tests/moremodules/namespace_420/sub2/__init__.py @@ -0,0 +1,4 @@ +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt + +sub2 = "namespace_420 sub2" diff --git a/tests/test_api.py b/tests/test_api.py index 90f96548..3a06da36 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -445,7 +445,7 @@ class ApiTest(CoverageTest): self.assertNotIn("no-data-collected", err) -class NamespaceModuleTest(CoverageTest): +class NamespaceModuleTest(UsingModulesMixin, CoverageTest): """Test PEP-420 namespace modules.""" def setUp(self): @@ -454,14 +454,23 @@ class NamespaceModuleTest(CoverageTest): self.skipTest("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") + self.make_file("main.py", "import namespace_420\n") cov = coverage.Coverage() self.start_import_stop(cov, "main") with self.assertRaisesRegex(CoverageException, r"Module .* has no file"): - cov.analysis(sys.modules['namespace']) + cov.analysis(sys.modules['namespace_420']) + + def test_bug_572(self): + self.make_file("main.py", "import namespace_420\n") + + # Use source=namespace_420 to trigger the check that used to fail, + # and use source=main so that something is measured. + cov = coverage.Coverage(source=["namespace_420", "main"]) + with self.assert_warnings(cov, []): + self.start_import_stop(cov, "main") + cov.report() class OmitIncludeTestsMixin(UsingModulesMixin, CoverageTestMethodsMixin): |