Skip to content

Commit fe7c309

Browse files
gh-83035: handle decorator with nested parens in inspect.getsource (GH-99654)
(cherry picked from commit 68e4129) Co-authored-by: Carl Meyer <[email protected]>
1 parent 72cfe5b commit fe7c309

File tree

4 files changed

+22
-9
lines changed

4 files changed

+22
-9
lines changed

Lib/inspect.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,7 +1052,6 @@ def __init__(self):
10521052
self.started = False
10531053
self.passline = False
10541054
self.indecorator = False
1055-
self.decoratorhasargs = False
10561055
self.last = 1
10571056
self.body_col0 = None
10581057

@@ -1067,21 +1066,14 @@ def tokeneater(self, type, token, srowcol, erowcol, line):
10671066
self.islambda = True
10681067
self.started = True
10691068
self.passline = True # skip to the end of the line
1070-
elif token == "(":
1071-
if self.indecorator:
1072-
self.decoratorhasargs = True
1073-
elif token == ")":
1074-
if self.indecorator:
1075-
self.indecorator = False
1076-
self.decoratorhasargs = False
10771069
elif type == tokenize.NEWLINE:
10781070
self.passline = False # stop skipping when a NEWLINE is seen
10791071
self.last = srowcol[0]
10801072
if self.islambda: # lambdas always end at the first NEWLINE
10811073
raise EndOfBlock
10821074
# hitting a NEWLINE when in a decorator without args
10831075
# ends the decorator
1084-
if self.indecorator and not self.decoratorhasargs:
1076+
if self.indecorator:
10851077
self.indecorator = False
10861078
elif self.passline:
10871079
pass

Lib/test/inspect_fodder2.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,3 +259,17 @@ def all_markers_with_args_and_kwargs(a, b, /, c, d, *args, e, f, **kwargs):
259259
#line 259
260260
def all_markers_with_defaults(a, b=1, /, c=2, d=3, *, e=4, f=5):
261261
pass
262+
263+
# line 263
264+
def deco_factory(**kwargs):
265+
def deco(f):
266+
@wraps(f)
267+
def wrapper(*a, **kwd):
268+
kwd.update(kwargs)
269+
return f(*a, **kwd)
270+
return wrapper
271+
return deco
272+
273+
@deco_factory(foo=(1 + 2), bar=lambda: 1)
274+
def complex_decorated(foo=0, bar=lambda: 0):
275+
return foo + bar()

Lib/test/test_inspect.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,12 @@ def test_class(self):
825825
self.assertSourceEqual(self.fodderModule.X, 1, 2)
826826

827827

828+
class TestComplexDecorator(GetSourceBase):
829+
fodderModule = mod2
830+
831+
def test_parens_in_decorator(self):
832+
self.assertSourceEqual(self.fodderModule.complex_decorated, 273, 275)
833+
828834
class _BrokenDataDescriptor(object):
829835
"""
830836
A broken data descriptor. See bug #1785.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix :func:`inspect.getsource` handling of decorator calls with nested parentheses.

0 commit comments

Comments
 (0)