[Python-checkins] cpython (3.5): Issue #24485: Function source inspection fails on closures.

meador.inge python-checkins at python.org
Fri Jul 24 06:00:12 CEST 2015


https://hg.python.org/cpython/rev/5400e21e92a7
changeset:   97032:5400e21e92a7
branch:      3.5
parent:      97030:732de5ba1f2b
user:        Meador Inge <meadori at gmail.com>
date:        Thu Jul 23 22:49:37 2015 -0500
summary:
  Issue #24485: Function source inspection fails on closures.

The fix for Issue #21217 introduced a regression that caused
`inspect.getsource` to return incorrect results on nested
functions.  The root cause of the regression was due to
switching the implementation to analyze the underlying
bytecode instead of the source code.

This commit switches things back to analyzing the source code
in a more complete way.  The original bug and the regression
are both fixed by the new source code analysis.

files:
  Lib/inspect.py           |  26 ++++++++++++++++++++++----
  Lib/test/test_inspect.py |   1 -
  Misc/NEWS                |   7 +++++++
  3 files changed, 29 insertions(+), 5 deletions(-)


diff --git a/Lib/inspect.py b/Lib/inspect.py
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -859,21 +859,37 @@
         self.islambda = False
         self.started = False
         self.passline = False
+        self.indecorator = False
+        self.decoratorhasargs = False
         self.last = 1
 
     def tokeneater(self, type, token, srowcol, erowcol, line):
-        if not self.started:
+        if not self.started and not self.indecorator:
+            # skip any decorators
+            if token == "@":
+                self.indecorator = True
             # look for the first "def", "class" or "lambda"
-            if token in ("def", "class", "lambda"):
+            elif token in ("def", "class", "lambda"):
                 if token == "lambda":
                     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]
             if self.islambda:       # lambdas always end at the first NEWLINE
                 raise EndOfBlock
+            # hitting a NEWLINE when in a decorator without args
+            # ends the decorator
+            if self.indecorator and not self.decoratorhasargs:
+                self.indecorator = False
         elif self.passline:
             pass
         elif type == tokenize.INDENT:
@@ -913,8 +929,10 @@
     object = unwrap(object)
     lines, lnum = findsource(object)
 
-    if ismodule(object): return lines, 0
-    else: return getblock(lines[lnum:]), lnum + 1
+    if ismodule(object):
+        return lines, 0
+    else:
+        return getblock(lines[lnum:]), lnum + 1
 
 def getsource(object):
     """Return the text of the source code for an object.
diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -464,7 +464,6 @@
     def test_getsource_unwrap(self):
         self.assertSourceEqual(mod2.real, 130, 132)
 
-    @unittest.expectedFailure
     def test_decorator_with_lambda(self):
         self.assertSourceEqual(mod2.func114, 113, 115)
 
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -28,6 +28,9 @@
 Library
 -------
 
+- Issue #22485: Fixed an issue that caused `inspect.getsource` to return incorrect
+  results on nested functions.
+
 - Issue #22153: Improve unittest docs. Patch from Martin Panter and evilzero.
 
 - Issue #24580: Symbolic group references to open group in re patterns now are
@@ -551,6 +554,10 @@
 - Issue #23342: Add a subprocess.run() function than returns a CalledProcess
   instance for a more consistent API than the existing call* functions.
 
+- Issue #21217: inspect.getsourcelines() now tries to compute the start and end
+  lines from the code object, fixing an issue when a lambda function is used as
+  decorator argument. Patch by Thomas Ballinger and Allison Kaptur.
+
 - Issue #24521: Fix possible integer overflows in the pickle module.
 
 - Issue #22931: Allow '[' and ']' in cookie values.

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list