From cb810ae379ab405b1a608d457bb0f108417b66ae Mon Sep 17 00:00:00 2001 From: tonghuaroot Date: Sat, 27 Jun 2026 21:22:22 +0800 Subject: [PATCH 1/2] gh-152409: Save the trace --file counts when --no-report is used The counts were only persisted at the end of CoverageResults.write_results(), which main() skips when --no-report is given, so --no-report --file silently discarded them. Move that step into CoverageResults.save_counts() (still called from write_results()) and call it on the --no-report branch too. --- Lib/test/test_trace.py | 24 ++++++++++++++++++- Lib/trace.py | 7 +++++- ...-06-27-10-30-00.gh-issue-152409.Tr8cE2.rst | 3 +++ 3 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-27-10-30-00.gh-issue-152409.Tr8cE2.rst diff --git a/Lib/test/test_trace.py b/Lib/test/test_trace.py index 19eee19bdea6d5..241e841d732f5e 100644 --- a/Lib/test/test_trace.py +++ b/Lib/test/test_trace.py @@ -1,5 +1,5 @@ import os -from pickle import dump +from pickle import dump, load import sys from test.support import captured_stdout, requires_resource from test.support.os_helper import (TESTFN, rmtree, unlink) @@ -561,6 +561,28 @@ def f(): self.assertIn('lines cov% module (path)', stdout) self.assertIn(f'6 100.0% {modulename} ({filename})', stdout) + def test_count_no_report_accumulates_counts(self): + # --no-report must still save the --file counts so they accumulate. + filename = f'{TESTFN}.py' + countsfile = f'{TESTFN}.counts' + with open(filename, 'w', encoding='utf-8') as fd: + self.addCleanup(unlink, filename) + self.addCleanup(unlink, countsfile) + fd.write('for i in range(3):\n pass\n') + argv = ('-m', 'trace', '--count', '--no-report', + '--file', countsfile, filename) + assert_python_ok(*argv, PYTHONIOENCODING='utf-8') + self.assertTrue(os.path.exists(countsfile)) + with open(countsfile, 'rb') as fd: + counts = load(fd)[0] + self.assertTrue(counts) + # A second run accumulates into the same file. + assert_python_ok(*argv, PYTHONIOENCODING='utf-8') + with open(countsfile, 'rb') as fd: + accumulated = load(fd)[0] + self.assertEqual(accumulated, + {key: 2 * value for key, value in counts.items()}) + def test_run_as_module(self): assert_python_ok('-m', 'trace', '-l', '--module', 'timeit', '-n', '1') assert_python_failure('-m', 'trace', '-l', '--module', 'not_a_module_zzz') diff --git a/Lib/trace.py b/Lib/trace.py index 43ec201c4696d1..0d92fa3b7cd6ad 100644 --- a/Lib/trace.py +++ b/Lib/trace.py @@ -287,8 +287,11 @@ def write_results(self, show_missing=True, summary=False, coverdir=None, *, n_lines, n_hits, modulename, filename = sums[m] print(f"{n_lines:5d} {n_hits/n_lines:.1%} {modulename} ({filename})") + self.save_counts() + + def save_counts(self): + """Save the accumulated counts to ``self.outfile`` if one was given.""" if self.outfile: - # try and store counts and module info into self.outfile try: with open(self.outfile, 'wb') as f: pickle.dump((self.counts, self.calledfuncs, self.callers), @@ -744,6 +747,8 @@ def parse_ignore_dir(s): if not opts.no_report: results.write_results(opts.missing, opts.summary, opts.coverdir) + else: + results.save_counts() if __name__=='__main__': main() diff --git a/Misc/NEWS.d/next/Library/2026-06-27-10-30-00.gh-issue-152409.Tr8cE2.rst b/Misc/NEWS.d/next/Library/2026-06-27-10-30-00.gh-issue-152409.Tr8cE2.rst new file mode 100644 index 00000000000000..2e6a759a102e66 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-27-10-30-00.gh-issue-152409.Tr8cE2.rst @@ -0,0 +1,3 @@ +Fix the :mod:`trace` command-line tool not saving the ``--file`` counts +when ``--no-report`` is used, which prevented accumulating counts over +several runs. Patch by tonghuaroot. From 19c6975e4c9d0f7902fe5d1180c9d8bffbf57e7e Mon Sep 17 00:00:00 2001 From: tonghuaroot Date: Tue, 18 Aug 2026 18:19:10 +0800 Subject: [PATCH 2/2] Make save_counts() private --- Lib/trace.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/trace.py b/Lib/trace.py index 0d92fa3b7cd6ad..66471f45e1c004 100644 --- a/Lib/trace.py +++ b/Lib/trace.py @@ -287,9 +287,9 @@ def write_results(self, show_missing=True, summary=False, coverdir=None, *, n_lines, n_hits, modulename, filename = sums[m] print(f"{n_lines:5d} {n_hits/n_lines:.1%} {modulename} ({filename})") - self.save_counts() + self._save_counts() - def save_counts(self): + def _save_counts(self): """Save the accumulated counts to ``self.outfile`` if one was given.""" if self.outfile: try: @@ -748,7 +748,7 @@ def parse_ignore_dir(s): if not opts.no_report: results.write_results(opts.missing, opts.summary, opts.coverdir) else: - results.save_counts() + results._save_counts() if __name__=='__main__': main()