Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit fabfc2c

Browse files
[3.11] GH-65052: Prevent pdb from crashing when trying to display objects (GH-111002)
(cherry picked from commit c523ce0)
1 parent faa7c20 commit fabfc2c

File tree

3 files changed

+64
-7
lines changed

3 files changed

+64
-7
lines changed

Lib/pdb.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -405,8 +405,9 @@ def preloop(self):
405405
# fields are changed to be displayed
406406
if newvalue is not oldvalue and newvalue != oldvalue:
407407
displaying[expr] = newvalue
408-
self.message('display %s: %r [old: %r]' %
409-
(expr, newvalue, oldvalue))
408+
self.message('display %s: %s [old: %s]' %
409+
(expr, self._safe_repr(newvalue, expr),
410+
self._safe_repr(oldvalue, expr)))
410411

411412
def interaction(self, frame, traceback):
412413
# Restore the previous signal handler at the Pdb prompt.
@@ -1221,7 +1222,7 @@ def do_args(self, arg):
12211222
for i in range(n):
12221223
name = co.co_varnames[i]
12231224
if name in dict:
1224-
self.message('%s = %r' % (name, dict[name]))
1225+
self.message('%s = %s' % (name, self._safe_repr(dict[name], name)))
12251226
else:
12261227
self.message('%s = *** undefined ***' % (name,))
12271228
do_a = do_args
@@ -1231,7 +1232,7 @@ def do_retval(self, arg):
12311232
Print the return value for the last return of a function.
12321233
"""
12331234
if '__return__' in self.curframe_locals:
1234-
self.message(repr(self.curframe_locals['__return__']))
1235+
self.message(self._safe_repr(self.curframe_locals['__return__'], "retval"))
12351236
else:
12361237
self.error('Not yet returned!')
12371238
do_rv = do_retval
@@ -1268,6 +1269,12 @@ def _msg_val_func(self, arg, func):
12681269
except:
12691270
self._error_exc()
12701271

1272+
def _safe_repr(self, obj, expr):
1273+
try:
1274+
return repr(obj)
1275+
except Exception as e:
1276+
return _rstr(f"*** repr({expr}) failed: {self._format_exc(e)} ***")
1277+
12711278
def do_p(self, arg):
12721279
"""p expression
12731280
Print the value of the expression.
@@ -1438,12 +1445,12 @@ def do_display(self, arg):
14381445
"""
14391446
if not arg:
14401447
self.message('Currently displaying:')
1441-
for item in self.displaying.get(self.curframe, {}).items():
1442-
self.message('%s: %r' % item)
1448+
for key, val in self.displaying.get(self.curframe, {}).items():
1449+
self.message('%s: %s' % (key, self._safe_repr(val, key)))
14431450
else:
14441451
val = self._getval_except(arg)
14451452
self.displaying.setdefault(self.curframe, {})[arg] = val
1446-
self.message('display %s: %r' % (arg, val))
1453+
self.message('display %s: %s' % (arg, self._safe_repr(val, arg)))
14471454

14481455
complete_display = _complete_expression
14491456

@@ -1645,6 +1652,8 @@ def _run(self, target: Union[_ModuleTarget, _ScriptTarget]):
16451652

16461653
self.run(target.code)
16471654

1655+
def _format_exc(self, exc: BaseException):
1656+
return traceback.format_exception_only(exc)[-1].strip()
16481657

16491658
def _getsourcelines(self, obj):
16501659
# GH-103319

Lib/test/test_pdb.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1704,6 +1704,53 @@ def test_pdb_issue_gh_103225():
17041704
(Pdb) continue
17051705
"""
17061706

1707+
def test_pdb_issue_gh_65052():
1708+
"""See GH-65052
1709+
1710+
args, retval and display should not crash if the object is not displayable
1711+
>>> class A:
1712+
... def __new__(cls):
1713+
... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
1714+
... return object.__new__(cls)
1715+
... def __init__(self):
1716+
... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
1717+
... self.a = 1
1718+
... def __repr__(self):
1719+
... return self.a
1720+
1721+
>>> def test_function():
1722+
... A()
1723+
>>> with PdbTestInput([ # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
1724+
... 's',
1725+
... 'retval',
1726+
... 'continue',
1727+
... 'args',
1728+
... 'display self',
1729+
... 'display',
1730+
... 'continue',
1731+
... ]):
1732+
... test_function()
1733+
> <doctest test.test_pdb.test_pdb_issue_gh_65052[0]>(4)__new__()
1734+
-> return object.__new__(cls)
1735+
(Pdb) s
1736+
--Return--
1737+
> <doctest test.test_pdb.test_pdb_issue_gh_65052[0]>(4)__new__()-><A instance at ...>
1738+
-> return object.__new__(cls)
1739+
(Pdb) retval
1740+
*** repr(retval) failed: AttributeError: 'A' object has no attribute 'a' ***
1741+
(Pdb) continue
1742+
> <doctest test.test_pdb.test_pdb_issue_gh_65052[0]>(7)__init__()
1743+
-> self.a = 1
1744+
(Pdb) args
1745+
self = *** repr(self) failed: AttributeError: 'A' object has no attribute 'a' ***
1746+
(Pdb) display self
1747+
display self: *** repr(self) failed: AttributeError: 'A' object has no attribute 'a' ***
1748+
(Pdb) display
1749+
Currently displaying:
1750+
self: *** repr(self) failed: AttributeError: 'A' object has no attribute 'a' ***
1751+
(Pdb) continue
1752+
"""
1753+
17071754

17081755
@support.requires_subprocess()
17091756
class PdbTestCase(unittest.TestCase):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Prevent :mod:`pdb` from crashing when trying to display undisplayable objects

0 commit comments

Comments
 (0)