| msg212759 - (view) | Author: Jurjen N.E. Bos (jneb) * | Date: 2014-03-05 10:45 |
The "args" command in pdb crashes when an argument cannot be printed. Fortunately, this is easy to fix. For version 3.3.3: In function Pdb.do_args (lib/pdb.py, line 1120) Change line 1131 self.message('%s = %r' % (name, dict[name])) to try: r = repr(dict[name]) except: r = "(Cannot print object)" self.message('%s = %s' % (name, r)) |
| msg212760 - (view) | Author: R. David Murray (r.david.murray) *  | Date: 2014-03-05 12:53 |
Why is the object not printable? Can you provide a reproducer? Also, the bare except is buggy, it would catch things like KeyboardInterrupt that should not be caught there. 'except Exception' would be appropriate in this case. |
| msg213212 - (view) | Author: Jurjen N.E. Bos (jneb) * | Date: 2014-03-12 07:58 |
Thanks for your reaction. The object is not printable, since I was debugging an __init__ of an object, and some fields where being initialized: class foo: def __init__(self): foo.bar = "hello" def repr(self): return foo.bar I tried to make a useable patch file (with neater layout and using Exeption), see attach. |
| msg213214 - (view) | Author: Jurjen N.E. Bos (jneb) * | Date: 2014-03-12 08:16 |
Oops. Here the correct example: >>> class foo: ... def __init__(self): ... foo.bar = "hello" ... def __repr__(self): return foo.bar ... >>> pdb.runcall(foo) > <stdin>(3)__init__() (Pdb) a Traceback (most recent call last): File ".\pdb.py", line 1132, in do_args self.message('%s = %r' % (name, dict[name])) File "<stdin>", line 4, in __repr__ AttributeError: type object 'foo' has no attribute 'bar' During handling of the above exception, another exception occurred: Traceback (most recent call last): File "<stdin>", line 1, in <module> File ".\pdb.py", line 1580, in runcall return Pdb().runcall(*args, **kwds) File "C:\Python33\lib\bdb.py", line 439, in runcall res = func(*args, **kwds) File "<stdin>", line 3, in __init__ File "<stdin>", line 3, in __init__ File "C:\Python33\lib\bdb.py", line 47, in trace_dispatch return self.dispatch_line(frame) File "C:\Python33\lib\bdb.py", line 65, in dispatch_line self.user_line(frame) File ".\pdb.py", line 266, in user_line self.interaction(frame, None) File ".\pdb.py", line 345, in interaction self._cmdloop() File ".\pdb.py", line 318, in _cmdloop self.cmdloop() File "C:\Python33\lib\cmd.py", line 138, in cmdloop stop = self.onecmd(line) File ".\pdb.py", line 411, in onecmd return cmd.Cmd.onecmd(self, line) File "C:\Python33\lib\cmd.py", line 217, in onecmd return func(arg) File ".\pdb.py", line 1134, in do_args self.message('%s = *** repr failed: %s ***' % (name,)) TypeError: not enough arguments for format string At least, I expect pdb to not crash, but a clearer error (as in the patch) is nice to have. |
| msg213217 - (view) | Author: Jurjen N.E. Bos (jneb) * | Date: 2014-03-12 08:22 |
I am not good at this. Sorry for the mess. Here is a good example, and a good patch: >>> class foo: ... def __init__(self): ... foo.bar = "hello" ... def __repr__(self): return foo.bar ... >>> pdb.runcall(foo) Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'pdb' is not defined >>> import pdb >>> pdb.runcall(foo) > <stdin>(3)__init__() (Pdb) a Traceback (most recent call last): File "<stdin>", line 1, in <module> File "C:\Python33\lib\pdb.py", line 1577, in runcall return Pdb().runcall(*args, **kwds) File "C:\Python33\lib\bdb.py", line 439, in runcall res = func(*args, **kwds) File "<stdin>", line 3, in __init__ File "<stdin>", line 3, in __init__ File "C:\Python33\lib\bdb.py", line 47, in trace_dispatch return self.dispatch_line(frame) File "C:\Python33\lib\bdb.py", line 65, in dispatch_line self.user_line(frame) File "C:\Python33\lib\pdb.py", line 266, in user_line self.interaction(frame, None) File "C:\Python33\lib\pdb.py", line 345, in interaction self._cmdloop() File "C:\Python33\lib\pdb.py", line 318, in _cmdloop self.cmdloop() File "C:\Python33\lib\cmd.py", line 138, in cmdloop stop = self.onecmd(line) File "C:\Python33\lib\pdb.py", line 411, in onecmd return cmd.Cmd.onecmd(self, line) File "C:\Python33\lib\cmd.py", line 217, in onecmd return func(arg) File "C:\Python33\lib\pdb.py", line 1131, in do_args self.message('%s = %r' % (name, dict[name])) File "<stdin>", line 4, in __repr__ AttributeError: type object 'foo' has no attribute 'bar' |
| msg213273 - (view) | Author: R. David Murray (r.david.murray) *  | Date: 2014-03-12 18:01 |
There is at least one other place (do_break) where this same problem could crop up. Unittest handles this by having a 'safe_repr' function. pdb doesn't need the same function unittest does, but it could do something similar, and then use %s and this function in the places where it currently uses repr to print an arbitrary object: def safe_repr(obj): try: return repr(obj) except Exception: return object.__repr__(obj) |
| msg213593 - (view) | Author: Jurjen N.E. Bos (jneb) * | Date: 2014-03-14 21:51 |
Maybe we could use Pdb._getval_except(arg, frame=None) in the routine do_args. If I understand the code, do_args does quite some work to get the value of name in the context of the current frame, maybe just calling self._getval_except(name, frame=self.curframe) plus or minus some code would do the job? I guess the code would actually become shorter... I'll try to figure it out. |
| msg213841 - (view) | Author: Jurjen N.E. Bos (jneb) * | Date: 2014-03-17 08:38 |
I did figure it out. It almost works, except when a argument lost its value, and the same name exists in the global context. To be more specific: I simplified do_args to the following code (that obviously ugly by explicitly evaluating repr in context, but that is not the point) def do_args(self, arg): """a(rgs) Print the argument list of the current function. Modified by Jurjen """ co = self.curframe.f_code n = co.co_argcount if co.co_flags & 4: n = n+1 if co.co_flags & 8: n = n+1 for i in range(n): name = co.co_varnames[i] expr = 'repr(%s)' % (name,) self.message('%s = %s' % (name, self._getval_except(expr))) At it works perfectly, except for this little surprise: >>> bar = "BAR" >>> def foo(bar): ... del bar ... return 5 >>> pdb.runcall(f, 10) > <stdin>(2)f() -> del bar (Pdb) a bar = 5 (Pdb) n > <stdin>(3)f() -> return 5 (Pdb) a bar = 'BAR' ##### Huh? Expected undefined I'll leave it to the experts to patch this in proper Python coding style. So, the conclusion is we need a way to safely evaluate the call to repr() in context, with self.curframe_locals[co.co_varnames[i]] as argument. I did not find a good supporting routine for that elsewhere in pdb. |
| msg213987 - (view) | Author: Xavier de Gaye (xdegaye) *  | Date: 2014-03-18 16:40 |
> There is at least one other place (do_break) where this same problem could crop up. Also in do_retval. And the exception is silently ignored in do_p and do_pp when repr() fails, which is not correct. A solution could be to have a message_safe method to be used in such cases. For example, substitute in do_args: self.message('%s = %r' % (name, dict[name])) with: self.message_safe('%s = %r', name, dict[name]) def message_safe(self, fmt, *args): try: print(fmt % args, file=self.stdout) except Exception: exc_info = sys.exc_info()[:2] self.error(traceback.format_exception_only(*exc_info)[-1].strip()) |
| msg218975 - (view) | Author: Xavier de Gaye (xdegaye) *  | Date: 2014-05-23 15:08 |
Commands that silently fail when an object is not printable: p, pp Commands that crash when an object is not printable: args, retval Python 3: display Python 2: on a 'return' trace event when the return value is not printable The attached script illustrates all these cases. |
| msg401999 - (view) | Author: Andrei Kulakov (andrei.avk) *  | Date: 2021-09-17 02:50 |
p/pp commands were fixed in this commit: https://github.com/python/cpython/commit/6544b2532df |
|
| Date | User | Action | Args |
| 2022-04-11 14:57:59 | admin | set | github: 65052 |
| 2021-09-17 02:50:21 | andrei.avk | set | messages: + msg401999 |
| 2021-09-17 02:42:36 | andrei.avk | set | nosy: + andrei.avk pull_requests: + pull_request26814
|
| 2021-09-12 15:06:19 | andrei.avk | link | issue42119 superseder |
| 2014-05-23 15:08:10 | xdegaye | set | files: + safe_repr.py
messages: + msg218975 |
| 2014-05-09 12:55:31 | ezio.melotti | set | stage: patch review |
| 2014-03-18 16:40:04 | xdegaye | set | nosy: + xdegaye messages: + msg213987
|
| 2014-03-17 08:38:51 | jneb | set | messages: + msg213841 |
| 2014-03-14 21:51:15 | jneb | set | messages: + msg213593 |
| 2014-03-12 18:01:53 | r.david.murray | set | messages: + msg213273 |
| 2014-03-12 08:22:57 | jneb | set | files: + pdb.patch
messages: + msg213217 |
| 2014-03-12 08:16:21 | jneb | set | messages: + msg213214 |
| 2014-03-12 07:58:48 | jneb | set | files: + pdb.patch keywords: + patch messages: + msg213212
|
| 2014-03-05 12:53:57 | r.david.murray | set | nosy: + r.david.murray messages: + msg212760
|
| 2014-03-05 10:45:57 | jneb | create | |