summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/inspect.py19
-rw-r--r--Lib/test/inspect_fodder2.py33
-rw-r--r--Lib/test/test_inspect.py44
3 files changed, 91 insertions, 5 deletions
diff --git a/Lib/inspect.py b/Lib/inspect.py
index 661957b..05bb71b 100644
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -432,7 +432,7 @@ def findsource(object):
if not hasattr(object, 'co_firstlineno'):
raise IOError('could not find function definition')
lnum = object.co_firstlineno - 1
- pat = re.compile(r'^(\s*def\s)|(.*\slambda(:|\s))|^(\s*@)')
+ pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
while lnum > 0:
if pat.match(lines[lnum]): break
lnum = lnum - 1
@@ -503,17 +503,28 @@ class BlockFinder:
"""Provide a tokeneater() method to detect the end of a code block."""
def __init__(self):
self.indent = 0
- self.started = 0
+ self.started = False
+ self.passline = False
self.last = 0
def tokeneater(self, type, token, (srow, scol), (erow, ecol), line):
if not self.started:
- if '@' in line: pass
- elif type == tokenize.NAME: self.started = 1
+ if token in ("def", "class", "lambda"):
+ lastcolon = line.rfind(":")
+ if lastcolon:
+ oneline = re.search(r"\w", line[lastcolon:])
+ if oneline and line[-2:] != "\\\n":
+ raise EndOfBlock, srow
+ self.started = True
+ self.passline = True
elif type == tokenize.NEWLINE:
+ self.passline = False
self.last = srow
+ elif self.passline:
+ pass
elif type == tokenize.INDENT:
self.indent = self.indent + 1
+ self.passline = True
elif type == tokenize.DEDENT:
self.indent = self.indent - 1
if self.indent == 0:
diff --git a/Lib/test/inspect_fodder2.py b/Lib/test/inspect_fodder2.py
index 19da352..ce42929 100644
--- a/Lib/test/inspect_fodder2.py
+++ b/Lib/test/inspect_fodder2.py
@@ -20,3 +20,36 @@ def wrapped():
@replace
def gone():
pass
+
+# line 24
+oll = lambda m: m
+
+# line 27
+tll = lambda g: g and \
+g and \
+g
+
+# line 32
+tlli = lambda d: d and \
+ d
+
+# line 36
+def onelinefunc(): pass
+
+# line 39
+def manyargs(arg1, arg2,
+arg3, arg4): pass
+
+# line 43
+def twolinefunc(m): return m and \
+m
+
+# line 47
+a = [None,
+ lambda x: x,
+ None]
+
+# line 52
+def setfunc(func):
+ globals()["anonymous"] = func
+setfunc(lambda x, y: x*y)
diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
index 3f2da0a..04f22b4 100644
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -187,6 +187,48 @@ class TestDecorators(GetSourceBase):
def test_replacing_decorator(self):
self.assertSourceEqual(mod2.gone, 9, 10)
+class TestOneliners(GetSourceBase):
+ fodderFile = mod2
+ def test_oneline_lambda(self):
+ # Test inspect.getsource with a one-line lambda function.
+ self.assertSourceEqual(mod2.oll, 25, 25)
+
+ def test_threeline_lambda(self):
+ # Test inspect.getsource with a three-line lambda function,
+ # where the second and third lines are _not_ indented.
+ self.assertSourceEqual(mod2.tll, 28, 30)
+
+ def test_twoline_indented_lambda(self):
+ # Test inspect.getsource with a two-line lambda function,
+ # where the second line _is_ indented.
+ self.assertSourceEqual(mod2.tlli, 33, 34)
+
+ def test_onelinefunc(self):
+ # Test inspect.getsource with a regular one-line function.
+ self.assertSourceEqual(mod2.onelinefunc, 37, 37)
+
+ def test_manyargs(self):
+ # Test inspect.getsource with a regular function where
+ # the arguments are on two lines and _not_ indented and
+ # the body on the second line with the last arguments.
+ self.assertSourceEqual(mod2.manyargs, 40, 41)
+
+ def test_twolinefunc(self):
+ # Test inspect.getsource with a regular function where
+ # the body is on two lines, following the argument list and
+ # continued on the next line by a \\.
+ self.assertSourceEqual(mod2.twolinefunc, 44, 45)
+
+ def test_lambda_in_list(self):
+ # Test inspect.getsource with a one-line lambda function
+ # defined in a list, indented.
+ self.assertSourceEqual(mod2.a[1], 49, 49)
+
+ def test_anonymous(self):
+ # Test inspect.getsource with a lambda function defined
+ # as argument to another function.
+ self.assertSourceEqual(mod2.anonymous, 55, 55)
+
# Helper for testing classify_class_attrs.
def attrs_wo_objs(cls):
return [t[:3] for t in inspect.classify_class_attrs(cls)]
@@ -371,7 +413,7 @@ class TestClassesAndFunctions(unittest.TestCase):
self.assert_(('datablob', 'data', A) in attrs, 'missing data')
def test_main():
- run_unittest(TestDecorators, TestRetrievingSourceCode,
+ run_unittest(TestDecorators, TestRetrievingSourceCode, TestOneliners,
TestInterpreterStack, TestClassesAndFunctions, TestPredicates)
if __name__ == "__main__":