From 34c945b6a977cc2cd002d054a9f07887cd37a0a1 Mon Sep 17 00:00:00 2001 From: andrei kulakov Date: Thu, 16 Sep 2021 22:40:01 -0400 Subject: [PATCH 1/3] fix args and retval commands to handle objects with broken repr() --- Doc/library/pdb.rst | 4 ++- Lib/pdb.py | 12 +++++-- Lib/test/test_pdb.py | 34 +++++++++++++++++++ .../2021-09-16-22-38-58.bpo-20853.J3kJay.rst | 2 ++ 4 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2021-09-16-22-38-58.bpo-20853.J3kJay.rst diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 6d1dba1bf2eb01..6dbd3e35e78685 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -543,7 +543,9 @@ can be overridden by the local file. .. pdbcommand:: retval - Print the return value for the last return of a function. + Print the return value for the last return of a function. This command must + be used immediately after the return line is executed; *return* command can + be used to jump to the location where *retval* can be used. .. rubric:: Footnotes diff --git a/Lib/pdb.py b/Lib/pdb.py index d7110074538ace..7ba2bf6fc2e124 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -1230,7 +1230,12 @@ def do_args(self, arg): for i in range(n): name = co.co_varnames[i] if name in dict: - self.message('%s = %r' % (name, dict[name])) + try: + r = dict[name] + repr(r) + except Exception as e: + r = e + self.message('%s = %r' % (name, r)) else: self.message('%s = *** undefined ***' % (name,)) do_a = do_args @@ -1240,7 +1245,10 @@ def do_retval(self, arg): Print the return value for the last return of a function. """ if '__return__' in self.curframe_locals: - self.message(repr(self.curframe_locals['__return__'])) + try: + self.message(repr(self.curframe_locals['__return__'])) + except: + self._error_exc() else: self.error('Not yet returned!') do_rv = do_retval diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 01263db28f18cd..9f2e9f4ec5d6ba 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -429,6 +429,40 @@ def test_pdb_pp_repr_exc(): (Pdb) continue """ +def test_pdb_bad_repr(): + """Test that args/retval commands handle bad repr objects. + + >>> class BadRepr: + ... def __repr__(self): + ... raise AttributeError("'BadRepr' object has no attribute 'foo'") + ... def __str__(self): + ... return '' + >>> obj = BadRepr() + + >>> def test_function(x): + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + ... return x + + >>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE, +ELLIPSIS + ... 'args', + ... 'return', + ... 'retval', + ... 'continue', + ... ]): + ... x = test_function(obj) + > (3)test_function() + -> return x + (Pdb) args + x = AttributeError("'BadRepr' object has no attribute 'foo'") + (Pdb) return + --Return-- + > (3)test_function()... + -> return x + (Pdb) retval + *** AttributeError: 'BadRepr' object has no attribute 'foo' + (Pdb) continue + """ + def do_nothing(): pass diff --git a/Misc/NEWS.d/next/Library/2021-09-16-22-38-58.bpo-20853.J3kJay.rst b/Misc/NEWS.d/next/Library/2021-09-16-22-38-58.bpo-20853.J3kJay.rst new file mode 100644 index 00000000000000..f4f88a17418ad5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-09-16-22-38-58.bpo-20853.J3kJay.rst @@ -0,0 +1,2 @@ +In :module:`pdb`, *args* and *retval* commands were fixed to properly handle +objects for which :func:`repr` raises an exception. From 5d12a8cf383caa4ea9252f0109e2164c4785c256 Mon Sep 17 00:00:00 2001 From: andrei kulakov Date: Thu, 16 Sep 2021 22:53:31 -0400 Subject: [PATCH 2/3] fix news entry --- .../next/Library/2021-09-16-22-38-58.bpo-20853.J3kJay.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2021-09-16-22-38-58.bpo-20853.J3kJay.rst b/Misc/NEWS.d/next/Library/2021-09-16-22-38-58.bpo-20853.J3kJay.rst index f4f88a17418ad5..8fd6ee6ba1bf8b 100644 --- a/Misc/NEWS.d/next/Library/2021-09-16-22-38-58.bpo-20853.J3kJay.rst +++ b/Misc/NEWS.d/next/Library/2021-09-16-22-38-58.bpo-20853.J3kJay.rst @@ -1,2 +1,2 @@ -In :module:`pdb`, *args* and *retval* commands were fixed to properly handle +In :mod:`pdb`, *args* and *retval* commands were fixed to properly handle objects for which :func:`repr` raises an exception. From d2a6d61315de835421d98d30264cf9e418b91c20 Mon Sep 17 00:00:00 2001 From: andrei kulakov Date: Thu, 16 Sep 2021 23:27:25 -0400 Subject: [PATCH 3/3] add comment to the test --- Lib/test/test_pdb.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 9f2e9f4ec5d6ba..2c6abc094384f2 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -430,6 +430,8 @@ def test_pdb_pp_repr_exc(): """ def test_pdb_bad_repr(): + # Note that return of test_function() needs to be assigned to a value; + # otherwise doctest tries to run repr() on it and fails. """Test that args/retval commands handle bad repr objects. >>> class BadRepr: