From 207bab0abe5ead99fa5549b4fa10498478dc92ad Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Thu, 26 Dec 2024 12:04:33 -0500 Subject: [PATCH 01/90] build: bump version --- CHANGES.rst | 6 ++++++ coverage/version.py | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index e5bfd2f0b..0f5fee55a 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -20,6 +20,12 @@ upgrading your version of coverage.py. .. Version 9.8.1 — 2027-07-27 .. -------------------------- +Unreleased +---------- + +Nothing yet. + + .. start-releases .. _changes_7-6-10: diff --git a/coverage/version.py b/coverage/version.py index a76371e77..68460a53e 100644 --- a/coverage/version.py +++ b/coverage/version.py @@ -8,8 +8,8 @@ # version_info: same semantics as sys.version_info. # _dev: the .devN suffix if any. -version_info = (7, 6, 10, "final", 0) -_dev = 0 +version_info = (7, 6, 11, "alpha", 0) +_dev = 1 def _make_version( From 2ab61373d5bf4090cedc2387aeb20f97d05c5824 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Thu, 26 Dec 2024 12:20:19 -0500 Subject: [PATCH 02/90] build: include the new version number in the bump message --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 943d40ec4..5ece540ca 100644 --- a/Makefile +++ b/Makefile @@ -235,7 +235,7 @@ update_rtd: #: Update ReadTheDocs with the versions to show bump_version: #: Edit sources to bump the version after a release (see howto.txt). git switch -c nedbat/bump-version python igor.py bump_version - git commit -a -m "build: bump version" + git commit -a -m "build: bump version to $$(python setup.py --version | sed 's/a.*//')" git push -u origin @ From 9b1ab979ea1bb4cb3aab858204a603d87c84a985 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Fri, 27 Dec 2024 07:46:26 -0500 Subject: [PATCH 03/90] test: add a test for #1775 --- tests/test_parser.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/test_parser.py b/tests/test_parser.py index 5c3042816..4e4670be8 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -1101,6 +1101,24 @@ def test_final_wildcard(self) -> None: # 4-6 isn't a possible arc, so the description is generic. assert parser.missing_arc_description(4, 6) == "line 4 didn't jump to line 6" + def test_missing_arc_descriptions_bug1775(self) -> None: + # Bug: the `if x == 2:` line was marked partial with a message of: + # line 6 didn't return from function 'func', because the return on line 4 wasn't executed + # At some point it changed to "didn't jump to the function exit," which + # is close enough. These situations are hard to describe precisely. + parser = self.parse_text("""\ + def func(): + x = 2 + try: + return 4 + finally: + if x == 2: # line 6 + print("x is 2") + + func() + """) + assert parser.missing_arc_description(6, -1) == "line 6 didn't jump to the function exit" + class ParserFileTest(CoverageTest): """Tests for coverage.py's code parsing from files.""" From 10d375b45bce2064ab89938da44eb9287a7ac613 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Fri, 27 Dec 2024 13:17:56 -0500 Subject: [PATCH 04/90] refactor: remove a version-conditioned macro from the C tracer --- coverage/ctracer/tracer.c | 20 ++++++++++---------- coverage/ctracer/util.h | 7 ------- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/coverage/ctracer/tracer.c b/coverage/ctracer/tracer.c index 8deedb37f..91813074a 100644 --- a/coverage/ctracer/tracer.c +++ b/coverage/ctracer/tracer.c @@ -359,7 +359,7 @@ CTracer_handle_call(CTracer *self, PyFrameObject *frame) } /* Check if we should trace this line. */ - filename = MyFrame_GetCode(frame)->co_filename; + filename = PyFrame_GetCode(frame)->co_filename; disposition = PyDict_GetItem(self->should_trace_cache, filename); if (disposition == NULL) { if (PyErr_Occurred()) { @@ -554,7 +554,7 @@ CTracer_handle_call(CTracer *self, PyFrameObject *frame) * The current opcode is guaranteed to be RESUME. The argument * determines what kind of resume it is. */ - pCode = MyCode_GetCode(MyFrame_GetCode(frame)); + pCode = MyCode_GetCode(PyFrame_GetCode(frame)); real_call = (PyBytes_AS_STRING(pCode)[MyFrame_GetLasti(frame) + 1] == 0); #else // f_lasti is -1 for a true call, and a real byte offset for a generator re-entry. @@ -562,7 +562,7 @@ CTracer_handle_call(CTracer *self, PyFrameObject *frame) #endif if (real_call) { - self->pcur_entry->last_line = -MyFrame_GetCode(frame)->co_firstlineno; + self->pcur_entry->last_line = -PyFrame_GetCode(frame)->co_firstlineno; } else { self->pcur_entry->last_line = PyFrame_GetLineNumber(frame); @@ -649,7 +649,7 @@ CTracer_handle_line(CTracer *self, PyFrameObject *frame) STATS( self->stats.lines++; ) if (self->pdata_stack->depth >= 0) { - SHOWLOG(PyFrame_GetLineNumber(frame), MyFrame_GetCode(frame)->co_filename, "line"); + SHOWLOG(PyFrame_GetLineNumber(frame), PyFrame_GetCode(frame)->co_filename, "line"); if (self->pcur_entry->file_data) { int lineno_from = -1; int lineno_to = -1; @@ -727,7 +727,7 @@ CTracer_handle_return(CTracer *self, PyFrameObject *frame) self->pcur_entry = &self->pdata_stack->stack[self->pdata_stack->depth]; if (self->tracing_arcs && self->pcur_entry->file_data) { BOOL real_return = FALSE; - pCode = MyCode_GetCode(MyFrame_GetCode(frame)); + pCode = MyCode_GetCode(PyFrame_GetCode(frame)); int lasti = MyFrame_GetLasti(frame); Py_ssize_t code_size = PyBytes_GET_SIZE(pCode); unsigned char * code_bytes = (unsigned char *)PyBytes_AS_STRING(pCode); @@ -759,7 +759,7 @@ CTracer_handle_return(CTracer *self, PyFrameObject *frame) real_return = !(is_yield || is_yield_from); #endif if (real_return) { - int first = MyFrame_GetCode(frame)->co_firstlineno; + int first = PyFrame_GetCode(frame)->co_firstlineno; if (CTracer_record_pair(self, self->pcur_entry->last_line, -first) < 0) { goto error; } @@ -782,7 +782,7 @@ CTracer_handle_return(CTracer *self, PyFrameObject *frame) } /* Pop the stack. */ - SHOWLOG(PyFrame_GetLineNumber(frame), MyFrame_GetCode(frame)->co_filename, "return"); + SHOWLOG(PyFrame_GetLineNumber(frame), PyFrame_GetCode(frame)->co_filename, "return"); self->pdata_stack->depth--; self->pcur_entry = &self->pdata_stack->stack[self->pdata_stack->depth]; } @@ -824,13 +824,13 @@ CTracer_trace(CTracer *self, PyFrameObject *frame, int what, PyObject *arg_unuse if (what <= (int)(sizeof(what_sym)/sizeof(const char *))) { w = what_sym[what]; } - ascii = PyUnicode_AsASCIIString(MyFrame_GetCode(frame)->co_filename); + ascii = PyUnicode_AsASCIIString(PyFrame_GetCode(frame)->co_filename); printf("%x trace: f:%x %s @ %s %d\n", (int)self, (int)frame, what_sym[what], PyBytes_AS_STRING(ascii), PyFrame_GetLineNumber(frame)); Py_DECREF(ascii); #endif #if TRACE_LOG - ascii = PyUnicode_AsASCIIString(MyFrame_GetCode(frame)->co_filename); + ascii = PyUnicode_AsASCIIString(PyFrame_GetCode(frame)->co_filename); if (strstr(PyBytes_AS_STRING(ascii), start_file) && PyFrame_GetLineNumber(frame) == start_line) { logging = TRUE; } @@ -926,7 +926,7 @@ CTracer_call(CTracer *self, PyObject *args, PyObject *kwds) } #if WHAT_LOG - ascii = PyUnicode_AsASCIIString(MyFrame_GetCode(frame)->co_filename); + ascii = PyUnicode_AsASCIIString(PyFrame_GetCode(frame)->co_filename); printf("pytrace: %s @ %s %d\n", what_sym[what], PyBytes_AS_STRING(ascii), PyFrame_GetLineNumber(frame)); Py_DECREF(ascii); #endif diff --git a/coverage/ctracer/util.h b/coverage/ctracer/util.h index 473db2080..94591e0d2 100644 --- a/coverage/ctracer/util.h +++ b/coverage/ctracer/util.h @@ -41,13 +41,6 @@ #define MyFrame_SetTrace(f, obj) {Py_INCREF(obj); Py_XSETREF((f)->f_trace, (PyObject*)(obj));} #endif -// Access f_code should be done through a helper starting in 3.9. -#if PY_VERSION_HEX >= 0x03090000 -#define MyFrame_GetCode(f) (PyFrame_GetCode(f)) -#else -#define MyFrame_GetCode(f) ((f)->f_code) -#endif - #if PY_VERSION_HEX >= 0x030B00B1 #define MyCode_GetCode(co) (PyCode_GetCode(co)) #define MyCode_FreeCode(code) Py_XDECREF(code) From 57ea8a13deff247e5929c6f63aeb9e8cee011dc2 Mon Sep 17 00:00:00 2001 From: Nick Drozd Date: Sun, 5 Jan 2025 07:38:24 -0600 Subject: [PATCH 05/90] type add some typing changes required by Mypyc (#1658) * Add Final annotations * Add TLineNo annotations * Use single assignment for class var --- coverage/config.py | 5 +++-- coverage/debug.py | 6 +++--- coverage/env.py | 9 +++------ coverage/parser.py | 2 +- coverage/results.py | 2 +- 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/coverage/config.py b/coverage/config.py index 357fc5af0..748ad425a 100644 --- a/coverage/config.py +++ b/coverage/config.py @@ -13,7 +13,7 @@ import re from typing import ( - Any, Callable, Union, + Any, Callable, Final, Union, ) from collections.abc import Iterable @@ -360,7 +360,8 @@ def copy(self) -> CoverageConfig: """Return a copy of the configuration.""" return copy.deepcopy(self) - CONCURRENCY_CHOICES = {"thread", "gevent", "greenlet", "eventlet", "multiprocessing"} + CONCURRENCY_CHOICES: Final[set[str]] = { + "thread", "gevent", "greenlet", "eventlet", "multiprocessing"} CONFIG_FILE_OPTIONS = [ # These are *args for _set_attr_from_config_option: diff --git a/coverage/debug.py b/coverage/debug.py index cf9310dc5..2e578a3d4 100644 --- a/coverage/debug.py +++ b/coverage/debug.py @@ -21,7 +21,7 @@ from typing import ( overload, - Any, Callable, IO, + Any, Callable, Final, IO, ) from collections.abc import Iterable, Iterator, Mapping @@ -467,8 +467,8 @@ def get_one( # a process-wide singleton. So stash it in sys.modules instead of # on a class attribute. Yes, this is aggressively gross. - SYS_MOD_NAME = "$coverage.debug.DebugOutputFile.the_one" - SINGLETON_ATTR = "the_one_and_is_interim" + SYS_MOD_NAME: Final[str] = "$coverage.debug.DebugOutputFile.the_one" + SINGLETON_ATTR: Final[str] = "the_one_and_is_interim" @classmethod def _set_singleton_data(cls, the_one: DebugOutputFile, interim: bool) -> None: diff --git a/coverage/env.py b/coverage/env.py index 0fb8683c5..0944d64d5 100644 --- a/coverage/env.py +++ b/coverage/env.py @@ -9,7 +9,7 @@ import platform import sys -from typing import Any +from typing import Any, Final from collections.abc import Iterable # debug_info() at the bottom wants to show all the globals, but not imports. @@ -53,10 +53,7 @@ class PYBEHAVIOR: # Is "if not __debug__" optimized away? The exact details have changed # across versions. - if pep626: - optimize_if_not_debug = 1 - else: - optimize_if_not_debug = 2 + optimize_if_not_debug = 1 if pep626 else 2 # 3.7 changed how functions with only docstrings are numbered. docstring_only_function = (not PYPY) and (PYVERSION <= (3, 10)) @@ -148,7 +145,7 @@ class PYBEHAVIOR: soft_keywords = (PYVERSION >= (3, 10)) # PEP669 Low Impact Monitoring: https://peps.python.org/pep-0669/ - pep669 = bool(getattr(sys, "monitoring", None)) + pep669: Final[bool] = bool(getattr(sys, "monitoring", None)) # Where does frame.f_lasti point when yielding from a generator? # It used to point at the YIELD, in 3.13 it points at the RESUME, diff --git a/coverage/parser.py b/coverage/parser.py index fb74ea9e0..e5d9adcde 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -466,7 +466,7 @@ def _line_numbers(self) -> Iterable[TLineNo]: byte_increments = self.code.co_lnotab[0::2] line_increments = self.code.co_lnotab[1::2] - last_line_num = None + last_line_num: TLineNo | None = None line_num = self.code.co_firstlineno byte_num = 0 for byte_incr, line_incr in zip(byte_increments, line_increments): diff --git a/coverage/results.py b/coverage/results.py index a9bde97c3..74de21dbe 100644 --- a/coverage/results.py +++ b/coverage/results.py @@ -343,7 +343,7 @@ def _line_ranges( lines = sorted(lines) pairs = [] - start = None + start: TLineNo | None = None lidx = 0 for stmt in statements: if lidx >= len(lines): From a6b8ccc5f3af142f4826ea0551afcf322f3b3996 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 5 Jan 2025 08:57:08 -0500 Subject: [PATCH 06/90] docs: thanks Nick Drozd for typing improvements --- CONTRIBUTORS.txt | 1 + coverage/config.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 1b51c9e0e..186608d1b 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -174,6 +174,7 @@ Naveen Srinivasan Naveen Yadav Neil Pilgrim Nicholas Nadeau +Nick Drozd Nikita Bloshchanevich Nikita Sobolev Nils Kattenbeck diff --git a/coverage/config.py b/coverage/config.py index 748ad425a..532357177 100644 --- a/coverage/config.py +++ b/coverage/config.py @@ -361,7 +361,8 @@ def copy(self) -> CoverageConfig: return copy.deepcopy(self) CONCURRENCY_CHOICES: Final[set[str]] = { - "thread", "gevent", "greenlet", "eventlet", "multiprocessing"} + "thread", "gevent", "greenlet", "eventlet", "multiprocessing" + } CONFIG_FILE_OPTIONS = [ # These are *args for _set_attr_from_config_option: From 08d0b4976a3bafbaf8d5971d393e037a7b3ffef5 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 5 Jan 2025 08:59:05 -0500 Subject: [PATCH 07/90] type: properly type the [paths] configuration --- coverage/config.py | 12 +++++++++--- coverage/types.py | 4 ++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/coverage/config.py b/coverage/config.py index 532357177..a8366d199 100644 --- a/coverage/config.py +++ b/coverage/config.py @@ -13,7 +13,7 @@ import re from typing import ( - Any, Callable, Final, Union, + Any, Callable, Final, Mapping, Union, ) from collections.abc import Iterable @@ -470,7 +470,13 @@ def set_option(self, option_name: str, value: TConfigValueIn | TConfigSectionIn) """ # Special-cased options. if option_name == "paths": - self.paths = value # type: ignore[assignment] + # This is ugly, but type-checks and ensures the values are close + # to right. + self.paths = {} + assert isinstance(value, Mapping) + for k, v in value.items(): + assert isinstance(v, Iterable) + self.paths[k] = list(v) return # Check all the hard-coded options. @@ -501,7 +507,7 @@ def get_option(self, option_name: str) -> TConfigValueOut | None: """ # Special-cased options. if option_name == "paths": - return self.paths # type: ignore[return-value] + return self.paths # Check all the hard-coded options. for option_spec in self.CONFIG_FILE_OPTIONS: diff --git a/coverage/types.py b/coverage/types.py index bcf8396d6..ac1fc4c59 100644 --- a/coverage/types.py +++ b/coverage/types.py @@ -125,8 +125,8 @@ def get_stats(self) -> dict[str, int] | None: ## Configuration # One value read from a config file. -TConfigValueIn = Optional[Union[bool, int, float, str, Iterable[str]]] -TConfigValueOut = Optional[Union[bool, int, float, str, list[str]]] +TConfigValueIn = Optional[Union[bool, int, float, str, Iterable[str], Mapping[str, Iterable[str]]]] +TConfigValueOut = Optional[Union[bool, int, float, str, list[str], dict[str, list[str]]]] # An entire config section, mapping option names to values. TConfigSectionIn = Mapping[str, TConfigValueIn] TConfigSectionOut = Mapping[str, TConfigValueOut] From b3b256da9d5ade47cf8a8ed1b6b5805513293c73 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 5 Jan 2025 08:59:35 -0500 Subject: [PATCH 08/90] type: mypy --strict --- coverage/data.py | 2 +- tests/test_config.py | 12 ++++++++++-- tests/test_files.py | 4 ++-- tests/test_plugins.py | 2 +- tox.ini | 4 ++-- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/coverage/data.py b/coverage/data.py index 9baab8edd..8f4346007 100644 --- a/coverage/data.py +++ b/coverage/data.py @@ -23,7 +23,7 @@ from coverage.exceptions import CoverageException, NoDataError from coverage.files import PathAliases from coverage.misc import Hasher, file_be_gone, human_sorted, plural -from coverage.sqldata import CoverageData +from coverage.sqldata import CoverageData as CoverageData # pylint: disable=useless-import-alias def line_counts(data: CoverageData, fullpath: bool = False) -> dict[str, int]: diff --git a/tests/test_config.py b/tests/test_config.py index 062c69324..e0a975652 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -313,7 +313,11 @@ def expanduser(s: str) -> str: s = s.replace("~joe/", "/Users/joe/") return s - with mock.patch.object(coverage.config.os.path, 'expanduser', new=expanduser): + with mock.patch.object( + coverage.config.os.path, # type: ignore[attr-defined] + 'expanduser', + new=expanduser + ): cov = coverage.Coverage() assert cov.config.data_file == "/Users/me/data.file" assert cov.config.html_dir == "/Users/joe/html_dir" @@ -352,7 +356,11 @@ def expanduser(s: str) -> str: s = s.replace("~joe/", "/Users/joe/") return s - with mock.patch.object(coverage.config.os.path, 'expanduser', new=expanduser): + with mock.patch.object( + coverage.config.os.path, # type: ignore[attr-defined] + 'expanduser', + new=expanduser + ): cov = coverage.Coverage() assert cov.config.data_file == "/Users/me/data.file" assert cov.config.html_dir == "/Users/joe/html_dir" diff --git a/tests/test_files.py b/tests/test_files.py index 7a56aac30..50e69e647 100644 --- a/tests/test_files.py +++ b/tests/test_files.py @@ -82,8 +82,8 @@ def test_canonical_filename_ensure_cache_hit(self) -> None: ], ) def test_relative_dir_for_root(self, curdir: str, sep: str) -> None: - with mock.patch.object(files.os, 'curdir', new=curdir): - with mock.patch.object(files.os, 'sep', new=sep): + with mock.patch.object(files.os, 'curdir', new=curdir): # type: ignore[attr-defined] + with mock.patch.object(files.os, 'sep', new=sep): # type: ignore[attr-defined] with mock.patch('coverage.files.os.path.normcase', return_value=curdir): files.set_relative_directory() assert files.relative_directory() == curdir diff --git a/tests/test_plugins.py b/tests/test_plugins.py index b3c8cd6f6..c4412090d 100644 --- a/tests/test_plugins.py +++ b/tests/test_plugins.py @@ -17,7 +17,7 @@ import coverage from coverage import Coverage -from coverage.control import Plugins +from coverage.plugin_support import Plugins from coverage.data import line_counts, sorted_lines from coverage.exceptions import CoverageWarning, NoSource, PluginError from coverage.misc import import_local_file diff --git a/tox.ini b/tox.ini index 2db2f4e62..57919d730 100644 --- a/tox.ini +++ b/tox.ini @@ -116,8 +116,8 @@ setenv = commands = # PYVERSIONS - mypy --python-version=3.9 --exclude=sysmon {env:TYPEABLE} - mypy --python-version=3.13 {env:TYPEABLE} + mypy --python-version=3.9 --strict --exclude=sysmon {env:TYPEABLE} + mypy --python-version=3.13 --strict {env:TYPEABLE} [gh] # https://pypi.org/project/tox-gh/ From ea8ae17b5a74d8925a336ae52688f5dfdcd70647 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 5 Jan 2025 09:02:25 -0500 Subject: [PATCH 09/90] chore: make upgrade doc_upgrade --- doc/requirements.pip | 4 ++-- requirements/dev.pip | 4 ++-- requirements/kit.pip | 2 +- requirements/mypy.pip | 4 ++-- requirements/pip.pip | 2 +- requirements/pytest.pip | 2 +- requirements/tox.pip | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/doc/requirements.pip b/doc/requirements.pip index 20b13366e..bc714515f 100644 --- a/doc/requirements.pip +++ b/doc/requirements.pip @@ -6,7 +6,7 @@ # alabaster==1.0.0 # via sphinx -anyio==4.7.0 +anyio==4.8.0 # via # starlette # watchfiles @@ -103,7 +103,7 @@ sphinxcontrib-serializinghtml==2.0.0 # via sphinx sphinxcontrib-spelling==8.0.1 # via -r doc/requirements.in -starlette==0.43.0 +starlette==0.45.2 # via sphinx-autobuild stevedore==5.4.0 # via doc8 diff --git a/requirements/dev.pip b/requirements/dev.pip index 3dd9143fc..afbce3046 100644 --- a/requirements/dev.pip +++ b/requirements/dev.pip @@ -49,7 +49,7 @@ flaky==3.8.1 # via -r /Users/ned/coverage/trunk/requirements/pytest.in greenlet==3.1.1 # via -r requirements/dev.in -hypothesis==6.123.1 +hypothesis==6.123.2 # via -r /Users/ned/coverage/trunk/requirements/pytest.in idna==3.10 # via requests @@ -181,7 +181,7 @@ urwid==2.6.16 # urwid-readline urwid-readline==0.15.1 # via pudb -virtualenv==20.28.0 +virtualenv==20.28.1 # via # -r /Users/ned/coverage/trunk/requirements/pip.in # tox diff --git a/requirements/kit.pip b/requirements/kit.pip index 92c1f8a9e..5d4af4ea4 100644 --- a/requirements/kit.pip +++ b/requirements/kit.pip @@ -4,7 +4,7 @@ # # make upgrade # -auditwheel==6.1.0 +auditwheel==6.2.0 # via -r requirements/kit.in backports-tarfile==1.2.0 # via jaraco-context diff --git a/requirements/mypy.pip b/requirements/mypy.pip index fdc5adcad..5bc393e8a 100644 --- a/requirements/mypy.pip +++ b/requirements/mypy.pip @@ -16,11 +16,11 @@ execnet==2.1.1 # via pytest-xdist flaky==3.8.1 # via -r /Users/ned/coverage/trunk/requirements/pytest.in -hypothesis==6.123.1 +hypothesis==6.123.2 # via -r /Users/ned/coverage/trunk/requirements/pytest.in iniconfig==2.0.0 # via pytest -mypy==1.14.0 +mypy==1.14.1 # via -r requirements/mypy.in mypy-extensions==1.0.0 # via mypy diff --git a/requirements/pip.pip b/requirements/pip.pip index ca05cfba6..fdd75d2dd 100644 --- a/requirements/pip.pip +++ b/requirements/pip.pip @@ -10,7 +10,7 @@ filelock==3.16.1 # via virtualenv platformdirs==4.3.6 # via virtualenv -virtualenv==20.28.0 +virtualenv==20.28.1 # via -r requirements/pip.in # The following packages are considered to be unsafe in a requirements file: diff --git a/requirements/pytest.pip b/requirements/pytest.pip index 107444ce1..9d221de45 100644 --- a/requirements/pytest.pip +++ b/requirements/pytest.pip @@ -16,7 +16,7 @@ execnet==2.1.1 # via pytest-xdist flaky==3.8.1 # via -r requirements/pytest.in -hypothesis==6.123.1 +hypothesis==6.123.2 # via -r requirements/pytest.in iniconfig==2.0.0 # via pytest diff --git a/requirements/tox.pip b/requirements/tox.pip index eae58f487..12fb73b31 100644 --- a/requirements/tox.pip +++ b/requirements/tox.pip @@ -42,5 +42,5 @@ tox-gh==1.4.4 # via -r requirements/tox.in typing-extensions==4.12.2 # via tox -virtualenv==20.28.0 +virtualenv==20.28.1 # via tox From 4fa393a3453642754f79d084edabb9718d8483cf Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 4 Jan 2025 10:37:31 -0500 Subject: [PATCH 10/90] test: this test is about context merging, not the precise arcs --- tests/test_context.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tests/test_context.py b/tests/test_context.py index 616a3d609..5c0618c02 100644 --- a/tests/test_context.py +++ b/tests/test_context.py @@ -48,7 +48,6 @@ def test_static_context(self) -> None: """ LINES = [1, 2, 4] - ARCS = [(-1, 1), (1, 2), (2, 4), (4, -1)] def run_red_blue(self, **options: TCovKwargs) -> tuple[CoverageData, CoverageData]: """Run red.py and blue.py, and return their CoverageData objects.""" @@ -93,6 +92,14 @@ def assert_combined_lines(filename: str, context: str, lines: list[TLineNo]) -> def test_combining_arc_contexts(self) -> None: red_data, blue_data = self.run_red_blue(branch=True) + + # The exact arc data changes depending on the core and the version. + # Extract the red arc data for comparisons below. + arc_data = red_data.arcs( + next(fname for fname in red_data.measured_files() if "red.py" in fname) + ) + assert arc_data is not None + for datas in [[red_data, blue_data], [blue_data, red_data]]: combined = CoverageData(suffix="combined") for data in datas: @@ -121,10 +128,10 @@ def assert_combined_arcs(filename: str, context: str, lines: list[TArc]) -> None combined.set_query_context(context) assert combined.arcs(filename) == lines - assert_combined_arcs(fred, 'red', self.ARCS) + assert_combined_arcs(fred, 'red', arc_data) assert_combined_arcs(fred, 'blue', []) assert_combined_arcs(fblue, 'red', []) - assert_combined_arcs(fblue, 'blue', self.ARCS) + assert_combined_arcs(fblue, 'blue', arc_data) @pytest.mark.skipif(not testenv.DYN_CONTEXTS, reason="No dynamic contexts with this core") From 40c40b6e0f5aba89b90c18f88d4585940b6be8e0 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Fri, 10 Jan 2025 20:29:38 +0800 Subject: [PATCH 11/90] build: add py3-none-any wheels to the distribution artifacts (#1914) * Add an option to disable compilation of the binary wheel. * Modify sdist workflow to also produce a py3-none-any wheel. * Correct the reference to the non-binary job. --- .github/workflows/kit.yml | 26 ++++++++++++++------------ setup.py | 6 ++++-- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/.github/workflows/kit.yml b/.github/workflows/kit.yml index b9ecbbf57..67fbc3fe2 100644 --- a/.github/workflows/kit.yml +++ b/.github/workflows/kit.yml @@ -162,7 +162,7 @@ jobs: run: | python -m pip install -r requirements/kit.pip - - name: "Build wheels" + - name: "Build binary wheels" env: CIBW_BUILD: ${{ matrix.py }}*-* CIBW_ARCHS: ${{ matrix.arch }} @@ -173,7 +173,7 @@ jobs: run: | python -m cibuildwheel --output-dir wheelhouse - - name: "List wheels" + - name: "List binary wheels" run: | ls -al wheelhouse/ @@ -181,15 +181,15 @@ jobs: run: | python -m twine check wheelhouse/* - - name: "Upload wheels" + - name: "Upload binary wheels" uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 with: name: dist-${{ env.MATRIX_ID }} path: wheelhouse/*.whl retention-days: 7 - sdist: - name: "Source distribution" + non-binary: + name: "Non-binary artifacts" runs-on: ubuntu-latest steps: - name: "Check out the repo" @@ -208,23 +208,25 @@ jobs: run: | python -m pip install -r requirements/kit.pip - - name: "Build sdist" + - name: "Build non-binary artifacts" + env: + COVERAGE_DISABLE_EXTENSION: 1 run: | python -m build - - name: "List sdist" + - name: "List non-binary artifacts" run: | ls -al dist/ - - name: "Check sdist" + - name: "Check non-binary artifacts" run: | python -m twine check dist/* - - name: "Upload sdist" + - name: "Upload non-binary artifacts" uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 with: - name: dist-sdist - path: dist/*.tar.gz + name: dist-non-binary + path: dist/* retention-days: 7 pypy: @@ -277,7 +279,7 @@ jobs: name: "Sign artifacts" needs: - wheels - - sdist + - non-binary - pypy runs-on: ubuntu-latest permissions: diff --git a/setup.py b/setup.py index cb0e9c054..9aa82bf91 100644 --- a/setup.py +++ b/setup.py @@ -170,9 +170,11 @@ def build_extension(self, ext): # There are a few reasons we might not be able to compile the C extension. -# Figure out if we should attempt the C extension or not. +# Figure out if we should attempt the C extension or not. Define +# COVERAGE_DISABLE_EXTENSION in the build environment to explicitly disable the +# extension. -compile_extension = True +compile_extension = os.getenv("COVERAGE_DISABLE_EXTENSION", None) is None if "__pypy__" in sys.builtin_module_names: # Pypy can't compile C extensions From 13f555bab5ce9c91c5130891e5a0d541685a882d Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Fri, 10 Jan 2025 08:07:26 -0500 Subject: [PATCH 12/90] build: check the number of built distributions --- .github/workflows/kit.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/kit.yml b/.github/workflows/kit.yml index 67fbc3fe2..31ccdc61b 100644 --- a/.github/workflows/kit.yml +++ b/.github/workflows/kit.yml @@ -292,10 +292,15 @@ jobs: merge-multiple: true - name: "List distributions" + env: + # PYVERSIONS: changing the list of versions will change the number of + # expected distributions. + EXPECTED: 63 run: | ls -alR - echo "Number of dists, there should be 72:" + echo "Number of dists, there should be $EXPECTED:" ls -1 coverage-* | wc -l + files=$(ls coverage-* 2>/dev/null | wc -l) && [ "$files" -eq $EXPECTED ] || exit 1 - name: "Sign artifacts" uses: sigstore/gh-action-sigstore-python@f514d46b907ebcd5bedc05145c03b69c1edd8b46 # v3.0.0 From 4227045c7c17309a721b83182892a195ae3d3df9 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Fri, 10 Jan 2025 08:07:52 -0500 Subject: [PATCH 13/90] docs: py3-none-any.whl, thanks Russell Keith-Magee --- CHANGES.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 0f5fee55a..fde2fc772 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -23,7 +23,10 @@ upgrading your version of coverage.py. Unreleased ---------- -Nothing yet. +- We now ship a py3-none-any.whl wheel file. Thanks, `Russell Keith-Magee + `_. + +.. _pull 1914: https://github.com/nedbat/coveragepy/pull/1914 .. start-releases From f3f4730e69c21144ca66502471849274ecc490bb Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Fri, 10 Jan 2025 08:07:52 -0500 Subject: [PATCH 14/90] build: more pre-commit checks I tried `check-hooks-apply`, but it complained that check-symlinks doesn't apply because I have no symlinks. That's dumb. I want to protect against future additions of bad symlinks. I tried `rst-backticks`, but it complained about every single-backticked thing in my docs. Sphinx allows single backticks, they just mean something different than code. --- .pre-commit-config.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 466833a9e..7e20a1034 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,3 +14,18 @@ repos: exclude: "(status\\.json|\\.min\\.js)$" - id: trailing-whitespace exclude: "stress_phystoken|\\.py,cover$" + + - repo: https://github.com/pre-commit/pygrep-hooks + rev: v1.10.0 + hooks: + - id: rst-directive-colons + - id: rst-inline-touching-normal + + - repo: https://github.com/sphinx-contrib/sphinx-lint + rev: v1.0.0 + hooks: + - id: sphinx-lint + + - repo: meta + hooks: + - id: check-useless-excludes From 32a162210e5ab257d9d0d342381a2ae89c3bf123 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Fri, 17 Jan 2025 08:17:43 -0500 Subject: [PATCH 15/90] chore: make upgrade --- requirements/dev.pip | 12 ++++++------ requirements/kit.pip | 6 +++--- requirements/light-threads.pip | 2 +- requirements/mypy.pip | 4 ++-- requirements/pip-tools.pip | 2 +- requirements/pip.pip | 4 ++-- requirements/pytest.pip | 4 ++-- requirements/tox.pip | 4 ++-- 8 files changed, 19 insertions(+), 19 deletions(-) diff --git a/requirements/dev.pip b/requirements/dev.pip index afbce3046..76ff23973 100644 --- a/requirements/dev.pip +++ b/requirements/dev.pip @@ -49,7 +49,7 @@ flaky==3.8.1 # via -r /Users/ned/coverage/trunk/requirements/pytest.in greenlet==3.1.1 # via -r requirements/dev.in -hypothesis==6.123.2 +hypothesis==6.124.0 # via -r /Users/ned/coverage/trunk/requirements/pytest.in idna==3.10 # via requests @@ -80,7 +80,7 @@ mccabe==0.7.0 # via pylint mdurl==0.1.2 # via markdown-it-py -more-itertools==10.5.0 +more-itertools==10.6.0 # via # jaraco-classes # jaraco-functools @@ -109,7 +109,7 @@ pluggy==1.5.0 # tox pudb==2024.1.3 # via -r requirements/dev.in -pygments==2.18.0 +pygments==2.19.1 # via # -r /Users/ned/coverage/trunk/requirements/pytest.in # pudb @@ -160,7 +160,7 @@ tox==4.23.2 # via # -r /Users/ned/coverage/trunk/requirements/tox.in # tox-gh -tox-gh==1.4.4 +tox-gh==1.5.0 # via -r /Users/ned/coverage/trunk/requirements/tox.in twine==6.0.1 # via -r requirements/dev.in @@ -181,7 +181,7 @@ urwid==2.6.16 # urwid-readline urwid-readline==0.15.1 # via pudb -virtualenv==20.28.1 +virtualenv==20.29.0 # via # -r /Users/ned/coverage/trunk/requirements/pip.in # tox @@ -193,7 +193,7 @@ zipp==3.21.0 # The following packages are considered to be unsafe in a requirements file: pip==24.3.1 # via -r /Users/ned/coverage/trunk/requirements/pip.in -setuptools==75.6.0 +setuptools==75.8.0 # via # -r /Users/ned/coverage/trunk/requirements/pip.in # check-manifest diff --git a/requirements/kit.pip b/requirements/kit.pip index 5d4af4ea4..70bce5f8f 100644 --- a/requirements/kit.pip +++ b/requirements/kit.pip @@ -49,7 +49,7 @@ markdown-it-py==3.0.0 # via rich mdurl==0.1.2 # via markdown-it-py -more-itertools==10.5.0 +more-itertools==10.6.0 # via # jaraco-classes # jaraco-functools @@ -68,7 +68,7 @@ platformdirs==4.3.6 # via cibuildwheel pyelftools==0.31 # via auditwheel -pygments==2.18.0 +pygments==2.19.1 # via # readme-renderer # rich @@ -107,5 +107,5 @@ zipp==3.21.0 # via importlib-metadata # The following packages are considered to be unsafe in a requirements file: -setuptools==75.6.0 +setuptools==75.8.0 # via -r requirements/kit.in diff --git a/requirements/light-threads.pip b/requirements/light-threads.pip index a39ae6ae5..1aa457736 100644 --- a/requirements/light-threads.pip +++ b/requirements/light-threads.pip @@ -25,7 +25,7 @@ zope-interface==7.2 # via gevent # The following packages are considered to be unsafe in a requirements file: -setuptools==75.6.0 +setuptools==75.8.0 # via # zope-event # zope-interface diff --git a/requirements/mypy.pip b/requirements/mypy.pip index 5bc393e8a..ebd92174f 100644 --- a/requirements/mypy.pip +++ b/requirements/mypy.pip @@ -16,7 +16,7 @@ execnet==2.1.1 # via pytest-xdist flaky==3.8.1 # via -r /Users/ned/coverage/trunk/requirements/pytest.in -hypothesis==6.123.2 +hypothesis==6.124.0 # via -r /Users/ned/coverage/trunk/requirements/pytest.in iniconfig==2.0.0 # via pytest @@ -28,7 +28,7 @@ packaging==24.2 # via pytest pluggy==1.5.0 # via pytest -pygments==2.18.0 +pygments==2.19.1 # via -r /Users/ned/coverage/trunk/requirements/pytest.in pytest==8.3.4 # via diff --git a/requirements/pip-tools.pip b/requirements/pip-tools.pip index 9600da4c1..6432eb0cc 100644 --- a/requirements/pip-tools.pip +++ b/requirements/pip-tools.pip @@ -30,5 +30,5 @@ zipp==3.21.0 # The following packages are considered to be unsafe in a requirements file: pip==24.3.1 # via pip-tools -setuptools==75.6.0 +setuptools==75.8.0 # via pip-tools diff --git a/requirements/pip.pip b/requirements/pip.pip index fdd75d2dd..a349ea4d1 100644 --- a/requirements/pip.pip +++ b/requirements/pip.pip @@ -10,11 +10,11 @@ filelock==3.16.1 # via virtualenv platformdirs==4.3.6 # via virtualenv -virtualenv==20.28.1 +virtualenv==20.29.0 # via -r requirements/pip.in # The following packages are considered to be unsafe in a requirements file: pip==24.3.1 # via -r requirements/pip.in -setuptools==75.6.0 +setuptools==75.8.0 # via -r requirements/pip.in diff --git a/requirements/pytest.pip b/requirements/pytest.pip index 9d221de45..7722f7e64 100644 --- a/requirements/pytest.pip +++ b/requirements/pytest.pip @@ -16,7 +16,7 @@ execnet==2.1.1 # via pytest-xdist flaky==3.8.1 # via -r requirements/pytest.in -hypothesis==6.123.2 +hypothesis==6.124.0 # via -r requirements/pytest.in iniconfig==2.0.0 # via pytest @@ -24,7 +24,7 @@ packaging==24.2 # via pytest pluggy==1.5.0 # via pytest -pygments==2.18.0 +pygments==2.19.1 # via -r requirements/pytest.in pytest==8.3.4 # via diff --git a/requirements/tox.pip b/requirements/tox.pip index 12fb73b31..4209600b5 100644 --- a/requirements/tox.pip +++ b/requirements/tox.pip @@ -38,9 +38,9 @@ tox==4.23.2 # via # -r requirements/tox.in # tox-gh -tox-gh==1.4.4 +tox-gh==1.5.0 # via -r requirements/tox.in typing-extensions==4.12.2 # via tox -virtualenv==20.28.1 +virtualenv==20.29.0 # via tox From fef9e449932396600a989c9fd57d11a4bee4e391 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Tue, 21 Jan 2025 05:31:12 -0500 Subject: [PATCH 16/90] build: pin virtualenv to avoid a free-threading problem --- requirements/dev.pip | 7 ++++--- requirements/kit.pip | 2 +- requirements/mypy.pip | 2 +- requirements/pins.pip | 3 ++- requirements/pip-tools.pip | 2 +- requirements/pip.pip | 6 ++++-- requirements/pytest.pip | 2 +- requirements/tox.pip | 6 ++++-- 8 files changed, 18 insertions(+), 12 deletions(-) diff --git a/requirements/dev.pip b/requirements/dev.pip index 76ff23973..5bcfa2d7b 100644 --- a/requirements/dev.pip +++ b/requirements/dev.pip @@ -49,11 +49,11 @@ flaky==3.8.1 # via -r /Users/ned/coverage/trunk/requirements/pytest.in greenlet==3.1.1 # via -r requirements/dev.in -hypothesis==6.124.0 +hypothesis==6.124.1 # via -r /Users/ned/coverage/trunk/requirements/pytest.in idna==3.10 # via requests -importlib-metadata==8.5.0 +importlib-metadata==8.6.1 # via # build # keyring @@ -181,8 +181,9 @@ urwid==2.6.16 # urwid-readline urwid-readline==0.15.1 # via pudb -virtualenv==20.29.0 +virtualenv==20.28.1 # via + # -c /Users/ned/coverage/trunk/requirements/pins.pip # -r /Users/ned/coverage/trunk/requirements/pip.in # tox wcwidth==0.2.13 diff --git a/requirements/kit.pip b/requirements/kit.pip index 70bce5f8f..53f8b518a 100644 --- a/requirements/kit.pip +++ b/requirements/kit.pip @@ -32,7 +32,7 @@ filelock==3.16.1 # via cibuildwheel idna==3.10 # via requests -importlib-metadata==8.5.0 +importlib-metadata==8.6.1 # via # build # keyring diff --git a/requirements/mypy.pip b/requirements/mypy.pip index ebd92174f..7c1ede777 100644 --- a/requirements/mypy.pip +++ b/requirements/mypy.pip @@ -16,7 +16,7 @@ execnet==2.1.1 # via pytest-xdist flaky==3.8.1 # via -r /Users/ned/coverage/trunk/requirements/pytest.in -hypothesis==6.124.0 +hypothesis==6.124.1 # via -r /Users/ned/coverage/trunk/requirements/pytest.in iniconfig==2.0.0 # via pytest diff --git a/requirements/pins.pip b/requirements/pins.pip index f27dad10c..8c2147b76 100644 --- a/requirements/pins.pip +++ b/requirements/pins.pip @@ -3,4 +3,5 @@ # Version pins, for use as a constraints file. -# None for now! +# https://github.com/pypa/virtualenv/issues/2829 +virtualenv<20.29.0 diff --git a/requirements/pip-tools.pip b/requirements/pip-tools.pip index 6432eb0cc..46a610f9f 100644 --- a/requirements/pip-tools.pip +++ b/requirements/pip-tools.pip @@ -8,7 +8,7 @@ build==1.2.2.post1 # via pip-tools click==8.1.8 # via pip-tools -importlib-metadata==8.5.0 +importlib-metadata==8.6.1 # via build packaging==24.2 # via build diff --git a/requirements/pip.pip b/requirements/pip.pip index a349ea4d1..4256e1833 100644 --- a/requirements/pip.pip +++ b/requirements/pip.pip @@ -10,8 +10,10 @@ filelock==3.16.1 # via virtualenv platformdirs==4.3.6 # via virtualenv -virtualenv==20.29.0 - # via -r requirements/pip.in +virtualenv==20.28.1 + # via + # -c /Users/ned/coverage/trunk/requirements/pins.pip + # -r requirements/pip.in # The following packages are considered to be unsafe in a requirements file: pip==24.3.1 diff --git a/requirements/pytest.pip b/requirements/pytest.pip index 7722f7e64..246ef2196 100644 --- a/requirements/pytest.pip +++ b/requirements/pytest.pip @@ -16,7 +16,7 @@ execnet==2.1.1 # via pytest-xdist flaky==3.8.1 # via -r requirements/pytest.in -hypothesis==6.124.0 +hypothesis==6.124.1 # via -r requirements/pytest.in iniconfig==2.0.0 # via pytest diff --git a/requirements/tox.pip b/requirements/tox.pip index 4209600b5..38ff013f8 100644 --- a/requirements/tox.pip +++ b/requirements/tox.pip @@ -42,5 +42,7 @@ tox-gh==1.5.0 # via -r requirements/tox.in typing-extensions==4.12.2 # via tox -virtualenv==20.29.0 - # via tox +virtualenv==20.28.1 + # via + # -c /Users/ned/coverage/trunk/requirements/pins.pip + # tox From 4f12504194248edabd8fc05fcc144edb3d0a2134 Mon Sep 17 00:00:00 2001 From: Allan Lewis Date: Tue, 21 Jan 2025 11:01:02 +0000 Subject: [PATCH 17/90] docs: improve config snippets in code exclusion docs (#1917) * doc/excluding.rst: Use conventional TOML style * doc/excluding.rst: Use 'literal strings' for regexes in TOML --- doc/excluding.rst | 70 +++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/doc/excluding.rst b/doc/excluding.rst index a3481fb5f..034627b55 100644 --- a/doc/excluding.rst +++ b/doc/excluding.rst @@ -104,7 +104,7 @@ all of them by adding a regex to the exclusion list: [tool.coverage.report] exclude_also = [ "def __repr__", - ] + ] """, ) .. ]]] @@ -124,7 +124,7 @@ all of them by adding a regex to the exclusion list: [tool.coverage.report] exclude_also = [ "def __repr__", - ] + ] .. code-tab:: ini :caption: setup.cfg or tox.ini @@ -133,7 +133,7 @@ all of them by adding a regex to the exclusion list: exclude_also = def __repr__ -.. [[[end]]] (checksum: e3194120285bcbac38a92b109edaa20c) +.. [[[end]]] (checksum: f3e70ebf128fbef4087efe75dcfadcb8) For example, here's a list of exclusions I've used: @@ -156,17 +156,17 @@ For example, here's a list of exclusions I've used: toml=r""" [tool.coverage.report] exclude_also = [ - "def __repr__", - "if self.debug:", - "if settings.DEBUG", - "raise AssertionError", - "raise NotImplementedError", - "if 0:", - "if __name__ == .__main__.:", - "if TYPE_CHECKING:", - "class .*\\bProtocol\\):", - "@(abc\\.)?abstractmethod", - ] + 'def __repr__', + 'if self.debug:', + 'if settings.DEBUG', + 'raise AssertionError', + 'raise NotImplementedError', + 'if 0:', + 'if __name__ == .__main__.:', + 'if TYPE_CHECKING:', + 'class .*\bProtocol\):', + '@(abc\.)?abstractmethod', + ] """, ) .. ]]] @@ -194,17 +194,17 @@ For example, here's a list of exclusions I've used: [tool.coverage.report] exclude_also = [ - "def __repr__", - "if self.debug:", - "if settings.DEBUG", - "raise AssertionError", - "raise NotImplementedError", - "if 0:", - "if __name__ == .__main__.:", - "if TYPE_CHECKING:", - "class .*\\bProtocol\\):", - "@(abc\\.)?abstractmethod", - ] + 'def __repr__', + 'if self.debug:', + 'if settings.DEBUG', + 'raise AssertionError', + 'raise NotImplementedError', + 'if 0:', + 'if __name__ == .__main__.:', + 'if TYPE_CHECKING:', + 'class .*\bProtocol\):', + '@(abc\.)?abstractmethod', + ] .. code-tab:: ini :caption: setup.cfg or tox.ini @@ -222,7 +222,7 @@ For example, here's a list of exclusions I've used: class .*\bProtocol\): @(abc\.)?abstractmethod -.. [[[end]]] (checksum: 91f09828a1e6d0e92543e14a8ea3ba39) +.. [[[end]]] (checksum: 650b209edd27112381b5f0a8d2ee0c45) The :ref:`config_report_exclude_also` option adds regexes to the built-in default list so that you can add your own exclusions. The older @@ -270,12 +270,12 @@ Here are some examples: [tool.coverage.report] exclude_also = [ # 1. Exclude an except clause of a specific form: - "except ValueError:\\n\\s*assume\\(False\\)", + 'except ValueError:\n\s*assume\(False\)', # 2. Comments to turn coverage on and off: - "no cover: start(?s:.)*?no cover: stop", + 'no cover: start(?s:.)*?no cover: stop', # 3. A pragma comment that excludes an entire file: - "\\A(?s:.*# pragma: exclude file.*)\\Z", - ] + '\A(?s:.*# pragma: exclude file.*)\Z', + ] """, ) .. ]]] @@ -300,12 +300,12 @@ Here are some examples: [tool.coverage.report] exclude_also = [ # 1. Exclude an except clause of a specific form: - "except ValueError:\\n\\s*assume\\(False\\)", + 'except ValueError:\n\s*assume\(False\)', # 2. Comments to turn coverage on and off: - "no cover: start(?s:.)*?no cover: stop", + 'no cover: start(?s:.)*?no cover: stop', # 3. A pragma comment that excludes an entire file: - "\\A(?s:.*# pragma: exclude file.*)\\Z", - ] + '\A(?s:.*# pragma: exclude file.*)\Z', + ] .. code-tab:: ini :caption: setup.cfg or tox.ini @@ -319,7 +319,7 @@ Here are some examples: ; 3. A pragma comment that excludes an entire file: \A(?s:.*# pragma: exclude file.*)\Z -.. [[[end]]] (checksum: ee3ef14b5a5d73f987b924df623a4927) +.. [[[end]]] (checksum: c46e819ad9a1d3a8e37037a89d28cfde) The first regex matches a specific except line followed by a specific function call. Both lines must be present for the exclusion to take effect. Note that From 979327017696c6a9f87d8b29bca9d7a8874b4a59 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Tue, 7 Jan 2025 14:57:38 -0500 Subject: [PATCH 18/90] fix: NoDebugging needs all the methods of DebugControl #1904 --- coverage/debug.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/coverage/debug.py b/coverage/debug.py index 2e578a3d4..fbd500a72 100644 --- a/coverage/debug.py +++ b/coverage/debug.py @@ -119,6 +119,11 @@ def should(self, option: str) -> bool: """Should we write debug messages? Never.""" return False + @contextlib.contextmanager + def without_callers(self) -> Iterator[None]: + """A dummy context manager to satisfy the api.""" + yield + def write(self, msg: str, *, exc: BaseException | None = None) -> None: """This will never be called.""" raise AssertionError("NoDebugging.write should never be called.") From 1961241d50a688b01a6b108ade5fbcf2d4869644 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Fri, 24 Jan 2025 07:43:19 -0500 Subject: [PATCH 19/90] chore: make upgrade --- requirements/dev.pip | 17 +++++++++-------- requirements/kit.pip | 9 +++++---- requirements/mypy.pip | 2 +- requirements/pip.pip | 2 +- requirements/pytest.pip | 2 +- requirements/tox.pip | 8 ++++---- 6 files changed, 21 insertions(+), 19 deletions(-) diff --git a/requirements/dev.pip b/requirements/dev.pip index 5bcfa2d7b..0adac425a 100644 --- a/requirements/dev.pip +++ b/requirements/dev.pip @@ -12,7 +12,7 @@ backports-tarfile==1.2.0 # via jaraco-context build==1.2.2.post1 # via check-manifest -cachetools==5.5.0 +cachetools==5.5.1 # via tox certifi==2024.12.14 # via requests @@ -41,7 +41,7 @@ exceptiongroup==1.2.2 # pytest execnet==2.1.1 # via pytest-xdist -filelock==3.16.1 +filelock==3.17.0 # via # tox # virtualenv @@ -49,8 +49,10 @@ flaky==3.8.1 # via -r /Users/ned/coverage/trunk/requirements/pytest.in greenlet==3.1.1 # via -r requirements/dev.in -hypothesis==6.124.1 +hypothesis==6.124.2 # via -r /Users/ned/coverage/trunk/requirements/pytest.in +id==1.5.0 + # via twine idna==3.10 # via requests importlib-metadata==8.6.1 @@ -96,8 +98,6 @@ packaging==24.2 # twine parso==0.8.4 # via jedi -pkginfo==1.12.0 - # via twine platformdirs==4.3.6 # via # pylint @@ -117,7 +117,7 @@ pygments==2.19.1 # rich pylint==3.3.3 # via -r requirements/dev.in -pyproject-api==1.8.0 +pyproject-api==1.9.0 # via tox pyproject-hooks==1.2.0 # via build @@ -134,6 +134,7 @@ readme-renderer==44.0 requests==2.32.3 # via # -r requirements/dev.in + # id # requests-toolbelt # twine requests-toolbelt==1.0.0 @@ -156,13 +157,13 @@ tomli==2.2.1 # tox tomlkit==0.13.2 # via pylint -tox==4.23.2 +tox==4.24.1 # via # -r /Users/ned/coverage/trunk/requirements/tox.in # tox-gh tox-gh==1.5.0 # via -r /Users/ned/coverage/trunk/requirements/tox.in -twine==6.0.1 +twine==6.1.0 # via -r requirements/dev.in typing-extensions==4.12.2 # via diff --git a/requirements/kit.pip b/requirements/kit.pip index 53f8b518a..ed509efc9 100644 --- a/requirements/kit.pip +++ b/requirements/kit.pip @@ -28,8 +28,10 @@ dependency-groups==1.3.0 # via cibuildwheel docutils==0.21.2 # via readme-renderer -filelock==3.16.1 +filelock==3.17.0 # via cibuildwheel +id==1.5.0 + # via twine idna==3.10 # via requests importlib-metadata==8.6.1 @@ -62,8 +64,6 @@ packaging==24.2 # cibuildwheel # dependency-groups # twine -pkginfo==1.12.0 - # via twine platformdirs==4.3.6 # via cibuildwheel pyelftools==0.31 @@ -78,6 +78,7 @@ readme-renderer==44.0 # via twine requests==2.32.3 # via + # id # requests-toolbelt # twine requests-toolbelt==1.0.0 @@ -91,7 +92,7 @@ tomli==2.2.1 # build # cibuildwheel # dependency-groups -twine==6.0.1 +twine==6.1.0 # via -r requirements/kit.in typing-extensions==4.12.2 # via diff --git a/requirements/mypy.pip b/requirements/mypy.pip index 7c1ede777..b7cfae2bd 100644 --- a/requirements/mypy.pip +++ b/requirements/mypy.pip @@ -16,7 +16,7 @@ execnet==2.1.1 # via pytest-xdist flaky==3.8.1 # via -r /Users/ned/coverage/trunk/requirements/pytest.in -hypothesis==6.124.1 +hypothesis==6.124.2 # via -r /Users/ned/coverage/trunk/requirements/pytest.in iniconfig==2.0.0 # via pytest diff --git a/requirements/pip.pip b/requirements/pip.pip index 4256e1833..926be0641 100644 --- a/requirements/pip.pip +++ b/requirements/pip.pip @@ -6,7 +6,7 @@ # distlib==0.3.9 # via virtualenv -filelock==3.16.1 +filelock==3.17.0 # via virtualenv platformdirs==4.3.6 # via virtualenv diff --git a/requirements/pytest.pip b/requirements/pytest.pip index 246ef2196..08cb2c7f5 100644 --- a/requirements/pytest.pip +++ b/requirements/pytest.pip @@ -16,7 +16,7 @@ execnet==2.1.1 # via pytest-xdist flaky==3.8.1 # via -r requirements/pytest.in -hypothesis==6.124.1 +hypothesis==6.124.2 # via -r requirements/pytest.in iniconfig==2.0.0 # via pytest diff --git a/requirements/tox.pip b/requirements/tox.pip index 38ff013f8..fa4634d70 100644 --- a/requirements/tox.pip +++ b/requirements/tox.pip @@ -4,7 +4,7 @@ # # make upgrade # -cachetools==5.5.0 +cachetools==5.5.1 # via tox chardet==5.2.0 # via tox @@ -14,7 +14,7 @@ colorama==0.4.6 # tox distlib==0.3.9 # via virtualenv -filelock==3.16.1 +filelock==3.17.0 # via # tox # virtualenv @@ -28,13 +28,13 @@ platformdirs==4.3.6 # virtualenv pluggy==1.5.0 # via tox -pyproject-api==1.8.0 +pyproject-api==1.9.0 # via tox tomli==2.2.1 # via # pyproject-api # tox -tox==4.23.2 +tox==4.24.1 # via # -r requirements/tox.in # tox-gh From fcdce1deb2f182dc5a34fdc6d91b50033ed2badb Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Fri, 24 Jan 2025 07:43:57 -0500 Subject: [PATCH 20/90] chore: make doc_upgrade --- doc/requirements.pip | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/requirements.pip b/doc/requirements.pip index bc714515f..9d48239a6 100644 --- a/doc/requirements.pip +++ b/doc/requirements.pip @@ -52,7 +52,7 @@ pyenchant==3.2.2 # via # -r doc/requirements.in # sphinxcontrib-spelling -pygments==2.18.0 +pygments==2.19.1 # via # doc8 # sphinx @@ -103,7 +103,7 @@ sphinxcontrib-serializinghtml==2.0.0 # via sphinx sphinxcontrib-spelling==8.0.1 # via -r doc/requirements.in -starlette==0.45.2 +starlette==0.45.3 # via sphinx-autobuild stevedore==5.4.0 # via doc8 @@ -113,7 +113,7 @@ urllib3==2.3.0 # via requests uvicorn==0.34.0 # via sphinx-autobuild -watchfiles==1.0.3 +watchfiles==1.0.4 # via sphinx-autobuild -websockets==14.1 +websockets==14.2 # via sphinx-autobuild From cd2db93276e680aca70bd36806847e82f76e2fa3 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 2 Feb 2025 16:27:03 -0700 Subject: [PATCH 21/90] docs: a reminder about when RESUME applies --- coverage/ctracer/tracer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coverage/ctracer/tracer.c b/coverage/ctracer/tracer.c index 91813074a..601fc87a9 100644 --- a/coverage/ctracer/tracer.c +++ b/coverage/ctracer/tracer.c @@ -303,7 +303,7 @@ CTracer_handle_call(CTracer *self, PyFrameObject *frame) PyObject * plugin = NULL; PyObject * plugin_name = NULL; PyObject * next_tracename = NULL; -#ifdef RESUME +#ifdef RESUME // >=3.11 PyObject * pCode = NULL; #endif From d6a1e5b6ea5bc03d0bf085fbac285b7e4a56d8a6 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 2 Feb 2025 16:27:29 -0700 Subject: [PATCH 22/90] test: run the pytracer first so .tox is left with a c extension for ad-hoc use --- tox.ini | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tox.ini b/tox.ini index 57919d730..ccc9e702f 100644 --- a/tox.ini +++ b/tox.ini @@ -41,6 +41,12 @@ commands = # Create tests/zipmods.zip python igor.py zip_mods + # Remove the C extension so that we can test the PyTracer + python igor.py remove_extension + + # Test with the PyTracer + python igor.py test_with_core pytrace {posargs} + # Build the C extension and test with the CTracer python setup.py --quiet build_ext --inplace python -m pip install {env:COVERAGE_PIP_ARGS} -q -e . @@ -48,12 +54,6 @@ commands = py3{12,13,14},anypy: python igor.py test_with_core sysmon {posargs} - # Remove the C extension so that we can test the PyTracer - python igor.py remove_extension - - # Test with the PyTracer - python igor.py test_with_core pytrace {posargs} - [testenv:anypy] # $set_env.py: COVERAGE_ANYPY - The custom Python for "tox -e anypy" # For running against my own builds of CPython, or any other specific Python. From 66030210bf7438d17830687aafa4504eb6e845db Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Feb 2025 08:31:58 -0500 Subject: [PATCH 23/90] chore: bump the action-dependencies group with 6 updates (#1922) Bumps the action-dependencies group with 6 updates: | Package | From | To | | --- | --- | --- | | [github/codeql-action](https://github.com/github/codeql-action) | `3.28.0` | `3.28.8` | | [actions/setup-python](https://github.com/actions/setup-python) | `5.3.0` | `5.4.0` | | [actions/upload-artifact](https://github.com/actions/upload-artifact) | `4.5.0` | `4.6.0` | | [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) | `3.2.0` | `3.3.0` | | [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance) | `2.1.0` | `2.2.0` | | [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) | `1.12.3` | `1.12.4` | Updates `github/codeql-action` from 3.28.0 to 3.28.8 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/48ab28a6f5dbc2a99bf1e0131198dd8f1df78169...dd746615b3b9d728a6a37ca2045b68ca76d4841a) Updates `actions/setup-python` from 5.3.0 to 5.4.0 - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/0b93645e9fea7318ecaed2b359559ac225c90a2b...42375524e23c412d93fb67b49958b491fce71c38) Updates `actions/upload-artifact` from 4.5.0 to 4.6.0 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/6f51ac03b9356f520e9adb1b1b7802705f340c2b...65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08) Updates `docker/setup-qemu-action` from 3.2.0 to 3.3.0 - [Release notes](https://github.com/docker/setup-qemu-action/releases) - [Commits](https://github.com/docker/setup-qemu-action/compare/49b3bc8e6bdd4a60e6116a5414239cba5943d3cf...53851d14592bedcffcf25ea515637cff71ef929a) Updates `actions/attest-build-provenance` from 2.1.0 to 2.2.0 - [Release notes](https://github.com/actions/attest-build-provenance/releases) - [Changelog](https://github.com/actions/attest-build-provenance/blob/main/RELEASE.md) - [Commits](https://github.com/actions/attest-build-provenance/compare/7668571508540a607bdfd90a87a560489fe372eb...520d128f165991a6c774bcb264f323e3d70747f4) Updates `pypa/gh-action-pypi-publish` from 1.12.3 to 1.12.4 - [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases) - [Commits](https://github.com/pypa/gh-action-pypi-publish/compare/67339c736fd9354cd4f8cb0b744f2b82a74b5c70...76f52bc884231f62b9a034ebfe128415bbaabdfc) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch dependency-group: action-dependencies - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-minor dependency-group: action-dependencies - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-minor dependency-group: action-dependencies - dependency-name: docker/setup-qemu-action dependency-type: direct:production update-type: version-update:semver-minor dependency-group: action-dependencies - dependency-name: actions/attest-build-provenance dependency-type: direct:production update-type: version-update:semver-minor dependency-group: action-dependencies - dependency-name: pypa/gh-action-pypi-publish dependency-type: direct:production update-type: version-update:semver-patch dependency-group: action-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 6 +++--- .github/workflows/coverage.yml | 8 ++++---- .github/workflows/kit.yml | 16 ++++++++-------- .github/workflows/publish.yml | 8 ++++---- .github/workflows/python-nightly.yml | 2 +- .github/workflows/quality.yml | 6 +++--- .github/workflows/testsuite.yml | 2 +- 7 files changed, 24 insertions(+), 24 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 4badbef9c..84a6ba085 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -51,7 +51,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3 + uses: github/codeql-action/init@dd746615b3b9d728a6a37ca2045b68ca76d4841a # v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -62,7 +62,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3 + uses: github/codeql-action/autobuild@dd746615b3b9d728a6a37ca2045b68ca76d4841a # v3 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -76,4 +76,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3 + uses: github/codeql-action/analyze@dd746615b3b9d728a6a37ca2045b68ca76d4841a # v3 diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 91d5c0096..07c2250fe 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -84,7 +84,7 @@ jobs: persist-credentials: false - name: "Set up Python" - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 with: python-version: "${{ matrix.python-version }}" allow-prereleases: true @@ -125,7 +125,7 @@ jobs: mv .metacov .metacov.$MATRIX_ID - name: "Upload coverage data" - uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 with: name: metacov-${{ env.MATRIX_ID }} path: .metacov.* @@ -147,7 +147,7 @@ jobs: persist-credentials: false - name: "Set up Python" - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 with: python-version: "3.9" # Minimum of PYVERSIONS # At a certain point, installing dependencies failed on pypy 3.9 and @@ -184,7 +184,7 @@ jobs: python igor.py combine_html - name: "Upload HTML report" - uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 with: name: html_report path: htmlcov diff --git a/.github/workflows/kit.yml b/.github/workflows/kit.yml index 31ccdc61b..4f971c010 100644 --- a/.github/workflows/kit.yml +++ b/.github/workflows/kit.yml @@ -142,7 +142,7 @@ jobs: steps: - name: "Setup QEMU" if: matrix.os == 'ubuntu' - uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0 + uses: docker/setup-qemu-action@53851d14592bedcffcf25ea515637cff71ef929a # v3.3.0 with: platforms: arm64 @@ -152,7 +152,7 @@ jobs: persist-credentials: false - name: "Install Python" - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 with: python-version: "3.9" # Minimum of PYVERSIONS cache: pip @@ -182,7 +182,7 @@ jobs: python -m twine check wheelhouse/* - name: "Upload binary wheels" - uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 with: name: dist-${{ env.MATRIX_ID }} path: wheelhouse/*.whl @@ -198,7 +198,7 @@ jobs: persist-credentials: false - name: "Install Python" - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 with: python-version: "3.9" # Minimum of PYVERSIONS cache: pip @@ -223,7 +223,7 @@ jobs: python -m twine check dist/* - name: "Upload non-binary artifacts" - uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 with: name: dist-non-binary path: dist/* @@ -239,7 +239,7 @@ jobs: persist-credentials: false - name: "Install PyPy" - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 with: python-version: "pypy-3.9" # Minimum of PyPy PYVERSIONS cache: pip @@ -267,7 +267,7 @@ jobs: python -m twine check dist/* - name: "Upload wheels" - uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 with: name: dist-pypy path: dist/*.whl @@ -312,7 +312,7 @@ jobs: ls -alR - name: "Upload signatures" - uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 with: name: signatures path: "*.sigstore.json" diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c87677169..0414abafd 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -72,12 +72,12 @@ jobs: ls -1 dist | wc -l - name: "Generate attestations" - uses: actions/attest-build-provenance@7668571508540a607bdfd90a87a560489fe372eb # v2.1.0 + uses: actions/attest-build-provenance@520d128f165991a6c774bcb264f323e3d70747f4 # v2.2.0 with: subject-path: "dist/*" - name: "Publish dists to Test PyPI" - uses: pypa/gh-action-pypi-publish@67339c736fd9354cd4f8cb0b744f2b82a74b5c70 # v1.12.3 + uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4 with: repository-url: https://test.pypi.org/legacy/ @@ -111,9 +111,9 @@ jobs: ls -1 dist | wc -l - name: "Generate attestations" - uses: actions/attest-build-provenance@7668571508540a607bdfd90a87a560489fe372eb # v2.1.0 + uses: actions/attest-build-provenance@520d128f165991a6c774bcb264f323e3d70747f4 # v2.2.0 with: subject-path: "dist/*" - name: "Publish dists to PyPI" - uses: pypa/gh-action-pypi-publish@67339c736fd9354cd4f8cb0b744f2b82a74b5c70 # v1.12.3 + uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4 diff --git a/.github/workflows/python-nightly.yml b/.github/workflows/python-nightly.yml index 4b73e09cc..99e19d091 100644 --- a/.github/workflows/python-nightly.yml +++ b/.github/workflows/python-nightly.yml @@ -92,7 +92,7 @@ jobs: nogil: "${{ matrix.nogil || false }}" - name: "Install ${{ matrix.python-version }} with setup-python" - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 if: "startsWith(matrix.python-version, 'pypy-')" with: python-version: "${{ matrix.python-version }}" diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index 54d3a3418..56f063c0d 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -42,7 +42,7 @@ jobs: persist-credentials: false - name: "Install Python" - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 with: python-version: "3.9" # Minimum of PYVERSIONS cache: pip @@ -67,7 +67,7 @@ jobs: persist-credentials: false - name: "Install Python" - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 with: python-version: "3.9" # Minimum of PYVERSIONS cache: pip @@ -92,7 +92,7 @@ jobs: persist-credentials: false - name: "Install Python" - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 with: python-version: "3.11" # Doc version from PYVERSIONS cache: pip diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml index 1f85ca745..84f1b6be0 100644 --- a/.github/workflows/testsuite.yml +++ b/.github/workflows/testsuite.yml @@ -79,7 +79,7 @@ jobs: persist-credentials: false - name: "Set up Python" - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 with: python-version: "${{ matrix.python-version }}" allow-prereleases: true From 156981f20730a2f4abd5a4efcc8cf1cad1d6a811 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Mon, 3 Feb 2025 08:32:29 -0700 Subject: [PATCH 24/90] build: zizmor can't tell this is safe --- .github/workflows/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 0414abafd..cabb250b0 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -37,7 +37,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: "Record run id" + - name: "Record run id" # zizmor: ignore[template-injection] id: run-id run: | echo "run-id=${{ fromJson(steps.runs.outputs.data).workflow_runs[0].id }}" >> "$GITHUB_OUTPUT" From ae8d3b9981bac68f903c63c9e432ef5e30b4865b Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Mon, 3 Feb 2025 13:12:45 -0700 Subject: [PATCH 25/90] chore: make upgrade --- requirements/dev.pip | 12 ++++++------ requirements/kit.pip | 2 +- requirements/light-threads.pip | 2 +- requirements/mypy.pip | 4 ++-- requirements/pip-tools.pip | 2 +- requirements/pip.pip | 2 +- requirements/pytest.pip | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/requirements/dev.pip b/requirements/dev.pip index 0adac425a..6a49e82ab 100644 --- a/requirements/dev.pip +++ b/requirements/dev.pip @@ -6,7 +6,7 @@ # astroid==3.3.8 # via pylint -attrs==24.3.0 +attrs==25.1.0 # via hypothesis backports-tarfile==1.2.0 # via jaraco-context @@ -14,7 +14,7 @@ build==1.2.2.post1 # via check-manifest cachetools==5.5.1 # via tox -certifi==2024.12.14 +certifi==2025.1.31 # via requests chardet==5.2.0 # via tox @@ -49,7 +49,7 @@ flaky==3.8.1 # via -r /Users/ned/coverage/trunk/requirements/pytest.in greenlet==3.1.1 # via -r requirements/dev.in -hypothesis==6.124.2 +hypothesis==6.125.1 # via -r /Users/ned/coverage/trunk/requirements/pytest.in id==1.5.0 # via twine @@ -62,7 +62,7 @@ importlib-metadata==8.6.1 # twine iniconfig==2.0.0 # via pytest -isort==5.13.2 +isort==6.0.0 # via pylint jaraco-classes==3.4.0 # via keyring @@ -115,7 +115,7 @@ pygments==2.19.1 # pudb # readme-renderer # rich -pylint==3.3.3 +pylint==3.3.4 # via -r requirements/dev.in pyproject-api==1.9.0 # via tox @@ -193,7 +193,7 @@ zipp==3.21.0 # via importlib-metadata # The following packages are considered to be unsafe in a requirements file: -pip==24.3.1 +pip==25.0 # via -r /Users/ned/coverage/trunk/requirements/pip.in setuptools==75.8.0 # via diff --git a/requirements/kit.pip b/requirements/kit.pip index ed509efc9..33e6e8828 100644 --- a/requirements/kit.pip +++ b/requirements/kit.pip @@ -14,7 +14,7 @@ bracex==2.5.post1 # via cibuildwheel build==1.2.2.post1 # via -r requirements/kit.in -certifi==2024.12.14 +certifi==2025.1.31 # via # cibuildwheel # requests diff --git a/requirements/light-threads.pip b/requirements/light-threads.pip index 1aa457736..dfb02c03c 100644 --- a/requirements/light-threads.pip +++ b/requirements/light-threads.pip @@ -8,7 +8,7 @@ cffi==1.17.1 # via -r requirements/light-threads.in dnspython==2.7.0 # via eventlet -eventlet==0.38.2 +eventlet==0.39.0 # via -r requirements/light-threads.in gevent==24.11.1 # via -r requirements/light-threads.in diff --git a/requirements/mypy.pip b/requirements/mypy.pip index b7cfae2bd..53eb29101 100644 --- a/requirements/mypy.pip +++ b/requirements/mypy.pip @@ -4,7 +4,7 @@ # # make upgrade # -attrs==24.3.0 +attrs==25.1.0 # via hypothesis colorama==0.4.6 # via -r /Users/ned/coverage/trunk/requirements/pytest.in @@ -16,7 +16,7 @@ execnet==2.1.1 # via pytest-xdist flaky==3.8.1 # via -r /Users/ned/coverage/trunk/requirements/pytest.in -hypothesis==6.124.2 +hypothesis==6.125.1 # via -r /Users/ned/coverage/trunk/requirements/pytest.in iniconfig==2.0.0 # via pytest diff --git a/requirements/pip-tools.pip b/requirements/pip-tools.pip index 46a610f9f..5ddf2973d 100644 --- a/requirements/pip-tools.pip +++ b/requirements/pip-tools.pip @@ -28,7 +28,7 @@ zipp==3.21.0 # via importlib-metadata # The following packages are considered to be unsafe in a requirements file: -pip==24.3.1 +pip==25.0 # via pip-tools setuptools==75.8.0 # via pip-tools diff --git a/requirements/pip.pip b/requirements/pip.pip index 926be0641..9d37a7727 100644 --- a/requirements/pip.pip +++ b/requirements/pip.pip @@ -16,7 +16,7 @@ virtualenv==20.28.1 # -r requirements/pip.in # The following packages are considered to be unsafe in a requirements file: -pip==24.3.1 +pip==25.0 # via -r requirements/pip.in setuptools==75.8.0 # via -r requirements/pip.in diff --git a/requirements/pytest.pip b/requirements/pytest.pip index 08cb2c7f5..b11451f74 100644 --- a/requirements/pytest.pip +++ b/requirements/pytest.pip @@ -4,7 +4,7 @@ # # make upgrade # -attrs==24.3.0 +attrs==25.1.0 # via hypothesis colorama==0.4.6 # via -r requirements/pytest.in @@ -16,7 +16,7 @@ execnet==2.1.1 # via pytest-xdist flaky==3.8.1 # via -r requirements/pytest.in -hypothesis==6.124.2 +hypothesis==6.125.1 # via -r requirements/pytest.in iniconfig==2.0.0 # via pytest From f85d9b7676a480c88d938c1e63a1dbebea45e21d Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Thu, 6 Feb 2025 07:22:21 -0500 Subject: [PATCH 26/90] fix: prevent code objects from leaking #1924 --- CHANGES.rst | 7 ++++++- coverage/ctracer/tracer.c | 31 +++++++++++++++++++++---------- tests/test_oddball.py | 15 +++++++++++++++ 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index fde2fc772..8edf5a080 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -23,11 +23,16 @@ upgrading your version of coverage.py. Unreleased ---------- +- Fix: a memory leak in CTracer has been fixed. The details are in `issue + 1924`_ and `pytest-dev 676`_. This should reduce the memory footprint for + everyone even if it hadn't caused a problem before. + - We now ship a py3-none-any.whl wheel file. Thanks, `Russell Keith-Magee `_. .. _pull 1914: https://github.com/nedbat/coveragepy/pull/1914 - +.. _issue 1924: https://github.com/nedbat/coveragepy/issues/1924 +.. _pytest-dev 676: https://github.com/pytest-dev/pytest-cov/issues/676 .. start-releases diff --git a/coverage/ctracer/tracer.c b/coverage/ctracer/tracer.c index 601fc87a9..4fca2fee7 100644 --- a/coverage/ctracer/tracer.c +++ b/coverage/ctracer/tracer.c @@ -288,6 +288,17 @@ CTracer_set_pdata_stack(CTracer *self) return ret; } +// Thanks for the idea, memray! +inline PyCodeObject* +MyFrame_BorrowCode(PyFrameObject* frame) +{ + // Return a borrowed reference. + PyCodeObject* pCode = PyFrame_GetCode(frame); + assert(Py_REFCNT(pCode) >= 2); + Py_DECREF(pCode); + return pCode; +} + /* * Parts of the trace function. */ @@ -359,7 +370,7 @@ CTracer_handle_call(CTracer *self, PyFrameObject *frame) } /* Check if we should trace this line. */ - filename = PyFrame_GetCode(frame)->co_filename; + filename = MyFrame_BorrowCode(frame)->co_filename; disposition = PyDict_GetItem(self->should_trace_cache, filename); if (disposition == NULL) { if (PyErr_Occurred()) { @@ -554,7 +565,7 @@ CTracer_handle_call(CTracer *self, PyFrameObject *frame) * The current opcode is guaranteed to be RESUME. The argument * determines what kind of resume it is. */ - pCode = MyCode_GetCode(PyFrame_GetCode(frame)); + pCode = MyCode_GetCode(MyFrame_BorrowCode(frame)); real_call = (PyBytes_AS_STRING(pCode)[MyFrame_GetLasti(frame) + 1] == 0); #else // f_lasti is -1 for a true call, and a real byte offset for a generator re-entry. @@ -562,7 +573,7 @@ CTracer_handle_call(CTracer *self, PyFrameObject *frame) #endif if (real_call) { - self->pcur_entry->last_line = -PyFrame_GetCode(frame)->co_firstlineno; + self->pcur_entry->last_line = -MyFrame_BorrowCode(frame)->co_firstlineno; } else { self->pcur_entry->last_line = PyFrame_GetLineNumber(frame); @@ -649,7 +660,7 @@ CTracer_handle_line(CTracer *self, PyFrameObject *frame) STATS( self->stats.lines++; ) if (self->pdata_stack->depth >= 0) { - SHOWLOG(PyFrame_GetLineNumber(frame), PyFrame_GetCode(frame)->co_filename, "line"); + SHOWLOG(PyFrame_GetLineNumber(frame), MyFrame_BorrowCode(frame)->co_filename, "line"); if (self->pcur_entry->file_data) { int lineno_from = -1; int lineno_to = -1; @@ -727,7 +738,7 @@ CTracer_handle_return(CTracer *self, PyFrameObject *frame) self->pcur_entry = &self->pdata_stack->stack[self->pdata_stack->depth]; if (self->tracing_arcs && self->pcur_entry->file_data) { BOOL real_return = FALSE; - pCode = MyCode_GetCode(PyFrame_GetCode(frame)); + pCode = MyCode_GetCode(MyFrame_BorrowCode(frame)); int lasti = MyFrame_GetLasti(frame); Py_ssize_t code_size = PyBytes_GET_SIZE(pCode); unsigned char * code_bytes = (unsigned char *)PyBytes_AS_STRING(pCode); @@ -759,7 +770,7 @@ CTracer_handle_return(CTracer *self, PyFrameObject *frame) real_return = !(is_yield || is_yield_from); #endif if (real_return) { - int first = PyFrame_GetCode(frame)->co_firstlineno; + int first = MyFrame_BorrowCode(frame)->co_firstlineno; if (CTracer_record_pair(self, self->pcur_entry->last_line, -first) < 0) { goto error; } @@ -782,7 +793,7 @@ CTracer_handle_return(CTracer *self, PyFrameObject *frame) } /* Pop the stack. */ - SHOWLOG(PyFrame_GetLineNumber(frame), PyFrame_GetCode(frame)->co_filename, "return"); + SHOWLOG(PyFrame_GetLineNumber(frame), MyFrame_BorrowCode(frame)->co_filename, "return"); self->pdata_stack->depth--; self->pcur_entry = &self->pdata_stack->stack[self->pdata_stack->depth]; } @@ -824,13 +835,13 @@ CTracer_trace(CTracer *self, PyFrameObject *frame, int what, PyObject *arg_unuse if (what <= (int)(sizeof(what_sym)/sizeof(const char *))) { w = what_sym[what]; } - ascii = PyUnicode_AsASCIIString(PyFrame_GetCode(frame)->co_filename); + ascii = PyUnicode_AsASCIIString(MyFrame_BorrowCode(frame)->co_filename); printf("%x trace: f:%x %s @ %s %d\n", (int)self, (int)frame, what_sym[what], PyBytes_AS_STRING(ascii), PyFrame_GetLineNumber(frame)); Py_DECREF(ascii); #endif #if TRACE_LOG - ascii = PyUnicode_AsASCIIString(PyFrame_GetCode(frame)->co_filename); + ascii = PyUnicode_AsASCIIString(MyFrame_BorrowCode(frame)->co_filename); if (strstr(PyBytes_AS_STRING(ascii), start_file) && PyFrame_GetLineNumber(frame) == start_line) { logging = TRUE; } @@ -926,7 +937,7 @@ CTracer_call(CTracer *self, PyObject *args, PyObject *kwds) } #if WHAT_LOG - ascii = PyUnicode_AsASCIIString(PyFrame_GetCode(frame)->co_filename); + ascii = PyUnicode_AsASCIIString(MyFrame_BorrowCode(frame)->co_filename); printf("pytrace: %s @ %s %d\n", what_sym[what], PyBytes_AS_STRING(ascii), PyFrame_GetLineNumber(frame)); Py_DECREF(ascii); #endif diff --git a/tests/test_oddball.py b/tests/test_oddball.py index 36626c620..900a587b4 100644 --- a/tests/test_oddball.py +++ b/tests/test_oddball.py @@ -206,6 +206,21 @@ def once(x): # line 301 if fails > 8: pytest.fail("RAM grew by %d" % (ram_growth)) # pragma: only failure + @pytest.mark.skipif(not testenv.C_TRACER, reason="Only the C tracer has refcounting issues") + # In fact, sysmon explicitly holds onto all code objects, + # so this will definitely fail with sysmon. + def test_eval_codeobject_leak(self) -> None: + # https://github.com/nedbat/coveragepy/issues/1924 + code = """\ + for i in range(100_000): + r = eval("'a' + '1'") + assert r == 'a1' + """ + ram_0 = osinfo.process_ram() + self.check_coverage(code, [1, 2, 3], "") + ram_growth = osinfo.process_ram() - ram_0 + assert ram_growth < 2_000 * 1024 + class MemoryFumblingTest(CoverageTest): """Test that we properly manage the None refcount.""" From f473b87e4116cceacdef1666a75feb4ba3cce0f3 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 8 Feb 2025 06:37:11 -0500 Subject: [PATCH 27/90] test: it could be useful to disable branch coverage in this helper --- tests/coveragetest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/coveragetest.py b/tests/coveragetest.py index a2c9c4a90..c5db35882 100644 --- a/tests/coveragetest.py +++ b/tests/coveragetest.py @@ -153,6 +153,7 @@ def check_coverage( partials: Iterable[str] = (), branchz: str | None = None, branchz_missing: str | None = None, + branch: bool = True, ) -> Coverage: """Check the coverage measurement of `text`. @@ -184,7 +185,7 @@ def check_coverage( branches_missing = arcz_to_arcs(branchz_missing) # Start up coverage.py. - cov = coverage.Coverage(branch=True) + cov = coverage.Coverage(branch=branch) cov.erase() for exc in excludes or []: cov.exclude(exc) From 27ee4ffc3b6486bc7b52dc5b18466e05fca8616e Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 8 Feb 2025 07:23:27 -0500 Subject: [PATCH 28/90] test: free-threading builds were failing the old leak test #1924 This is a subtler check for leaks, and still clearly distinguishes between the broken code and the fixed code. --- tests/test_oddball.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/tests/test_oddball.py b/tests/test_oddball.py index 900a587b4..90e4283a4 100644 --- a/tests/test_oddball.py +++ b/tests/test_oddball.py @@ -209,17 +209,25 @@ def once(x): # line 301 @pytest.mark.skipif(not testenv.C_TRACER, reason="Only the C tracer has refcounting issues") # In fact, sysmon explicitly holds onto all code objects, # so this will definitely fail with sysmon. - def test_eval_codeobject_leak(self) -> None: + @pytest.mark.parametrize("branch", [False, True]) + def test_eval_codeobject_leak(self, branch: bool) -> None: # https://github.com/nedbat/coveragepy/issues/1924 code = """\ - for i in range(100_000): + for i in range(10_000): r = eval("'a' + '1'") assert r == 'a1' """ - ram_0 = osinfo.process_ram() - self.check_coverage(code, [1, 2, 3], "") - ram_growth = osinfo.process_ram() - ram_0 - assert ram_growth < 2_000 * 1024 + # Looking for leaks is hard. We consider the leak fixed if at least + # one of our loops only increased the footprint by a small amount. + base = osinfo.process_ram() + deltas = [] + for _ in range(10): + self.check_coverage(code, [1, 2, 3], "", branch=branch) + now = osinfo.process_ram() + deltas.append(now - base) + print(f"Mem delta: {(now - base)//1024}") + base = now + assert any(d < 50 * 1024 for d in deltas) class MemoryFumblingTest(CoverageTest): From 938d519ba264ac67cdfcca8a436fe15a68318dc6 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 8 Feb 2025 09:03:28 -0500 Subject: [PATCH 29/90] docs: prep for 7.6.11 --- CHANGES.rst | 10 ++++++---- NOTICE.txt | 2 +- coverage/version.py | 4 ++-- doc/conf.py | 8 ++++---- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 8edf5a080..a9b6b058f 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -20,8 +20,12 @@ upgrading your version of coverage.py. .. Version 9.8.1 — 2027-07-27 .. -------------------------- -Unreleased ----------- +.. start-releases + +.. _changes_7-6-11: + +Version 7.6.11 — 2025-02-08 +--------------------------- - Fix: a memory leak in CTracer has been fixed. The details are in `issue 1924`_ and `pytest-dev 676`_. This should reduce the memory footprint for @@ -34,8 +38,6 @@ Unreleased .. _issue 1924: https://github.com/nedbat/coveragepy/issues/1924 .. _pytest-dev 676: https://github.com/pytest-dev/pytest-cov/issues/676 -.. start-releases - .. _changes_7-6-10: Version 7.6.10 — 2024-12-26 diff --git a/NOTICE.txt b/NOTICE.txt index 7376ffdda..05dd87e01 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -1,5 +1,5 @@ Copyright 2001 Gareth Rees. All rights reserved. -Copyright 2004-2024 Ned Batchelder. All rights reserved. +Copyright 2004-2025 Ned Batchelder. All rights reserved. Except where noted otherwise, this software is licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in diff --git a/coverage/version.py b/coverage/version.py index 68460a53e..940e744e8 100644 --- a/coverage/version.py +++ b/coverage/version.py @@ -8,8 +8,8 @@ # version_info: same semantics as sys.version_info. # _dev: the .devN suffix if any. -version_info = (7, 6, 11, "alpha", 0) -_dev = 1 +version_info = (7, 6, 11, "final", 0) +_dev = 0 def _make_version( diff --git a/doc/conf.py b/doc/conf.py index 9756049e0..9938799d7 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -65,13 +65,13 @@ # built documents. # @@@ editable -copyright = "2009–2024, Ned Batchelder" # pylint: disable=redefined-builtin +copyright = "2009–2025, Ned Batchelder" # pylint: disable=redefined-builtin # The short X.Y.Z version. -version = "7.6.10" +version = "7.6.11" # The full version, including alpha/beta/rc tags. -release = "7.6.10" +release = "7.6.11" # The date of release, in "monthname day, year" format. -release_date = "December 26, 2024" +release_date = "February 8, 2025" # @@@ end rst_epilog = f""" From a20898d2d48b2fb7ff30d3e63eb33de8e8948fe1 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 8 Feb 2025 09:03:45 -0500 Subject: [PATCH 30/90] docs: sample HTML for 7.6.11 --- doc/sample_html/class_index.html | 8 ++++---- doc/sample_html/function_index.html | 8 ++++---- doc/sample_html/index.html | 8 ++++---- doc/sample_html/status.json | 2 +- doc/sample_html/z_7b071bdc2a35fa80___init___py.html | 8 ++++---- doc/sample_html/z_7b071bdc2a35fa80___main___py.html | 8 ++++---- doc/sample_html/z_7b071bdc2a35fa80_cogapp_py.html | 8 ++++---- doc/sample_html/z_7b071bdc2a35fa80_makefiles_py.html | 8 ++++---- doc/sample_html/z_7b071bdc2a35fa80_test_cogapp_py.html | 8 ++++---- doc/sample_html/z_7b071bdc2a35fa80_test_makefiles_py.html | 8 ++++---- .../z_7b071bdc2a35fa80_test_whiteutils_py.html | 8 ++++---- doc/sample_html/z_7b071bdc2a35fa80_utils_py.html | 8 ++++---- doc/sample_html/z_7b071bdc2a35fa80_whiteutils_py.html | 8 ++++---- 13 files changed, 49 insertions(+), 49 deletions(-) diff --git a/doc/sample_html/class_index.html b/doc/sample_html/class_index.html index dcd0c2515..06601b11d 100644 --- a/doc/sample_html/class_index.html +++ b/doc/sample_html/class_index.html @@ -56,8 +56,8 @@

Classes

- coverage.py v7.6.10, - created at 2024-12-26 11:29 -0500 + coverage.py v7.6.11, + created at 2025-02-08 09:03 -0500

@@ -537,8 +537,8 @@

- coverage.py v7.6.10, - created at 2024-12-26 11:29 -0500 + coverage.py v7.6.11, + created at 2025-02-08 09:03 -0500

diff --git a/doc/sample_html/z_7b071bdc2a35fa80_makefiles_py.html b/doc/sample_html/z_7b071bdc2a35fa80_makefiles_py.html index 3c0f62ea4..55e0e8d4f 100644 --- a/doc/sample_html/z_7b071bdc2a35fa80_makefiles_py.html +++ b/doc/sample_html/z_7b071bdc2a35fa80_makefiles_py.html @@ -66,8 +66,8 @@

^ index     » next       - coverage.py v7.6.10, - created at 2024-12-26 11:29 -0500 + coverage.py v7.6.11, + created at 2025-02-08 09:03 -0500