[Python-ideas] Enhance exceptions (and improve tracebakcs)

spir denis.spir at gmail.com
Mon Feb 17 11:22:56 CET 2014


On 02/15/2014 04:40 PM, Sebastian Kreft wrote:
> More than once I've been in a situation where I wish that some of the
> stdlib exceptions had a better message or some more information to help me
> diagnose the problem.
>
> For example:
> a = [1, 2, 3, 4, 5]
> a[5]
> IndexError: list index out of range
>
> In this case there's no reference to neither the length of the array nor to
> the offending index.
>
> I'm of the idea that we could extend the exceptions by adding some more
> information to them, so 3rd party libraries could use them for
> debugging/logging.
>
> For example, one such use case would be to have a modified test runner,
> that in case of exceptions automatically prints some debug information.
> Another would be a logger system that in case of an exception also logs
> some debug info that could be relevant to understand and solve the issue.
>
> I propose extending (at least) the following exceptions with the following
> attributes:
> KeyError: key, object
> IndexError: index, object
> AttributeError: attribute, object
> NameError: name
>
> Of course that populating these attributes could be controlled by a flag.
>
> I know that some of this information is already present in some exceptions,
> depending on the context. However, I propose adding these attributes, as in
> this way a tool could easily and reliably extract the information and work
> with it, as opposed to have to parse the huge variety of different messages
> there are.
>
> For the first use case mentioned above I have a working prototype, although
> it does not use this proposal, but a series of hacks (I'm modifying the
> bytecode to save a reference to the key and object :() and parsing of the
> exception messages. But I want to share what the output of such a tool
> could be.
>
> ======================================================================
> ERROR: test_attribute (example.ExampleTest)
> ----------------------------------------------------------------------
> Traceback (most recent call last):
>    File "/home/skreft/test/debug_exception/example.py.py", line 18, in
> test_attribute
> AttributeError: 'str' object has no attribute 'Lower'. Did you mean
> 'islower', 'lower'?
> Debug info:
>      Object: ''
>      Type: <type 'str'>
>
> ======================================================================
> ERROR: test_index (example.ExampleTest)
> ----------------------------------------------------------------------
> Traceback (most recent call last):
>    File "/home/skreft/test/debug_exception/example.py.py", line 6, in
> test_index
> IndexError: list index out of range
> Debug info:
>      Object: [1, 2]
>      Object len: 2
>      Index: 2
>
> ======================================================================
> ERROR: test_key (example.ExampleTest)
> ----------------------------------------------------------------------
> Traceback (most recent call last):
>    File "/home/skreft/test/debug_exception/example.py.py", line 10, in
> test_key
> KeyError_: 'fooo', did you mean 'foo'?
> Debug info:
>      Object: {'foo': 1}
>      Key: 'fooo'
>
> ======================================================================
> ERROR: test_name (example.ExampleTest)
> ----------------------------------------------------------------------
> Traceback (most recent call last):
>    File "/home/skreft/test/debug_exception/example.py.py", line 14, in
> test_name
> NameError: global name 'fooo' is not defined. Did you mean 'foo'?
>
> ----------------------------------------------------------------------
> Ran 4 tests in 0.005s

I very much approve this proposal (also the comments by Nick). Actually, I had a 
similar idea of systematically adding _relevant data_ to error reports; and also 
proposing it as standard practice in guidelines, not only when using standard 
error types, but for custom ones too.
That these data are set as attributes on error objects, making them reusable in 
custom error report formats, is also an excellent point.

I would however take the opporunity to improve a bit the traceback part of error 
reports by (1) renaming it (2) setting it apart (with a simple line). (As they 
are now, tracebacks are real enigmas to novice (python) programmers, and they 
mess up the rest of error messages.) For instance:

======================================================================
ERROR: test_key (example.ExampleTest)
----------------------------------------------------------------------
KeyError_: 'fooo', did you mean 'foo'?
Debug info:
      Object: {'foo': 1}
      Key: 'fooo'
----------------------------------------------------------------------
Function call chain chronology:
----------------------------------------------------------------------
   File "_.py", line 9, in <module>
     main()
   File "_.py", line 7, in main
     test()
   File "_.py", line 5, in test
     test_key()
   File "_.py", line 3, in test_key
     print(x['fooo'])
======================================================================

Maybe "Function call chain" in not the best term --propose your own-- but it 
still helps and understand what it's all about. "Chronology" seems 
self-explaining to me and avoids "(most recent call last)".

Placing the tracback after the message just reflects the fact that users 
(especially novice ones) read top down. I do agree that experienced programmers 
often read python error messages backwards --starting at the bottom-- but it's 
because what's usually the most relevant info is placed there, at the end of the 
message, in standard python error format:

Traceback (most recent call last):
   File "_.py", line 10, in <module>
     main()
   File "_.py", line 8, in main
     test()
   File "_.py", line 6, in test
     test_key()
   File "_.py", line 4, in test_key
     print(x['fooo'])
KeyError: 'fooo'

But I would not fight for this.

d


More information about the Python-ideas mailing list