diff options
-rw-r--r-- | CHANGES.rst | 2 | ||||
-rw-r--r-- | README.rst | 2 | ||||
-rw-r--r-- | coverage/debug.py | 1 | ||||
-rw-r--r-- | coverage/env.py | 3 | ||||
-rw-r--r-- | coverage/execfile.py | 7 | ||||
-rw-r--r-- | coverage/files.py | 7 | ||||
-rw-r--r-- | doc/index.rst | 2 | ||||
-rw-r--r-- | setup.py | 1 | ||||
-rw-r--r-- | tests/test_execfile.py | 14 | ||||
-rw-r--r-- | tests/test_process.py | 19 |
10 files changed, 45 insertions, 13 deletions
diff --git a/CHANGES.rst b/CHANGES.rst index af1e5788..4eec16e9 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -32,6 +32,8 @@ Unreleased registers `numbits_to_nums` for use in SQLite queries. Thanks, Simon Willison. +- Python 3.9a1 is supported. + .. _issue 745: https://github.com/nedbat/coveragepy/issues/745 .. _issue 838: https://github.com/nedbat/coveragepy/issues/838 @@ -20,7 +20,7 @@ library to determine which lines are executable, and which have been executed. Coverage.py runs on many versions of Python: * CPython 2.7. -* CPython 3.5 through 3.8. +* CPython 3.5 through 3.9 alpha 1. * PyPy2 7.0 and PyPy3 7.0. Documentation is on `Read the Docs`_. Code repository and issue tracker are on diff --git a/coverage/debug.py b/coverage/debug.py index c713978a..c516ac5b 100644 --- a/coverage/debug.py +++ b/coverage/debug.py @@ -215,6 +215,7 @@ def simplify(v): # pragma: debugging def pp(v): # pragma: debugging """Debug helper to pretty-print data, including SimpleNamespace objects.""" + # Might not be needed in 3.9+ pprint.pprint(simplify(v)) diff --git a/coverage/env.py b/coverage/env.py index bb335ab3..0d4642ef 100644 --- a/coverage/env.py +++ b/coverage/env.py @@ -78,6 +78,9 @@ class PYBEHAVIOR(object): # Are while-true loops optimized into absolute jumps with no loop setup? nix_while_true = (PYVERSION >= (3, 8)) + # Python 3.9a1 made sys.argv[0] and other reported files absolute paths. + report_absolute_files = (PYVERSION >= (3, 9)) + # Coverage.py specifics. # Are we using the C-implemented trace function? diff --git a/coverage/execfile.py b/coverage/execfile.py index 5527d10a..7ac36dcf 100644 --- a/coverage/execfile.py +++ b/coverage/execfile.py @@ -13,6 +13,7 @@ import types from coverage import env from coverage.backward import BUILTINS from coverage.backward import PYC_MAGIC_NUMBER, imp, importlib_util_find_spec +from coverage.files import python_reported_file from coverage.misc import CoverageException, ExceptionDuringRun, NoCode, NoSource, isolate_module from coverage.phystokens import compile_unicode from coverage.python import get_python_source @@ -158,6 +159,7 @@ class PyRunner(object): except ImportError: pass else: + try_filename = python_reported_file(try_filename) self.spec = importlib.machinery.ModuleSpec("__main__", None, origin=try_filename) self.spec.has_location = True self.package = "" @@ -167,6 +169,9 @@ class PyRunner(object): if env.PY3: self.loader = DummyLoader("__main__") + self.args[0] = python_reported_file(self.args[0]) + self.arg0 = python_reported_file(self.arg0) + if self.modulename is None: self.modulename = '__main__' @@ -179,7 +184,7 @@ class PyRunner(object): top_file = inspect.stack()[-1][0].f_code.co_filename if os.path.abspath(sys.path[0]) == os.path.abspath(os.path.dirname(top_file)): # Set sys.path correctly. - sys.path[0] = path0 + sys.path[0] = python_reported_file(path0) def run(self): """Run the Python code!""" diff --git a/coverage/files.py b/coverage/files.py index dc8c248f..2836d4e5 100644 --- a/coverage/files.py +++ b/coverage/files.py @@ -172,6 +172,13 @@ def abs_file(filename): return path +def python_reported_file(filename): + """Return the string as Python would describe this file name.""" + if env.PYBEHAVIOR.report_absolute_files: + filename = os.path.abspath(filename) + return filename + + RELATIVE_DIR = None CANONICAL_FILENAME_CACHE = None set_relative_directory() diff --git a/doc/index.rst b/doc/index.rst index 3e40ce2c..5e32e08a 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -31,7 +31,7 @@ not. The latest version is coverage.py 5.0b1, released November 11, 2019. It is supported on: - * Python versions 2.7, 3.5, 3.6, 3.7, and 3.8. + * Python versions 2.7, 3.5, 3.6, 3.7, 3.8, and 3.9 alpha. * PyPy2 7.2.0 and PyPy3 7.2.0. @@ -32,6 +32,7 @@ Programming Language :: Python :: 3.5 Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 +Programming Language :: Python :: 3.9 Programming Language :: Python :: Implementation :: CPython Programming Language :: Python :: Implementation :: PyPy Topic :: Software Development :: Quality Assurance diff --git a/tests/test_execfile.py b/tests/test_execfile.py index 7ced605a..e3d62005 100644 --- a/tests/test_execfile.py +++ b/tests/test_execfile.py @@ -14,6 +14,7 @@ import sys from coverage import env from coverage.backward import binary_bytes from coverage.execfile import run_python_file, run_python_module +from coverage.files import python_reported_file from coverage.misc import NoCode, NoSource from tests.coveragetest import CoverageTest, TESTS_DIR, UsingModulesMixin @@ -45,7 +46,7 @@ class RunFileTest(CoverageTest): self.assertEqual(mod_globs['__main__.DATA'], "xyzzy") # Argv should have the proper values. - self.assertEqual(mod_globs['argv0'], TRY_EXECFILE) + self.assertEqual(mod_globs['argv0'], python_reported_file(TRY_EXECFILE)) self.assertEqual(mod_globs['argv1-n'], ["arg1", "arg2"]) # __builtins__ should have the right values, like open(). @@ -84,7 +85,9 @@ class RunFileTest(CoverageTest): self.assertEqual(self.stdout(), "a is 1\n") def test_no_such_file(self): - with self.assertRaisesRegex(NoSource, "No file to run: 'xyzzy.py'"): + path = python_reported_file('xyzzy.py') + msg = re.escape("No file to run: '{}'".format(path)) + with self.assertRaisesRegex(NoSource, msg): run_python_file(["xyzzy.py"]) def test_directory_with_main(self): @@ -156,7 +159,9 @@ class RunPycFileTest(CoverageTest): os.remove(pycfile) def test_no_such_pyc_file(self): - with self.assertRaisesRegex(NoCode, "No file to run: 'xyzzy.pyc'"): + path = python_reported_file('xyzzy.pyc') + msg = re.escape("No file to run: '{}'".format(path)) + with self.assertRaisesRegex(NoCode, msg): run_python_file(["xyzzy.pyc"]) def test_running_py_from_binary(self): @@ -166,8 +171,9 @@ class RunPycFileTest(CoverageTest): with open(bf, "wb") as f: f.write(b'\x7fELF\x02\x01\x01\x00\x00\x00') + path = python_reported_file('binary') msg = ( - r"Couldn't run 'binary' as Python code: " + re.escape("Couldn't run '{}' as Python code: ".format(path)) + r"(TypeError|ValueError): " r"(" r"compile\(\) expected string without null bytes" # for py2 diff --git a/tests/test_process.py b/tests/test_process.py index 06e429dd..e9e19e8a 100644 --- a/tests/test_process.py +++ b/tests/test_process.py @@ -18,6 +18,7 @@ import pytest import coverage from coverage import env from coverage.data import line_counts +from coverage.files import python_reported_file from coverage.misc import output_encoding from tests.coveragetest import CoverageTest @@ -472,9 +473,10 @@ class ProcessTest(CoverageTest): self.assertMultiLineEqual(out, out2) # But also make sure that the output is what we expect. - self.assertIn('File "throw.py", line 5, in f2', out) + path = python_reported_file('throw.py') + msg = 'File "{}", line 5,? in f2'.format(re.escape(path)) + self.assertRegex(out, msg) self.assertIn('raise Exception("hey!")', out) - self.assertNotIn('coverage', out) self.assertEqual(status, 1) def test_code_exits(self): @@ -582,9 +584,13 @@ class ProcessTest(CoverageTest): out = self.run_command("coverage html") self.assertEqual(out.count("Module xyzzy was never imported."), 0) - def test_warnings_if_never_run(self): + def test_warns_if_never_run(self): + # Note: the name of the function can't have "warning" in it, or the + # absolute path of the file will have "warning" in it, and an assertion + # will fail. out = self.run_command("coverage run i_dont_exist.py") - self.assertIn("No file to run: 'i_dont_exist.py'", out) + path = python_reported_file('i_dont_exist.py') + self.assertIn("No file to run: '{}'".format(path), out) self.assertNotIn("warning", out) self.assertNotIn("Exception", out) @@ -1321,12 +1327,13 @@ class YankedDirectoryTest(CoverageTest): def test_removing_directory_with_error(self): self.make_file("bug806.py", self.BUG_806) out = self.run_command("coverage run bug806.py") + path = python_reported_file('bug806.py') self.assertEqual(out, textwrap.dedent("""\ Traceback (most recent call last): - File "bug806.py", line 8, in <module> + File "{}", line 8, in <module> print(sys.argv[1]) IndexError: list index out of range - """)) + """.format(path))) def possible_pth_dirs(): |