summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS.txt1
-rw-r--r--CHANGES.txt5
-rw-r--r--coverage/control.py45
-rw-r--r--coverage/execfile.py16
-rw-r--r--pylintrc2
-rw-r--r--tests/test_files.py1
-rw-r--r--tests/test_process.py25
7 files changed, 54 insertions, 41 deletions
diff --git a/AUTHORS.txt b/AUTHORS.txt
index 05794483..5e7bb54a 100644
--- a/AUTHORS.txt
+++ b/AUTHORS.txt
@@ -16,6 +16,7 @@ David Christian
Marcus Cobden
Matthew Desmarais
Danek Duvall
+Buck Evan
Ben Finney
Martin Fuzzey
Alex Gaynor
diff --git a/CHANGES.txt b/CHANGES.txt
index 3974a46e..828a0421 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -27,9 +27,14 @@ Latest
- You can now programmatically adjust the configuration of coverage by setting
items on `Coverage.config` after construcion.
+- A module run with ``-m`` can be used as the argument to ``--source``, fixing
+ `issue 328`_. Thanks, Buck Evan.
+
- Made some PyPy-specific tweaks to improve speed under PyPy. Thanks, Alex
Gaynor.
+.. _issue 328: https://bitbucket.org/ned/coveragepy/issue/328/misbehavior-in-run-source
+
Version 4.0a1 --- 27 September 2014
-----------------------------------
diff --git a/coverage/control.py b/coverage/control.py
index 346f655f..bcb18231 100644
--- a/coverage/control.py
+++ b/coverage/control.py
@@ -129,6 +129,7 @@ class Coverage(object):
# The matchers for _should_trace.
self.source_match = None
+ self.source_pkgs_match = None
self.pylib_match = self.cover_match = None
self.include_match = self.omit_match = None
@@ -305,36 +306,36 @@ class Coverage(object):
filename = filename[:-9] + ".py"
return filename
- def _name_for_module(self, module_namespace, filename):
- """
- For configurability's sake, we allow __main__ modules to be matched by their importable name.
+ def _name_for_module(self, module_globals, filename):
+ """Get the name of the module for a set of globals and filename.
+
+ For configurability's sake, we allow __main__ modules to be matched by
+ their importable name.
+
+ If loaded via runpy (aka -m), we can usually recover the "original" full
+ dotted module name, otherwise, we resort to interpreting the filename to
+ get the module's name. In the case that the module name can't be
+ deteremined, None is returned.
- If loaded via runpy (aka -m), we can usually recover the "original" full dotted module name,
- otherwise, we resort to interpreting the filename to get the module's name.
- In the case that the module name can't be deteremined, None is returned.
"""
- # TODO: unit-test
- dunder_name = module_namespace.get('__name__', None)
+ dunder_name = module_globals.get('__name__', None)
if isinstance(dunder_name, str) and dunder_name != '__main__':
- # this is the usual case: an imported module
+ # This is the usual case: an imported module.
return dunder_name
- loader = module_namespace.get('__loader__', None)
+ loader = module_globals.get('__loader__', None)
for attrname in ('fullname', 'name'): # attribute renamed in py3.2
if hasattr(loader, attrname):
fullname = getattr(loader, attrname)
else:
continue
- if (
- isinstance(fullname, str) and
- fullname != '__main__'
- ):
- # module loaded via runpy -m
+ if isinstance(fullname, str) and fullname != '__main__':
+ # Module loaded via: runpy -m
return fullname
- # script as first argument to python cli
+ # Script as first argument to Python CLI.
inspectedname = inspect.getmodulename(filename)
if inspectedname is not None:
return inspectedname
@@ -675,12 +676,12 @@ class Coverage(object):
):
self._warn("Module %s has no Python source." % pkg)
else:
- raise AssertionError('''\
-Unexpected third case:
- name: %s
- object: %r
- __file__: %s''' % (pkg, sys.modules[pkg], sys.modules[pkg].__file__)
- )
+ raise AssertionError(
+ "Unexpected third case: name = %s, "
+ "object = %r, "
+ "__file__ = %s" % (
+ pkg, sys.modules[pkg], sys.modules[pkg].__file__
+ ))
# Find out if we got any data.
summary = self.data.summary()
diff --git a/coverage/execfile.py b/coverage/execfile.py
index 8965d207..f08b7589 100644
--- a/coverage/execfile.py
+++ b/coverage/execfile.py
@@ -7,18 +7,12 @@ from coverage.backward import PYC_MAGIC_NUMBER, imp, importlib_util_find_spec
from coverage.misc import ExceptionDuringRun, NoCode, NoSource
-if sys.version_info >= (3, 3):
- DEFAULT_FULLNAME = '__main__'
-else:
- DEFAULT_FULLNAME = None
-
-
class DummyLoader(object):
"""A shim for the pep302 __loader__, emulating pkgutil.ImpLoader.
Currently only implements the .fullname attribute
"""
- def __init__(self, fullname, *args):
+ def __init__(self, fullname, *_args):
self.fullname = fullname
@@ -109,7 +103,7 @@ def run_python_module(modulename, args):
run_python_file(pathname, args, package=packagename, modulename=modulename)
-def run_python_file(filename, args, package=None, modulename=DEFAULT_FULLNAME):
+def run_python_file(filename, args, package=None, modulename=None):
"""Run a python file as if it were the main program on the command line.
`filename` is the path to the file to execute, it need not be a .py file.
@@ -117,7 +111,13 @@ def run_python_file(filename, args, package=None, modulename=DEFAULT_FULLNAME):
element naming the file being executed. `package` is the name of the
enclosing package, if any.
+ `modulename` is the name of the module the file was run as.
+
"""
+ if modulename is None and sys.version_info >= (3, 3):
+ modulename = '__main__'
+
+
# Create a module to serve as __main__
old_main_mod = sys.modules['__main__']
main_mod = types.ModuleType('__main__')
diff --git a/pylintrc b/pylintrc
index 15a3b4d8..2aa6f172 100644
--- a/pylintrc
+++ b/pylintrc
@@ -293,7 +293,7 @@ int-import-graph=
[FORMAT]
# Maximum number of characters on a single line.
-max-line-length=79
+max-line-length=80
# Maximum number of lines in a module
max-module-lines=10000
diff --git a/tests/test_files.py b/tests/test_files.py
index f6976a81..6c5a332d 100644
--- a/tests/test_files.py
+++ b/tests/test_files.py
@@ -85,7 +85,6 @@ class MatcherTest(CoverageTest):
def test_module_matcher(self):
matches_to_try = [
('test', True),
- ('test', True),
('trash', False),
('testing', False),
('test.x', True),
diff --git a/tests/test_process.py b/tests/test_process.py
index 09d4c207..e8418e35 100644
--- a/tests/test_process.py
+++ b/tests/test_process.py
@@ -358,9 +358,13 @@ class ProcessTest(CoverageTest):
self.assertEqual(self.line_count(out), 6, out)
def test_coverage_run_script_imports_doubledashsource(self):
+ # This file imports try_execfile, which compiles it to .pyc, so the
+ # first run will have __file__ == "try_execfile.py" and the second will
+ # have __file__ == "try_execfile.pyc", which throws off the comparison.
+ # Setting dont_write_bytecode True stops the compilation to .pyc and
+ # keeps the test working.
self.make_file("myscript", """\
- import sys
- sys.dont_write_bytecode = True
+ import sys; sys.dont_write_bytecode = True
def main():
import tests.try_execfile
@@ -728,13 +732,15 @@ class ProcessStartupTest(ProcessCoverageMixin, CoverageTest):
class ProcessStartupWithSourceTest(ProcessCoverageMixin, CoverageTest):
"""Show that we can configure {[run]source} during process-level coverage.
- There are two interesting variables:
+ There are three interesting variables:
1) -m versus a simple script argument (eg `python myscript`)
2) filtering for the top-level (main.py) or second-level (sub.py) module
3) whether the files are in a package or not
... for a total of eight tests.
+
"""
+
def assert_pth_and_source_work_together(self, dashm, package, source):
def fullname(modname):
if package and dashm:
@@ -749,23 +755,23 @@ class ProcessStartupWithSourceTest(ProcessCoverageMixin, CoverageTest):
raise SkipTest(
"Can't test subprocess pth file suppport during metacoverage"
)
- # Main will run sub.py
+
+ # Main will run sub.py.
self.make_file(path("main.py"), """\
import %s
if True: pass
""" % fullname('sub'))
if package:
- self.make_file(path("__init__.py"), '')
+ self.make_file(path("__init__.py"), "")
# sub.py will write a few lines.
self.make_file(path("sub.py"), """\
with open("out.txt", "w") as f:
- f.write("Hello, world!\\n")
+ f.write("Hello, world!")
""")
self.make_file("coverage.ini", """\
[run]
source = %s
- """ % fullname(source)
- )
+ """ % fullname(source))
self.set_environ("COVERAGE_PROCESS_START", "coverage.ini")
@@ -774,11 +780,12 @@ class ProcessStartupWithSourceTest(ProcessCoverageMixin, CoverageTest):
else:
cmd = (sys.executable, path('main.py'))
+ # TODO: can we use run_command here instead of Popen?
from subprocess import Popen
Popen(cmd).wait()
with open("out.txt") as f:
- self.assertEqual(f.read(), "Hello, world!\n")
+ self.assertEqual(f.read(), "Hello, world!")
# Read the data from .coverage
self.assert_exists(".coverage")