diff --git a/Lib/inspect.py b/Lib/inspect.py index c52469e63861a22..45b7e47f05da7a1 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1626,7 +1626,7 @@ def getframeinfo(frame, context=1): raise TypeError('{!r} is not a frame or traceback object'.format(frame)) filename = getsourcefile(frame) or getfile(frame) - if context > 0: + if context > 0 and lineno is not None: start = lineno - 1 - context//2 try: lines, lnum = findsource(frame) diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index df5843abfcb8753..e8f5d949a35fa72 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -846,6 +846,39 @@ def test_getframeinfo_get_first_line(self): self.assertEqual(frame_info.code_context[0], "# line 1\n") self.assertEqual(frame_info.code_context[1], "'A module docstring.'\n") + def test_getframeinfo_no_lineno(self): + # gh-89726: some instructions carry no line number, so a frame + # stopped on one has f_lineno set to None. getframeinfo() must + # report that rather than failing. + def f(): + try: + raise ValueError + except ValueError: + pass + + infos = [] + + def trace(frame, event, arg): + if frame.f_code is f.__code__ and frame.f_lineno is None: + infos.append(inspect.getframeinfo(frame)) + frame.f_trace_opcodes = True + return trace + + old_trace = sys.gettrace() + sys.settrace(trace) + try: + f() + finally: + sys.settrace(old_trace) + + self.assertTrue(infos, 'no frame with f_lineno set to None') + for info in infos: + with self.subTest(info=info): + self.assertIsNone(info.lineno) + self.assertIsNone(info.code_context) + self.assertIsNone(info.index) + self.assertEqual(info.function, 'f') + def test_getsource(self): self.assertSourceEqual(git.abuse, 29, 39) self.assertSourceEqual(mod.StupidGit, 21, 51) diff --git a/Misc/NEWS.d/next/Library/2022-03-22-10-16-11.bpo-45563.o-oP2m.rst b/Misc/NEWS.d/next/Library/2022-03-22-10-16-11.bpo-45563.o-oP2m.rst new file mode 100644 index 000000000000000..aa32e5e1e76028d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-03-22-10-16-11.bpo-45563.o-oP2m.rst @@ -0,0 +1,4 @@ +:func:`inspect.getframeinfo` no longer raises :exc:`TypeError` for a frame +stopped on an instruction that carries no line number, such as while tracing +opcodes. ``lineno``, ``code_context`` and ``index`` are reported as ``None`` +instead.