mirror of
https://github.com/python/cpython.git
synced 2026-01-05 15:02:33 +00:00
[3.11] GH-65052: Prevent pdb from crashing when trying to display objects (GH-111002)
(cherry picked from commit c523ce0f43)
This commit is contained in:
parent
faa7c207bf
commit
fabfc2ccfc
3 changed files with 64 additions and 7 deletions
23
Lib/pdb.py
23
Lib/pdb.py
|
|
@ -405,8 +405,9 @@ def preloop(self):
|
|||
# fields are changed to be displayed
|
||||
if newvalue is not oldvalue and newvalue != oldvalue:
|
||||
displaying[expr] = newvalue
|
||||
self.message('display %s: %r [old: %r]' %
|
||||
(expr, newvalue, oldvalue))
|
||||
self.message('display %s: %s [old: %s]' %
|
||||
(expr, self._safe_repr(newvalue, expr),
|
||||
self._safe_repr(oldvalue, expr)))
|
||||
|
||||
def interaction(self, frame, traceback):
|
||||
# Restore the previous signal handler at the Pdb prompt.
|
||||
|
|
@ -1221,7 +1222,7 @@ 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]))
|
||||
self.message('%s = %s' % (name, self._safe_repr(dict[name], name)))
|
||||
else:
|
||||
self.message('%s = *** undefined ***' % (name,))
|
||||
do_a = do_args
|
||||
|
|
@ -1231,7 +1232,7 @@ 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__']))
|
||||
self.message(self._safe_repr(self.curframe_locals['__return__'], "retval"))
|
||||
else:
|
||||
self.error('Not yet returned!')
|
||||
do_rv = do_retval
|
||||
|
|
@ -1268,6 +1269,12 @@ def _msg_val_func(self, arg, func):
|
|||
except:
|
||||
self._error_exc()
|
||||
|
||||
def _safe_repr(self, obj, expr):
|
||||
try:
|
||||
return repr(obj)
|
||||
except Exception as e:
|
||||
return _rstr(f"*** repr({expr}) failed: {self._format_exc(e)} ***")
|
||||
|
||||
def do_p(self, arg):
|
||||
"""p expression
|
||||
Print the value of the expression.
|
||||
|
|
@ -1438,12 +1445,12 @@ def do_display(self, arg):
|
|||
"""
|
||||
if not arg:
|
||||
self.message('Currently displaying:')
|
||||
for item in self.displaying.get(self.curframe, {}).items():
|
||||
self.message('%s: %r' % item)
|
||||
for key, val in self.displaying.get(self.curframe, {}).items():
|
||||
self.message('%s: %s' % (key, self._safe_repr(val, key)))
|
||||
else:
|
||||
val = self._getval_except(arg)
|
||||
self.displaying.setdefault(self.curframe, {})[arg] = val
|
||||
self.message('display %s: %r' % (arg, val))
|
||||
self.message('display %s: %s' % (arg, self._safe_repr(val, arg)))
|
||||
|
||||
complete_display = _complete_expression
|
||||
|
||||
|
|
@ -1645,6 +1652,8 @@ def _run(self, target: Union[_ModuleTarget, _ScriptTarget]):
|
|||
|
||||
self.run(target.code)
|
||||
|
||||
def _format_exc(self, exc: BaseException):
|
||||
return traceback.format_exception_only(exc)[-1].strip()
|
||||
|
||||
def _getsourcelines(self, obj):
|
||||
# GH-103319
|
||||
|
|
|
|||
|
|
@ -1704,6 +1704,53 @@ def test_pdb_issue_gh_103225():
|
|||
(Pdb) continue
|
||||
"""
|
||||
|
||||
def test_pdb_issue_gh_65052():
|
||||
"""See GH-65052
|
||||
|
||||
args, retval and display should not crash if the object is not displayable
|
||||
>>> class A:
|
||||
... def __new__(cls):
|
||||
... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
|
||||
... return object.__new__(cls)
|
||||
... def __init__(self):
|
||||
... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
|
||||
... self.a = 1
|
||||
... def __repr__(self):
|
||||
... return self.a
|
||||
|
||||
>>> def test_function():
|
||||
... A()
|
||||
>>> with PdbTestInput([ # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
|
||||
... 's',
|
||||
... 'retval',
|
||||
... 'continue',
|
||||
... 'args',
|
||||
... 'display self',
|
||||
... 'display',
|
||||
... 'continue',
|
||||
... ]):
|
||||
... test_function()
|
||||
> <doctest test.test_pdb.test_pdb_issue_gh_65052[0]>(4)__new__()
|
||||
-> return object.__new__(cls)
|
||||
(Pdb) s
|
||||
--Return--
|
||||
> <doctest test.test_pdb.test_pdb_issue_gh_65052[0]>(4)__new__()-><A instance at ...>
|
||||
-> return object.__new__(cls)
|
||||
(Pdb) retval
|
||||
*** repr(retval) failed: AttributeError: 'A' object has no attribute 'a' ***
|
||||
(Pdb) continue
|
||||
> <doctest test.test_pdb.test_pdb_issue_gh_65052[0]>(7)__init__()
|
||||
-> self.a = 1
|
||||
(Pdb) args
|
||||
self = *** repr(self) failed: AttributeError: 'A' object has no attribute 'a' ***
|
||||
(Pdb) display self
|
||||
display self: *** repr(self) failed: AttributeError: 'A' object has no attribute 'a' ***
|
||||
(Pdb) display
|
||||
Currently displaying:
|
||||
self: *** repr(self) failed: AttributeError: 'A' object has no attribute 'a' ***
|
||||
(Pdb) continue
|
||||
"""
|
||||
|
||||
|
||||
@support.requires_subprocess()
|
||||
class PdbTestCase(unittest.TestCase):
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
Prevent :mod:`pdb` from crashing when trying to display undisplayable objects
|
||||
Loading…
Add table
Add a link
Reference in a new issue