[3.13] gh-137477: Fix inspect.getblock() for generator expressions (GH-137488) (GH-137995)
Some checks are pending
Tests / Hypothesis tests on Ubuntu (push) Blocked by required conditions
Tests / Windows MSI (push) Blocked by required conditions
Tests / Change detection (push) Waiting to run
Tests / Docs (push) Blocked by required conditions
Tests / (push) Blocked by required conditions
Tests / Check if the ABI has changed (push) Blocked by required conditions
Tests / Check if Autoconf files are up to date (push) Blocked by required conditions
Tests / Check if generated files are up to date (push) Blocked by required conditions
Tests / Android (x86_64) (push) Blocked by required conditions
Tests / Ubuntu SSL tests with OpenSSL (push) Blocked by required conditions
Tests / Android (aarch64) (push) Blocked by required conditions
Tests / WASI (push) Blocked by required conditions
Tests / Address sanitizer (push) Blocked by required conditions
Tests / Sanitizers (push) Blocked by required conditions
Tests / CIFuzz (push) Blocked by required conditions
Tests / All required checks pass (push) Blocked by required conditions
Lint / lint (push) Waiting to run

This fixes also inspect.getsourcelines() and inspect.getsource().
(cherry picked from commit eae9d7de1c)
This commit is contained in:
Serhiy Storchaka 2025-08-20 16:43:28 +03:00 committed by GitHub
parent 47b1c5d74e
commit c04b3de517
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 38 additions and 7 deletions

View file

@ -1159,7 +1159,7 @@ class BlockFinder:
"""Provide a tokeneater() method to detect the end of a code block."""
def __init__(self):
self.indent = 0
self.islambda = False
self.singleline = False
self.started = False
self.passline = False
self.indecorator = False
@ -1168,19 +1168,22 @@ class BlockFinder:
def tokeneater(self, type, token, srowcol, erowcol, line):
if not self.started and not self.indecorator:
if type == tokenize.INDENT or token == "async":
pass
# skip any decorators
if token == "@":
elif token == "@":
self.indecorator = True
# look for the first "def", "class" or "lambda"
elif token in ("def", "class", "lambda"):
if token == "lambda":
self.islambda = True
else:
# For "def" and "class" scan to the end of the block.
# For "lambda" and generator expression scan to
# the end of the logical line.
self.singleline = token not in ("def", "class")
self.started = True
self.passline = True # skip to the end of the line
elif type == tokenize.NEWLINE:
self.passline = False # stop skipping when a NEWLINE is seen
self.last = srowcol[0]
if self.islambda: # lambdas always end at the first NEWLINE
if self.singleline:
raise EndOfBlock
# hitting a NEWLINE when in a decorator without args
# ends the decorator

View file

@ -369,3 +369,23 @@ class dc364:
# line 369
dc370 = dataclasses.make_dataclass('dc370', (('x', int), ('y', int)))
dc371 = dataclasses.make_dataclass('dc370', (('x', int), ('y', int)), module=__name__)
import inspect
import itertools
# line 376
ge377 = (
inspect.currentframe()
for i in itertools.count()
)
# line 382
def func383():
# line 384
ge385 = (
inspect.currentframe()
for i in itertools.count()
)
return ge385
pass # end of file

View file

@ -1187,12 +1187,18 @@ class TestBuggyCases(GetSourceBase):
self.addCleanup(asyncio.set_event_loop_policy, None)
self.assertSourceEqual(asyncio.run(mod2.func225()), 226, 227)
self.assertSourceEqual(mod2.cls226, 231, 235)
self.assertSourceEqual(mod2.cls226.func232, 232, 235)
self.assertSourceEqual(asyncio.run(mod2.cls226().func232()), 233, 234)
def test_class_definition_same_name_diff_methods(self):
self.assertSourceEqual(mod2.cls296, 296, 298)
self.assertSourceEqual(mod2.cls310, 310, 312)
def test_generator_expression(self):
self.assertSourceEqual(next(mod2.ge377), 377, 380)
self.assertSourceEqual(next(mod2.func383()), 385, 388)
class TestNoEOL(GetSourceBase):
def setUp(self):
self.tempdir = TESTFN + '_dir'

View file

@ -0,0 +1,2 @@
Fix :func:`!inspect.getblock`, :func:`inspect.getsourcelines` and
:func:`inspect.getsource` for generator expressions.