summaryrefslogtreecommitdiff
path: root/coverage/control.py
diff options
context:
space:
mode:
authorNed Batchelder <nedbat@gmail.com>2017-01-14 17:18:56 -0500
committerNed Batchelder <nedbat@gmail.com>2017-01-14 17:18:56 -0500
commit3d8e48162df541de153ee0f23f75074e2fc13376 (patch)
treefd22302b96422e6749f8beb5d376dff03b3a66cf /coverage/control.py
parent6d24c0864b2e18fb646ddca1cefd71819b64e83d (diff)
parentd9ca8593eba371b49402974c1c1f2bf7fd52fed9 (diff)
downloadpython-coveragepy-3d8e48162df541de153ee0f23f75074e2fc13376.tar.gz
Merged in dachary/coverage.py/issue-426 (pull request #122)
make --source module do the same as --source directory #426
Diffstat (limited to 'coverage/control.py')
-rw-r--r--coverage/control.py66
1 files changed, 27 insertions, 39 deletions
diff --git a/coverage/control.py b/coverage/control.py
index 037fc6d..ebb449c 100644
--- a/coverage/control.py
+++ b/coverage/control.py
@@ -26,7 +26,7 @@ from coverage.misc import CoverageException, bool_or_none, join_regex
from coverage.misc import file_be_gone, isolate_module
from coverage.plugin import FileReporter
from coverage.plugin_support import Plugins
-from coverage.python import PythonFileReporter
+from coverage.python import PythonFileReporter, source_for_file
from coverage.results import Analysis, Numbers
from coverage.summary import SummaryReporter
from coverage.xmlreport import XmlReporter
@@ -164,6 +164,7 @@ class Coverage(object):
# Other instance attributes, set later.
self.omit = self.include = self.source = None
+ self.source_pkgs_unmatched = None
self.source_pkgs = None
self.data = self.data_files = self.collector = None
self.plugins = None
@@ -228,6 +229,7 @@ class Coverage(object):
self.source.append(files.canonical_filename(src))
else:
self.source_pkgs.append(src)
+ self.source_pkgs_unmatched = self.source_pkgs[:]
self.omit = prep_patterns(self.config.omit)
self.include = prep_patterns(self.config.include)
@@ -367,38 +369,6 @@ class Coverage(object):
morf_filename = PythonFileReporter(morf, self).filename
return os.path.split(morf_filename)[0]
- def _source_for_file(self, filename):
- """Return the source file for `filename`.
-
- Given a file name being traced, return the best guess as to the source
- file to attribute it to.
-
- """
- if filename.endswith(".py"):
- # .py files are themselves source files.
- return filename
-
- elif filename.endswith((".pyc", ".pyo")):
- # Bytecode files probably have source files near them.
- py_filename = filename[:-1]
- if os.path.exists(py_filename):
- # Found a .py file, use that.
- return py_filename
- if env.WINDOWS:
- # On Windows, it could be a .pyw file.
- pyw_filename = py_filename + "w"
- if os.path.exists(pyw_filename):
- return pyw_filename
- # Didn't find source, but it's probably the .py file we want.
- return py_filename
-
- elif filename.endswith("$py.class"):
- # Jython is easy to guess.
- return filename[:-9] + ".py"
-
- # No idea, just use the file name as-is.
- return filename
-
def _name_for_module(self, module_globals, filename):
"""Get the name of the module for a set of globals and file name.
@@ -461,7 +431,7 @@ class Coverage(object):
# co_filename value.
dunder_file = frame.f_globals.get('__file__')
if dunder_file:
- filename = self._source_for_file(dunder_file)
+ filename = source_for_file(dunder_file)
if original_filename and not original_filename.startswith('<'):
orig = os.path.basename(original_filename)
if orig != os.path.basename(filename):
@@ -558,8 +528,8 @@ class Coverage(object):
# stdlib and coverage.py directories.
if self.source_match:
if self.source_pkgs_match.match(modulename):
- if modulename in self.source_pkgs:
- self.source_pkgs.remove(modulename)
+ if modulename in self.source_pkgs_unmatched:
+ self.source_pkgs_unmatched.remove(modulename)
return None # There's no reason to skip this file.
if not self.source_match.match(filename):
@@ -824,10 +794,10 @@ class Coverage(object):
self.collector.save_data(self.data)
- # If there are still entries in the source_pkgs list, then we never
+ # If there are still entries in the source_pkgs_unmatched list, then we never
# encountered those packages.
if self._warn_unimported_source:
- for pkg in self.source_pkgs:
+ for pkg in self.source_pkgs_unmatched:
if pkg not in sys.modules:
self._warn("Module %s was never imported." % pkg)
elif not (
@@ -842,8 +812,26 @@ class Coverage(object):
if not self.data and self._warn_no_data:
self._warn("No data was collected.")
+ src_directories = self.source[:]
+
+ for pkg in self.source_pkgs:
+ if (not pkg in sys.modules or
+ not hasattr(sys.modules[pkg], '__file__') or
+ not os.path.exists(sys.modules[pkg].__file__)):
+ continue
+ pkg_file = source_for_file(sys.modules[pkg].__file__)
+ #
+ # Do not explore the souce tree of a module that is
+ # not a directory tree. For instance if
+ # sys.modules['args'].__file__ == /lib/python2.7/site-packages/args.pyc
+ # we do not want to explore all of /lib/python2.7/site-packages
+ #
+ if not pkg_file.endswith('__init__.py'):
+ continue
+ src_directories.append(self._canonical_dir(sys.modules[pkg]))
+
# Find files that were never executed at all.
- for src in self.source:
+ for src in src_directories:
for py_file in find_python_files(src):
py_file = files.canonical_filename(py_file)