diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2014-11-24 22:53:07 -0500 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2014-11-24 22:53:07 -0500 |
commit | 478677345233a9f24b4fd0335d2094e91917e6eb (patch) | |
tree | 60a286d3b0c79cae6206a2d1ff3371eaf4d9dee1 | |
parent | 2b369aa719d2a4b4e755c9030f1d0cc1dfeeeacb (diff) | |
download | python-coveragepy-git-478677345233a9f24b4fd0335d2094e91917e6eb.tar.gz |
Cleanups from pull request 42
-rw-r--r-- | AUTHORS.txt | 1 | ||||
-rw-r--r-- | CHANGES.txt | 5 | ||||
-rw-r--r-- | coverage/control.py | 45 | ||||
-rw-r--r-- | coverage/execfile.py | 16 | ||||
-rw-r--r-- | pylintrc | 2 | ||||
-rw-r--r-- | tests/test_files.py | 1 | ||||
-rw-r--r-- | tests/test_process.py | 25 |
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__') @@ -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") |