From 94db9d239aa60ab8a7bb20acc588aa8c631185a5 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Sun, 31 Dec 2017 20:32:29 +0100 Subject: [PATCH 1/3] bpo-32468: Better frame repr() --- Lib/test/test_frame.py | 39 +++++++++++++++++++ .../2017-12-31-20-32-58.bpo-32468.YBs__0.rst | 1 + Objects/frameobject.c | 11 +++++- 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2017-12-31-20-32-58.bpo-32468.YBs__0.rst diff --git a/Lib/test/test_frame.py b/Lib/test/test_frame.py index cabfef236dd95c0..10ec575cb90d356 100644 --- a/Lib/test/test_frame.py +++ b/Lib/test/test_frame.py @@ -159,5 +159,44 @@ def test_locals_clear_locals(self): self.assertEqual(inner.f_locals, {}) +class ReprTest(unittest.TestCase): + """ + Tests for repr(frame). + """ + + def test_repr(self): + def outer(): + x = 5 + y = 6 + def inner(): + z = x + 2 + 1/0 + t = 9 + return inner() + + offset = outer.__code__.co_firstlineno + try: + outer() + except ZeroDivisionError as e: + tb = e.__traceback__ + frames = [] + while tb: + frames.append(tb.tb_frame) + tb = tb.tb_next + else: + self.fail("should have raised") + + f_this, f_outer, f_inner = frames + self.assertRegex(repr(f_this), + r"^$" + % (__file__, offset + 22)) + self.assertRegex(repr(f_outer), + r"^$" + % (__file__, offset + 7)) + self.assertRegex(repr(f_inner), + r"^$" + % (__file__, offset + 5)) + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2017-12-31-20-32-58.bpo-32468.YBs__0.rst b/Misc/NEWS.d/next/Library/2017-12-31-20-32-58.bpo-32468.YBs__0.rst new file mode 100644 index 000000000000000..135bbd816e869f7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2017-12-31-20-32-58.bpo-32468.YBs__0.rst @@ -0,0 +1 @@ +Improve frame repr() to mention filename, code name and current line number. diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 6ab3a22950ade69..1ac3d752575268c 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -547,6 +547,15 @@ frame_sizeof(PyFrameObject *f) PyDoc_STRVAR(sizeof__doc__, "F.__sizeof__() -> size of F in memory, in bytes"); +static PyObject * +frame_repr(PyFrameObject *f) +{ + int lineno = PyFrame_GetLineNumber(f); + return PyUnicode_FromFormat( + "", + f, f->f_code->co_filename, lineno, f->f_code->co_name); +} + static PyMethodDef frame_methods[] = { {"clear", (PyCFunction)frame_clear, METH_NOARGS, clear__doc__}, @@ -565,7 +574,7 @@ PyTypeObject PyFrame_Type = { 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ - 0, /* tp_repr */ + (reprfunc)frame_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ From d8879312a23fe221b94ac8a132726ef5efbb1f1c Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Sun, 31 Dec 2017 20:47:13 +0100 Subject: [PATCH 2/3] Try to fix test on Windows --- Lib/test/test_frame.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_frame.py b/Lib/test/test_frame.py index 10ec575cb90d356..be3bb1ba9132e86 100644 --- a/Lib/test/test_frame.py +++ b/Lib/test/test_frame.py @@ -1,3 +1,4 @@ +import re import types import unittest import weakref @@ -187,15 +188,16 @@ def inner(): self.fail("should have raised") f_this, f_outer, f_inner = frames + file_repr = re.escape(repr(__file__)) self.assertRegex(repr(f_this), - r"^$" - % (__file__, offset + 22)) + r"^$" + % (file_repr, offset + 23)) self.assertRegex(repr(f_outer), - r"^$" - % (__file__, offset + 7)) + r"^$" + % (file_repr, offset + 7)) self.assertRegex(repr(f_inner), - r"^$" - % (__file__, offset + 5)) + r"^$" + % (file_repr, offset + 5)) if __name__ == "__main__": From 278490827a4e90d4275f1f85fe479e0da0184fc0 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Sun, 31 Dec 2017 20:56:35 +0100 Subject: [PATCH 3/3] Apparently, hex display is uppercase on Windows --- Lib/test/test_frame.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_frame.py b/Lib/test/test_frame.py index be3bb1ba9132e86..fd795085a5cd400 100644 --- a/Lib/test/test_frame.py +++ b/Lib/test/test_frame.py @@ -190,13 +190,13 @@ def inner(): f_this, f_outer, f_inner = frames file_repr = re.escape(repr(__file__)) self.assertRegex(repr(f_this), - r"^$" + r"^$" % (file_repr, offset + 23)) self.assertRegex(repr(f_outer), - r"^$" + r"^$" % (file_repr, offset + 7)) self.assertRegex(repr(f_inner), - r"^$" + r"^$" % (file_repr, offset + 5))