This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Improvements to traceback module
Type: enhancement Stage: resolved
Components: Versions: Python 3.4, Python 3.5
process
Status: closed Resolution: wont fix
Dependencies: Superseder:
Assigned To: Nosy List: Claudiu.Popa, akuchling, benjamin.peterson, gvanrossum, pitrou, serhiy.storchaka, vstinner
Priority: normal Keywords: patch

Created on 2013-10-02 17:03 by gvanrossum, last changed 2022-04-11 14:57 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
TB.patch gvanrossum, 2013-10-02 18:41 review
Messages (13)
msg198852 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2013-10-02 17:03
The traceback module is driving me nuts.  It has some handy helpers to extract info about a traceback or a full stack without formatting them, but (a) these are _internal, and (b) they don't return the frame object as part of the information, so code that wants to do additional stuff (e.g. print the values of local variables) cannot use them. (I guess in a sense the two problems cancel each other out. :-)

Here's a proposed fix.  (I know it is lacking tests.)

It adds extract_tb_ex() and extract_stack_ex() functions that return a list of 5-tuples filename, line number, function name, text, frame).

I'm also reworking the lowest-level internal function, _extract_tb_or_stack_iter(), to take an iterator instead of a starting point and a function to get the info and the next starting point.  The old design feels unpythonic to me -- the task at hand so clearly feels like it should wrap an iterator!

Finally, I'm adding some important info to a few docstrings: when the limit clips the number of frames, you get the *oldest* frames from a traceback, but the *newest* frames from a stack. That makes sense when you think about it, but I still think it's worth mentioning.

Feedback?
msg198857 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2013-10-02 18:35
You forgot a patch.
msg198859 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2013-10-02 18:41
Sigh. Here it is.
msg198868 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2013-10-02 20:18
> It adds extract_tb_ex() and extract_stack_ex() functions ...

I don't like "_ex" suffixes, it's not future proof if we need to add another function later.

You may rename them using "_iter" suffix and return an iterator instead of a list. Such idea was also proposed for os.listdir() => os.scandir() / os.iterdir(). See the discussion in #11406. The caller can write tuple(extract_stack_iter()), as I do with dict.items() to sort a dictionary.

> Feedback?

I like unit tests :-) The patch should also document new functions.
You may only need the most recent frames.
msg198871 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2013-10-02 20:41
>
> I don't like "_ex" suffixes, it's not future proof if we need to add
> another function later.
>

Me neither, but you can't change a function that returns a list of 4-tuples
into a function that returns a list of 5-tuples without breaking existing
code. IIRC for struct and time tuples we created a hack in C where we
return something that behaves like an N-tuple but has some extra attributes
-- but I don't think collections.namedtuple supports that.

> You may rename them using "_iter" suffix and return an iterator instead of
> a list.

I already thought of that, but that doesn't work: the iterator version
would return the stack in the wrong order (note the .reverse() call in the
code).

> Such idea was also proposed for os.listdir() => os.scandir() /
> os.iterdir(). See the discussion in #11406. The caller can write
> tuple(extract_stack_iter()), as I do with dict.items() to sort a dictionary.
>
> I like unit tests :-) The patch should also document new functions.
>

I'll take care of that when we've agreed on the new API.

> You may only need the most recent frames.
>

Not sure what you mean by that.
msg198872 - (view) Author: PCManticore (Claudiu.Popa) * (Python triager) Date: 2013-10-02 21:13
> I already thought of that, but that doesn't work: the iterator version
> would return the stack in the wrong order (note the .reverse() call in the code).


Then, couldn't this:

   stack = list(_extract_stack_iter(_get_stack(f), limit=limit))	
   stack.reverse()
   return stack
	

be rewritten as this, knowing the fact that _extract_stack_iter returns an iterable?

  return reversed(_extract_stack_iter(_get_stack(f), limit=limit))

