Issue 19585: Frame annotation - Python tracker (original) (raw)
Created on 2013-11-14 17:09 by doerwalter, last changed 2022-04-11 14:57 by admin.
Messages (10)
Author: Walter Dörwald (doerwalter) *
Date: 2013-11-14 17:09
This patch adds frame annotations, i.e. it adds an attribute f_annotation to frame objects, a decorator to set this attribute on exceptions and extensions to the traceback machinery that display the annotation in the traceback.
Author: STINNER Victor (vstinner) *
Date: 2013-11-14 17:30
What is the use case of frame annotations?
Author: Walter Dörwald (doerwalter) *
Date: 2013-11-14 17:43
See http://bugs.python.org/issue18861 and the discussion started here: https://mail.python.org/pipermail/python-dev/2013-November/130155.html.
Basically it allows to add context information to a traceback without changing the type of the exception.
In the following example:
import itertools ', '.join(itertools.chain((str(i) for i in range(100)), [42]))
the join method itself adds context information to the TypeError:
Traceback (most recent call last): File "hurz.py", line 2, in ', '.join(itertools.chain((str(i) for i in range(100)), [42])) TypeError: sequence item 100: expected str instance, int found
i.e. the "sequence item 100" is context information.
However when the exception occurs higher up in the call chain, no such context information is added:
import itertools
def foo(x): return str(x+1)
', '.join(foo(x) for x in itertools.chain(range(100), [None]))
This gives:
Traceback (most recent call last): File "hurz.py", line 6, in ', '.join(foo(x) for x in itertools.chain(range(100), [None])) File "hurz.py", line 6, in ', '.join(foo(x) for x in itertools.chain(range(100), [None])) File "hurz.py", line 4, in foo return str(x+1) TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
With frame annotations the traceback might look like this:
Traceback (most recent call last): File "hurz.py", line 6, in ', '.join(foo(x) for x in itertools.chain(range(100), [None])) File "hurz.py", line 6, in : sequence item 100 ', '.join(foo(x) for x in itertools.chain(range(100), [None])) File "hurz.py", line 4, in foo return str(x+1) TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
Author: Antoine Pitrou (pitrou) *
Date: 2013-11-14 21:56
I think this would need a PEP.
Author: Alyssa Coghlan (ncoghlan) *
Date: 2013-11-14 22:37
Aye, it would. The improved exception chaining and frame hiding ideas in issue 18861 are also related.
The part I particularly like in Walter's suggestion is the idea of a "frame description" that is displayed in the traceback for that frame, without the traceback module needing to know the details of other annotations.
Author: Walter Dörwald (doerwalter) *
Date: 2013-11-25 12:02
Here is a new version of the patch. The annotation is done on the code object instead of on the frame object. This avoids two problems: There is no runtime overhead, as the decorator returns the original function and no additional frames show up in the traceback. Since the variables are only known at runtime, the annotation is now a function that does the formatting of the annotation message and gets passed the frame object. With this there is no runtime overhead when no exception is raised and even if an exception is raise, but the traceback is never formatted.
Author: Alyssa Coghlan (ncoghlan) *
Date: 2013-11-25 12:52
Code objects are shared amongst multiple function objects, so you can't store mutable state on them.
Author: Walter Dörwald (doerwalter) *
Date: 2013-11-25 17:12
Do you have an example where code objects are shared? We could attach the annotation formatter to the function object, but unfortunately the function object is now accessible in the traceback.
Note the co_annotation is not the annotation string, rather it is a function that does the formatting of the annotation.
Author: Alyssa Coghlan (ncoghlan) *
Date: 2013-11-25 21:19
A nested function will always share the code object between its instances - the nested code object is a compile time constant stored as part of the containing code object.
Any code object attribute must be consistent for the lifetime of the object.
Author: Alyssa Coghlan (ncoghlan) *
Date: 2014-01-16 04:29
Another use case from frame annotations: allowing greenlets and threads to indicate which greenlet or thread a traceback is from whenever it is printed (this is similar to the way the runtime indicates which thread a traceback occurred in when it terminates the the thread, but would apply whenever the uppermost frame is displayed in a thread that isn't the main thread, or in the case of greenlets, the uppermost frame in the greenlet, always)
History
Date
User
Action
Args
2022-04-11 14:57:53
admin
set
github: 63784
2014-01-16 04:29:39
ncoghlan
set
messages: +
2013-11-25 21:19:35
ncoghlan
set
messages: +
2013-11-25 17:12:38
doerwalter
set
messages: +
2013-11-25 12:52:52
ncoghlan
set
messages: +
2013-11-25 12:02:11
doerwalter
set
files: + code-annotation.diff
messages: +
2013-11-14 22:37:25
ncoghlan
set
messages: +
2013-11-14 21:56:56
pitrou
set
nosy: + pitrou, ncoghlan
messages: +
2013-11-14 17:43:31
doerwalter
set
messages: +
2013-11-14 17:30:05
vstinner
set
nosy: + vstinner
messages: +
2013-11-14 17:09:30
doerwalter
create