Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions Lib/test/test_trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,57 @@ def test_cover_files_written_with_highlight(self):
>>>>>> print('unreachable')
'''))


# gh-142867: Deferred annotations (PEP 649) should not appear as not covered
class TestCoverageAnnotations(unittest.TestCase):

codefile = 'tmp_annotations.py'
coverfile = 'tmp_annotations.cover'

def tearDown(self):
unlink(self.codefile)
unlink(self.coverfile)

def test_multiline_annotation_not_marked_uncovered(self):
# gh-142867: Multiline type annotations should not be marked as
# uncovered since annotation evaluation is deferred (PEP 649)
with open(self.codefile, 'w', encoding='utf-8') as f:
f.write(textwrap.dedent('''\
def x() -> tuple[
int,
]:
return (1,)

x()
'''))
argv = '-m trace --count --missing'.split() + [self.codefile]
status, stdout, stderr = assert_python_ok(*argv)
self.assertTrue(os.path.exists(self.coverfile))
with open(self.coverfile, encoding='utf-8') as f:
content = f.read()
# The multiline annotation (line 2: "int,") should NOT be marked
# as uncovered with ">>>>>>". It should have a blank prefix since
# annotation lines are not executed during normal program flow.
self.assertNotIn('>>>>>> ', content)

def test_class_annotation_not_marked_uncovered(self):
# Class attribute annotations should not be marked as uncovered
with open(self.codefile, 'w', encoding='utf-8') as f:
f.write(textwrap.dedent('''\
class X:
a: int

x = X()
'''))
argv = '-m trace --count --missing'.split() + [self.codefile]
status, stdout, stderr = assert_python_ok(*argv)
self.assertTrue(os.path.exists(self.coverfile))
with open(self.coverfile, encoding='utf-8') as f:
content = f.read()
# The annotation line should NOT be marked as uncovered
self.assertNotIn('>>>>>> ', content)


class TestCommandLine(unittest.TestCase):

def test_failures(self):
Expand Down
3 changes: 3 additions & 0 deletions Lib/trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,9 @@ def _find_lines(code, strs):
# and check the constants for references to other code objects
for c in code.co_consts:
if inspect.iscode(c):
# skip __annotate__ code objects (PEP 649)
if c.co_name == "__annotate__":
continue
# find another code object, so recurse into it
linenos.update(_find_lines(c, strs))
return linenos
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix :mod:`trace` module incorrectly marking deferred annotations (PEP 649)
as not covered in ``--count --missing`` mode.
Loading