[Python-checkins] gh-83035: handle decorator with nested parens in inspect.getsource (GH-99654)

miss-islington webhook-mailer at python.org
Wed Dec 7 12:26:17 EST 2022


https://github.com/python/cpython/commit/2997f3913a7f644352a1d4013588451837d2ac58
commit: 2997f3913a7f644352a1d4013588451837d2ac58
branch: 3.11
author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
committer: miss-islington <31488909+miss-islington at users.noreply.github.com>
date: 2022-12-07T09:26:11-08:00
summary:

gh-83035: handle decorator with nested parens in inspect.getsource (GH-99654)

(cherry picked from commit 68e41295b8611a990de68f15c89f1eb3dea51867)

Co-authored-by: Carl Meyer <carl at oddbird.net>

files:
A Misc/NEWS.d/next/Library/2022-11-21-16-24-01.gh-issue-83035.qZIujU.rst
M Lib/inspect.py
M Lib/test/inspect_fodder2.py
M Lib/test/test_inspect.py

diff --git a/Lib/inspect.py b/Lib/inspect.py
index d1a9daf28913..cab92b6b8fb8 100644
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -1175,7 +1175,6 @@ def __init__(self):
         self.started = False
         self.passline = False
         self.indecorator = False
-        self.decoratorhasargs = False
         self.last = 1
         self.body_col0 = None
 
@@ -1190,13 +1189,6 @@ def tokeneater(self, type, token, srowcol, erowcol, line):
                     self.islambda = True
                 self.started = True
             self.passline = True    # skip to the end of the line
-        elif token == "(":
-            if self.indecorator:
-                self.decoratorhasargs = True
-        elif token == ")":
-            if self.indecorator:
-                self.indecorator = False
-                self.decoratorhasargs = False
         elif type == tokenize.NEWLINE:
             self.passline = False   # stop skipping when a NEWLINE is seen
             self.last = srowcol[0]
@@ -1204,7 +1196,7 @@ def tokeneater(self, type, token, srowcol, erowcol, line):
                 raise EndOfBlock
             # hitting a NEWLINE when in a decorator without args
             # ends the decorator
-            if self.indecorator and not self.decoratorhasargs:
+            if self.indecorator:
                 self.indecorator = False
         elif self.passline:
             pass
diff --git a/Lib/test/inspect_fodder2.py b/Lib/test/inspect_fodder2.py
index e7d4b53ebefc..2dc49817087c 100644
--- a/Lib/test/inspect_fodder2.py
+++ b/Lib/test/inspect_fodder2.py
@@ -259,3 +259,17 @@ def all_markers_with_args_and_kwargs(a, b, /, c, d, *args, e, f, **kwargs):
 #line 259
 def all_markers_with_defaults(a, b=1, /, c=2, d=3, *, e=4, f=5):
     pass
+
+# line 263
+def deco_factory(**kwargs):
+    def deco(f):
+        @wraps(f)
+        def wrapper(*a, **kwd):
+            kwd.update(kwargs)
+            return f(*a, **kwd)
+        return wrapper
+    return deco
+
+ at deco_factory(foo=(1 + 2), bar=lambda: 1)
+def complex_decorated(foo=0, bar=lambda: 0):
+    return foo + bar()
diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
index a54e6eb53e68..6c5e674aa69f 100644
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -886,6 +886,12 @@ def test_class(self):
         self.assertSourceEqual(self.fodderModule.X, 1, 2)
 
 
+class TestComplexDecorator(GetSourceBase):
+    fodderModule = mod2
+
+    def test_parens_in_decorator(self):
+        self.assertSourceEqual(self.fodderModule.complex_decorated, 273, 275)
+
 class _BrokenDataDescriptor(object):
     """
     A broken data descriptor. See bug #1785.
diff --git a/Misc/NEWS.d/next/Library/2022-11-21-16-24-01.gh-issue-83035.qZIujU.rst b/Misc/NEWS.d/next/Library/2022-11-21-16-24-01.gh-issue-83035.qZIujU.rst
new file mode 100644
index 000000000000..629d9aefb2d8
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-11-21-16-24-01.gh-issue-83035.qZIujU.rst
@@ -0,0 +1 @@
+Fix :func:`inspect.getsource` handling of decorator calls with nested parentheses.



More information about the Python-checkins mailing list