diff --git a/CHANGES.rst b/CHANGES.rst index ff40f698c..139d4d5ab 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -23,7 +23,11 @@ upgrading your version of coverage.py. Unreleased ---------- -Nothing yet. +- Fix: coverage used to fail when measuring code using :func:`runpy.run_path + ` with a :class:`Path ` argument. + This is now fixed, thanks to `Ask Hjorth Larsen `_. + +.. _pull 1819: https://github.com/nedbat/coveragepy/pull/1819/files .. scriv-start-here diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 728f2fb1d..e44920ce2 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -25,6 +25,7 @@ Artem Dayneko Arthur Deygin Arthur Rio Asher Foa +Ask Hjorth Larsen Ben Carlsson Ben Finney Benjamin Parzella diff --git a/coverage/inorout.py b/coverage/inorout.py index 5ea29edf1..4df54b2b4 100644 --- a/coverage/inorout.py +++ b/coverage/inorout.py @@ -321,7 +321,8 @@ def nope(disp: TFileDisposition, reason: str) -> TFileDisposition: # co_filename value. dunder_file = frame.f_globals and frame.f_globals.get("__file__") if dunder_file: - filename = source_for_file(dunder_file) + # Danger: __file__ can (rarely?) be of type Path. + filename = source_for_file(str(dunder_file)) if original_filename and not original_filename.startswith("<"): orig = os.path.basename(original_filename) if orig != os.path.basename(filename): diff --git a/tests/test_python.py b/tests/test_python.py index ee0268ffc..6a8362919 100644 --- a/tests/test_python.py +++ b/tests/test_python.py @@ -63,3 +63,24 @@ def test_source_for_file_windows(tmp_path: pathlib.Path) -> None: # If both pyw and py exist, py is preferred a_py.write_text("") assert source_for_file(src + 'c') == src + + +class RunpyTest(CoverageTest): + """Tests using runpy.""" + + @pytest.mark.parametrize("convert_to", ["str", "Path"]) + def test_runpy_path(self, convert_to: str) -> None: + # Ensure runpy.run_path(path) works when path is pathlib.Path or str. + # + # runpy.run_path(pathlib.Path(...)) causes __file__ to be a Path, + # which may make source_for_file() stumble (#1819) with: + # + # AttributeError: 'PosixPath' object has no attribute 'endswith' + + self.check_coverage(f"""\ + import runpy + from pathlib import Path + pyfile = Path('script.py') + pyfile.write_text('') + runpy.run_path({convert_to}(pyfile)) + """)