From 86788502be80058e840841522a0049b941c67745 Mon Sep 17 00:00:00 2001 From: orlnub123 Date: Mon, 29 Oct 2018 05:43:24 +0300 Subject: [PATCH 1/7] Fix findsource breaking on class frame objects --- Lib/inspect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/inspect.py b/Lib/inspect.py index b8a142232b88a0..bf8acdee149329 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -826,7 +826,7 @@ def findsource(object): if not hasattr(object, 'co_firstlineno'): raise OSError('could not find function definition') lnum = object.co_firstlineno - 1 - pat = re.compile(r'^(\s*def\s)|(\s*async\s+def\s)|(.*(? 0: if pat.match(lines[lnum]): break lnum = lnum - 1 From aeb294d0acd27c59e60c96c9363e36a1924348bb Mon Sep 17 00:00:00 2001 From: orlnub123 Date: Mon, 29 Oct 2018 06:04:39 +0300 Subject: [PATCH 2/7] Add test --- Lib/test/inspect_fodder2.py | 5 +++++ Lib/test/test_inspect.py | 2 ++ 2 files changed, 7 insertions(+) diff --git a/Lib/test/inspect_fodder2.py b/Lib/test/inspect_fodder2.py index c6987ea2c9e485..d5a7dbcd83f49a 100644 --- a/Lib/test/inspect_fodder2.py +++ b/Lib/test/inspect_fodder2.py @@ -137,3 +137,8 @@ def func136(): def func137(): never_reached1 never_reached2 + +#line 141 +class cls142: + import inspect + frame144 = inspect.currentframe() diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index b9072e0137eb08..2b3e9d0d60a6da 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -676,6 +676,8 @@ def test_getsource_on_method(self): def test_nested_func(self): self.assertSourceEqual(mod2.cls135.func136, 136, 139) + def test_getsource_on_class_frame(self): + self.assertSourceEqual(mod2.cls142.frame144, 142, 144) class TestNoEOL(GetSourceBase): def setUp(self): From e997f4d4e823d9323d4f494969642f559f60fca5 Mon Sep 17 00:00:00 2001 From: orlnub123 Date: Mon, 29 Oct 2018 07:18:39 +0300 Subject: [PATCH 3/7] Add news entry --- .../next/Library/2018-10-29-04-14-58.bpo-35101.xImh8d.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2018-10-29-04-14-58.bpo-35101.xImh8d.rst diff --git a/Misc/NEWS.d/next/Library/2018-10-29-04-14-58.bpo-35101.xImh8d.rst b/Misc/NEWS.d/next/Library/2018-10-29-04-14-58.bpo-35101.xImh8d.rst new file mode 100644 index 00000000000000..375aef20ca7b94 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-10-29-04-14-58.bpo-35101.xImh8d.rst @@ -0,0 +1,2 @@ +Fix inspect.findsource incorrectly returning the line number of the first +function above any given class frame objects. From c55f94109afb1997459bf116c68f1614771a9b79 Mon Sep 17 00:00:00 2001 From: orlnub123 Date: Thu, 1 Nov 2018 04:28:21 +0300 Subject: [PATCH 4/7] Remove previous test --- Lib/test/inspect_fodder2.py | 5 ----- Lib/test/test_inspect.py | 3 --- 2 files changed, 8 deletions(-) diff --git a/Lib/test/inspect_fodder2.py b/Lib/test/inspect_fodder2.py index d5a7dbcd83f49a..c6987ea2c9e485 100644 --- a/Lib/test/inspect_fodder2.py +++ b/Lib/test/inspect_fodder2.py @@ -137,8 +137,3 @@ def func136(): def func137(): never_reached1 never_reached2 - -#line 141 -class cls142: - import inspect - frame144 = inspect.currentframe() diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 2b3e9d0d60a6da..48fe6a163dbff6 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -676,9 +676,6 @@ def test_getsource_on_method(self): def test_nested_func(self): self.assertSourceEqual(mod2.cls135.func136, 136, 139) - def test_getsource_on_class_frame(self): - self.assertSourceEqual(mod2.cls142.frame144, 142, 144) - class TestNoEOL(GetSourceBase): def setUp(self): self.tempdir = TESTFN + '_dir' From d3bb9f7d714e762a4185f57db4b8164b1bd37e5b Mon Sep 17 00:00:00 2001 From: orlnub123 Date: Thu, 1 Nov 2018 04:29:12 +0300 Subject: [PATCH 5/7] Add new tests --- Lib/test/inspect_fodder.py | 23 +++++++++++++++++++++++ Lib/test/test_inspect.py | 16 ++++++++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/Lib/test/inspect_fodder.py b/Lib/test/inspect_fodder.py index ff3f0e4b73b9ad..79182d08f8ee41 100644 --- a/Lib/test/inspect_fodder.py +++ b/Lib/test/inspect_fodder.py @@ -80,3 +80,26 @@ async def lobbest(grenade): raise Exception() except: tb = sys.exc_info()[2] + +# line 84 +def extra_a(): + pass +class A: + def func(self): + pass + fr = inspect.currentframe() + +# line 92 +extra_b = 1 +class B: + def func(self): + pass + fr = inspect.currentframe() + +# line 99 +def extra_c(): + pass +class C: + def func(self): + pass + fr = inspect.currentframe() diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 48fe6a163dbff6..8c34ff227a26d8 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -375,6 +375,10 @@ def assertSourceEqual(self, obj, top, bottom): self.assertEqual(inspect.getsource(obj), self.sourcerange(top, bottom)) + def assertNotSourceEqual(self, obj, top, bottom): + self.assertNotEqual(inspect.getsource(obj), + self.sourcerange(top, bottom)) + class TestRetrievingSourceCode(GetSourceBase): fodderModule = mod @@ -552,7 +556,7 @@ def monkey(filename, module_globals=None): def test_getsource_on_code_object(self): self.assertSourceEqual(mod.eggs.__code__, 12, 18) -class TestGettingSourceOfToplevelFrames(GetSourceBase): +class TestGettingSourceOfFrames(GetSourceBase): fodderModule = mod def test_range_toplevel_frame(self): @@ -562,6 +566,14 @@ def test_range_toplevel_frame(self): def test_range_traceback_toplevel_frame(self): self.assertSourceEqual(mod.tb, 1, None) + def test_class_frame(self): + self.assertSourceEqual(mod.A.fr, 87, 90) + self.assertNotSourceEqual(mod.A.fr, 85, 86) + self.assertSourceEqual(mod.B.fr, 94, 97) + self.assertNotSourceEqual(mod.B.fr, 87, 90) + self.assertSourceEqual(mod.C.fr, 102, 105) + self.assertNotSourceEqual(mod.C.fr, 100, 101) + class TestDecorators(GetSourceBase): fodderModule = mod2 @@ -3904,7 +3916,7 @@ def test_main(): TestBoundArguments, TestSignaturePrivateHelpers, TestSignatureDefinitions, TestIsDataDescriptor, TestGetClosureVars, TestUnwrap, TestMain, TestReload, - TestGetCoroutineState, TestGettingSourceOfToplevelFrames + TestGetCoroutineState, TestGettingSourceOfFrames ) if __name__ == "__main__": From 77009c89fbd21f41547e08b0bb30ace71c79ef7d Mon Sep 17 00:00:00 2001 From: orlnub123 Date: Thu, 1 Nov 2018 04:51:07 +0300 Subject: [PATCH 6/7] Fix tests --- Lib/test/test_inspect.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 8c34ff227a26d8..bc1b0a1b0aff9f 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -385,7 +385,10 @@ class TestRetrievingSourceCode(GetSourceBase): def test_getclasses(self): classes = inspect.getmembers(mod, inspect.isclass) self.assertEqual(classes, - [('FesteringGob', mod.FesteringGob), + [('A', mod.A), + ('B', mod.B), + ('C', mod.C), + ('FesteringGob', mod.FesteringGob), ('MalodorousPervert', mod.MalodorousPervert), ('ParrotDroppings', mod.ParrotDroppings), ('StupidGit', mod.StupidGit), @@ -394,7 +397,10 @@ def test_getclasses(self): tree = inspect.getclasstree([cls[1] for cls in classes]) self.assertEqual(tree, [(object, ()), - [(mod.ParrotDroppings, (object,)), + [(mod.A, (object,)), + (mod.B, (object,)), + (mod.C, (object,)), + (mod.ParrotDroppings, (object,)), [(mod.FesteringGob, (mod.MalodorousPervert, mod.ParrotDroppings)) ], @@ -409,7 +415,10 @@ def test_getclasses(self): tree = inspect.getclasstree([cls[1] for cls in classes], True) self.assertEqual(tree, [(object, ()), - [(mod.ParrotDroppings, (object,)), + [(mod.A, (object,)), + (mod.B, (object,)), + (mod.C, (object,)), + (mod.ParrotDroppings, (object,)), (mod.StupidGit, (object,)), [(mod.MalodorousPervert, (mod.StupidGit,)), [(mod.FesteringGob, (mod.MalodorousPervert, @@ -422,6 +431,8 @@ def test_getclasses(self): def test_getfunctions(self): functions = inspect.getmembers(mod, inspect.isfunction) self.assertEqual(functions, [('eggs', mod.eggs), + ('extra_a', mod.extra_a), + ('extra_c', mod.extra_c), ('lobbest', mod.lobbest), ('spam', mod.spam)]) From 3c28e4f69fbfdc945758449d70c4d8b82a0cf1b4 Mon Sep 17 00:00:00 2001 From: orlnub123 Date: Thu, 1 Nov 2018 19:10:29 +0300 Subject: [PATCH 7/7] Fix duplicate test --- Lib/test/inspect_fodder.py | 8 +++----- Lib/test/test_inspect.py | 9 ++++----- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/Lib/test/inspect_fodder.py b/Lib/test/inspect_fodder.py index 79182d08f8ee41..a55e40bf0d241e 100644 --- a/Lib/test/inspect_fodder.py +++ b/Lib/test/inspect_fodder.py @@ -82,9 +82,9 @@ async def lobbest(grenade): tb = sys.exc_info()[2] # line 84 -def extra_a(): +def extra_c(): pass -class A: +class C: def func(self): pass fr = inspect.currentframe() @@ -97,9 +97,7 @@ def func(self): fr = inspect.currentframe() # line 99 -def extra_c(): - pass -class C: +class A: def func(self): pass fr = inspect.currentframe() diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index bc1b0a1b0aff9f..90eebec611ccc6 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -431,7 +431,6 @@ def test_getclasses(self): def test_getfunctions(self): functions = inspect.getmembers(mod, inspect.isfunction) self.assertEqual(functions, [('eggs', mod.eggs), - ('extra_a', mod.extra_a), ('extra_c', mod.extra_c), ('lobbest', mod.lobbest), ('spam', mod.spam)]) @@ -578,12 +577,12 @@ def test_range_traceback_toplevel_frame(self): self.assertSourceEqual(mod.tb, 1, None) def test_class_frame(self): - self.assertSourceEqual(mod.A.fr, 87, 90) + self.assertSourceEqual(mod.A.fr, 100, 103) self.assertNotSourceEqual(mod.A.fr, 85, 86) self.assertSourceEqual(mod.B.fr, 94, 97) - self.assertNotSourceEqual(mod.B.fr, 87, 90) - self.assertSourceEqual(mod.C.fr, 102, 105) - self.assertNotSourceEqual(mod.C.fr, 100, 101) + self.assertNotSourceEqual(mod.B.fr, 85, 86) + self.assertSourceEqual(mod.C.fr, 87, 90) + self.assertNotSourceEqual(mod.C.fr, 85, 86) class TestDecorators(GetSourceBase): fodderModule = mod2