And in this case, extract_stack_ex could become extract_stack_iter or something like that.
msg198873 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2013-10-02 21:26
No, reversed() doesn't work on iterators.
msg198874 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2013-10-02 21:53
> Me neither, but you can't change a function that returns a list of 4-tuples
> into a function that returns a list of 5-tuples without breaking existing
> code. IIRC for struct and time tuples we created a hack in C where we
> return something that behaves like an N-tuple but has some extra attributes
> -- but I don't think collections.namedtuple supports that.

It do.

class tb_entity(namedtuple('tb_entity', 'filename lineno name line')):
    def __new__(cls, filename, lineno, name, line, frame=None):
        self = super().__new__(cls, filename, lineno, name, line)
        self.frame = frame
        return self
msg198876 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2013-10-02 22:42
Nice. However it will take up a lot more space, because now there's an instance dict. (And adding __slots__ to a namedtuple subclass doesn't work.) I'll have to think about whether I care about the extra space.
msg198922 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2013-10-03 22:00
> And adding __slots__ to a namedtuple subclass doesn't work.

Are you sure? I do it all the time.
msg198924 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2013-10-03 22:12
Well this is what I get:

$ python3
Python 3.4.0a1+ (default:41de6f0e62fd+, Aug 27 2013, 18:44:07)
[GCC 4.2.1 Compatible Apple LLVM 4.2 (clang-425.0.28)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from collections import namedtuple
from collections import namedtuple
>>> A = namedtuple('A', 'foo bar')
A = namedtuple('A', 'foo bar')
>>> class B(A):
class B(A):
...   __slots__ = ['baz']
  __slots__ = ['baz']
... 

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: nonempty __slots__ not supported for subtype of 'A'
>>> 

When I try to set __slots__ on an existing namedtuple it doesn't complain, but it doesn't work either:

>>> A.__slots__ = ['xxx']
>>> a.xxx = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'xxx'
>>> 

What am I doing wrong?
msg198925 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2013-10-03 22:13
> Well this is what I get:
> 
> $ python3
> Python 3.4.0a1+ (default:41de6f0e62fd+, Aug 27 2013, 18:44:07)
> [GCC 4.2.1 Compatible Apple LLVM 4.2 (clang-425.0.28)] on darwin
> Type "help", "copyright", "credits" or "license" for more information.
> >>> from collections import namedtuple
> from collections import namedtuple
> >>> A = namedtuple('A', 'foo bar')
> A = namedtuple('A', 'foo bar')
> >>> class B(A):
> class B(A):
> ...   __slots__ = ['baz']
>   __slots__ = ['baz']
> ... 
> 
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
> TypeError: nonempty __slots__ not supported for subtype of 'A'

Ah, ok, you're right. I only use empty __slots__ :-)
msg204627 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2013-11-27 23:25
I decided to abandon this project and close the issue as wontfix.
History
Date User Action Args
2022-04-11 14:57:51adminsetgithub: 63345
2013-11-27 23:25:54gvanrossumsetstatus: open -> closed
resolution: wont fix
messages: + msg204627

stage: patch review -> resolved
2013-10-03 22:13:21pitrousetmessages: + msg198925
2013-10-03 22:12:33gvanrossumsetmessages: + msg198924
2013-10-03 22:00:35pitrousetnosy: + pitrou
messages: + msg198922
2013-10-02 22:42:56gvanrossumsetmessages: + msg198876
2013-10-02 21:53:27serhiy.storchakasetmessages: + msg198874
2013-10-02 21:26:05gvanrossumsetmessages: + msg198873
2013-10-02 21:13:37Claudiu.Popasetmessages: + msg198872
2013-10-02 20:41:00gvanrossumsetmessages: + msg198871
2013-10-02 20:18:30vstinnersetnosy: + vstinner
messages: + msg198868
2013-10-02 19:04:21Claudiu.Popasetnosy: + Claudiu.Popa
2013-10-02 18:41:35gvanrossumsetfiles: + TB.patch
keywords: + patch
messages: + msg198859
2013-10-02 18:35:50serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg198857
2013-10-02 17:03:34gvanrossumsetstage: patch review
type: enhancement
versions: + Python 3.4, Python 3.5
2013-10-02 17:03:01gvanrossumcreate