[TIP] Annotated tracebacks

Chris Jerdonek chris.jerdonek at gmail.com
Tue Oct 21 11:00:20 PDT 2014


On Tue, Oct 21, 2014 at 10:39 AM, holger krekel <holger at merlinux.eu> wrote:
> On Mon, Oct 20, 2014 at 09:05 +0300, Marius Gedminas wrote:
>> On Sat, Oct 18, 2014 at 10:52:47PM +1300, Robert Collins wrote:
>> > testtools just had this bug opened on it:
>> >
>> > https://github.com/testing-cabal/testtools/issues/111
>> >
>> > Which has a few contributing issues but one in particular is that
>> > simple tracebacks don't give you the value of variables in parameters,
>> > nor of local variables in the trace.
>> >
>> > I'm aware of the implementation details that can make showing those
>> > values fraught (since __str__ and __repr__ can execute arbitrary
>> > code), but I thought I'd do a straw poll here and see who supports the
>> > idea of the traceback module itself offering to format such things
>> > (e.g. via a locals=False parameter to format_list and friends), which
>> > testtools could then backport to older pythons, and use itself to do
>> > this.
>>
>> +1: the stdlib traceback module ought to let us provide additional
>> information per frame.
>>
>> I'm ambivalent about outputting _all_ the locals.  My brief experience
>> with this (in py.test) leads me to think 99% of the time all that does
>> is make the traceback too overwhelmingly long to read comfortably.  (The
>> other 1% of the time the extra information is indispensable.)
>
> I agree and because of "--pdb" i rarely use --showlocals today much, even.
> One problem is that e.g. in a CI setting you want to see as much info
> as possible because it's not always trivial to reproduce the error.
> But in an interactive setting you don't want to be overwhelmed.
> So i guess by default things should be as terse as is still helpful
> but there needs to be an easy way to get more in CI or similar settings.

I don't know what the proposed API is, but one use case is the case of
an error being thrown from within an imported module that you don't
control.  In such cases, you might only be interested in the value of
a single variable within a single frame.  Maybe one part of the API
could provide programmatic access to a list of dicts, for example.
Each element of the list would correspond to a frame.  And each dict
would be the variables and their representations in that frame.  Then
the user could pick out only those variables they are interested in.

--Chris





>
>> In the Zope world[1] we had a convention of showing the value of
>> __traceback_info__, if available in the locals of each frame.  Usually
>> this would be a tuple with whatever locals the developer thought would
>> be useful to see in case of errors.
>
> py.test only has "__tracebackhide__" indicating if this frame should be hidden
> in the traceback representation.  That's fairly useful when you want to
> write helper functions which produce a failure message but want to have
> it shown where the helper was called.
>
>> (There's also __traceback_supplement__, but it's horrible.)
>>
>>   [1] https://github.com/zopefoundation/zope.exceptions/blob/master/src/zope/exceptions/exceptionformatter.py
>>
>>
>> I've also abused the linecache module to add extra information to
>> certain traceback frames: https://gist.github.com/mgedmin/4269249
>
> interesting.  pytest also abuses the filename to allow showing tracebacks
> of dynamically exec-ed code (works with py26 and py3X) so that you can just
> use "co = py.code.compile(...)" and when using regular unpatched traceback
> code it will display it properly. See here:
>
> https://bitbucket.org/hpk42/py/src/9978b99852892cfeb6cabafa4e231144dd5c6d05/py/_code/source.py?at=default#cl-158
>
>> > In terms of addressing the implementation details, my thoughts today
>> > are to render the traceback once in simple mode, and then once with
>> > variables, and if something throws during the variable render, just
>> > use the simple one.
>>
>> I think
>>
>>   foo = <unrepresentable>
>>
>> might me more useful.
>
> Yes, definitely.  Given the following line:
>
>     assert not A()   # with A.repr = lambda self: 0/0
>
> pytest gives:
>
>     >       assert not A()
>     E       assert not <[ZeroDivisionError("integer division or modulo
>             by zero") raised in repr()] A object at 0x7f44774e3dd0>
>
> so it contains a bit more info than just "unrepresentable".
>
> best,
> holger
>
>
>> Marius Gedminas
>> --
>> We're sysadmins. To us, data is a protocol-overhead.
>
>
>
>> _______________________________________________
>> testing-in-python mailing list
>> testing-in-python at lists.idyll.org
>> http://lists.idyll.org/listinfo/testing-in-python
>
>
> _______________________________________________
> testing-in-python mailing list
> testing-in-python at lists.idyll.org
> http://lists.idyll.org/listinfo/testing-in-python



More information about the testing-in-python mailing list