summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/tracemalloc.rst18
-rw-r--r--Doc/whatsnew/3.7.rst4
-rw-r--r--Lib/test/test_tracemalloc.py30
-rw-r--r--Lib/test/test_warnings/__init__.py6
-rw-r--r--Lib/tracemalloc.py26
-rw-r--r--Lib/warnings.py2
-rw-r--r--Misc/NEWS.d/next/Library/2017-11-24-00-59-12.bpo-32121.ePbmwC.rst6
7 files changed, 68 insertions, 24 deletions
diff --git a/Doc/library/tracemalloc.rst b/Doc/library/tracemalloc.rst
index 048ee64..2d327c0 100644
--- a/Doc/library/tracemalloc.rst
+++ b/Doc/library/tracemalloc.rst
@@ -650,8 +650,8 @@ Traceback
.. class:: Traceback
- Sequence of :class:`Frame` instances sorted from the most recent frame to
- the oldest frame.
+ Sequence of :class:`Frame` instances sorted from the oldest frame to the
+ most recent frame.
A traceback contains at least ``1`` frame. If the ``tracemalloc`` module
failed to get a frame, the filename ``"<unknown>"`` at line number ``0`` is
@@ -663,11 +663,17 @@ Traceback
The :attr:`Trace.traceback` attribute is an instance of :class:`Traceback`
instance.
- .. method:: format(limit=None)
+ .. versionchanged:: 3.7
+ Frames are now sorted from the oldest to the most recent, instead of most recent to oldest.
- Format the traceback as a list of lines with newlines. Use the
- :mod:`linecache` module to retrieve lines from the source code. If
- *limit* is set, only format the *limit* most recent frames.
+ .. method:: format(limit=None, most_recent_first=False)
+
+ Format the traceback as a list of lines with newlines. Use the
+ :mod:`linecache` module to retrieve lines from the source code.
+ If *limit* is set, format the *limit* most recent frames if *limit*
+ is positive. Otherwise, format the ``abs(limit)`` oldest frames.
+ If *most_recent_first* is ``True``, the order of the formatted frames
+ is reversed, returning the most recent frame first instead of last.
Similar to the :func:`traceback.format_tb` function, except that
:meth:`.format` does not include newlines.
diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst
index e4600fe..5c00159 100644
--- a/Doc/whatsnew/3.7.rst
+++ b/Doc/whatsnew/3.7.rst
@@ -751,6 +751,10 @@ Changes in the Python API
avoid a warning escape them with a backslash.
(Contributed by Serhiy Storchaka in :issue:`30349`.)
+* :class:`tracemalloc.Traceback` frames are now sorted from oldest to most
+ recent to be more consistent with :mod:`traceback`.
+ (Contributed by Jesse Bakker in :issue:`32121`.)
+
.. _Unicode Technical Standard #18: https://unicode.org/reports/tr18/
diff --git a/Lib/test/test_tracemalloc.py b/Lib/test/test_tracemalloc.py
index 533ba6d..b0a0e1b 100644
--- a/Lib/test/test_tracemalloc.py
+++ b/Lib/test/test_tracemalloc.py
@@ -171,6 +171,9 @@ class TestTracemallocEnabled(unittest.TestCase):
traces = tracemalloc._get_traces()
+ obj1_traceback._frames = tuple(reversed(obj1_traceback._frames))
+ obj2_traceback._frames = tuple(reversed(obj2_traceback._frames))
+
trace1 = self.find_trace(traces, obj1_traceback)
trace2 = self.find_trace(traces, obj2_traceback)
domain1, size1, traceback1 = trace1
@@ -537,11 +540,11 @@ class TestSnapshot(unittest.TestCase):
def test_trace_format(self):
snapshot, snapshot2 = create_snapshots()
trace = snapshot.traces[0]
- self.assertEqual(str(trace), 'a.py:2: 10 B')
+ self.assertEqual(str(trace), 'b.py:4: 10 B')
traceback = trace.traceback
- self.assertEqual(str(traceback), 'a.py:2')
+ self.assertEqual(str(traceback), 'b.py:4')
frame = traceback[0]
- self.assertEqual(str(frame), 'a.py:2')
+ self.assertEqual(str(frame), 'b.py:4')
def test_statistic_format(self):
snapshot, snapshot2 = create_snapshots()
@@ -574,17 +577,32 @@ class TestSnapshot(unittest.TestCase):
side_effect=getline):
tb = snapshot.traces[0].traceback
self.assertEqual(tb.format(),
+ [' File "b.py", line 4',
+ ' <b.py, 4>',
+ ' File "a.py", line 2',
+ ' <a.py, 2>'])
+
+ self.assertEqual(tb.format(limit=1),
+ [' File "a.py", line 2',
+ ' <a.py, 2>'])
+
+ self.assertEqual(tb.format(limit=-1),
+ [' File "b.py", line 4',
+ ' <b.py, 4>'])
+
+ self.assertEqual(tb.format(most_recent_first=True),
[' File "a.py", line 2',
' <a.py, 2>',
' File "b.py", line 4',
' <b.py, 4>'])
- self.assertEqual(tb.format(limit=1),
+ self.assertEqual(tb.format(limit=1, most_recent_first=True),
[' File "a.py", line 2',
' <a.py, 2>'])
- self.assertEqual(tb.format(limit=-1),
- [])
+ self.assertEqual(tb.format(limit=-1, most_recent_first=True),
+ [' File "b.py", line 4',
+ ' <b.py, 4>'])
class TestFilters(unittest.TestCase):
diff --git a/Lib/test/test_warnings/__init__.py b/Lib/test/test_warnings/__init__.py
index f2fdaa5..e60bc4d 100644
--- a/Lib/test/test_warnings/__init__.py
+++ b/Lib/test/test_warnings/__init__.py
@@ -941,11 +941,11 @@ class PyWarningsDisplayTests(WarningsDisplayTests, unittest.TestCase):
expected = textwrap.dedent('''
{fname}:5: ResourceWarning: unclosed file <...>
f = None
- Object allocated at (most recent call first):
- File "{fname}", lineno 3
- f = open(__file__)
+ Object allocated at (most recent call last):
File "{fname}", lineno 7
func()
+ File "{fname}", lineno 3
+ f = open(__file__)
''')
expected = expected.format(fname=support.TESTFN).strip()
self.assertEqual(stderr, expected)
diff --git a/Lib/tracemalloc.py b/Lib/tracemalloc.py
index 597a297..2c1ac3b 100644
--- a/Lib/tracemalloc.py
+++ b/Lib/tracemalloc.py
@@ -171,16 +171,18 @@ class Frame:
@total_ordering
class Traceback(Sequence):
"""
- Sequence of Frame instances sorted from the most recent frame
- to the oldest frame.
+ Sequence of Frame instances sorted from the oldest frame
+ to the most recent frame.
"""
__slots__ = ("_frames",)
def __init__(self, frames):
Sequence.__init__(self)
# frames is a tuple of frame tuples: see Frame constructor for the
- # format of a frame tuple
- self._frames = frames
+ # format of a frame tuple; it is reversed, because _tracemalloc
+ # returns frames sorted from most recent to oldest, but the
+ # Python API expects oldest to most recent
+ self._frames = tuple(reversed(frames))
def __len__(self):
return len(self._frames)
@@ -209,11 +211,19 @@ class Traceback(Sequence):
def __repr__(self):
return "<Traceback %r>" % (tuple(self),)
- def format(self, limit=None):
+ def format(self, limit=None, most_recent_first=False):
lines = []
- if limit is not None and limit < 0:
- return lines
- for frame in self[:limit]:
+ if limit is not None:
+ if limit > 0:
+ frame_slice = self[-limit:]
+ else:
+ frame_slice = self[:limit]
+ else:
+ frame_slice = self
+
+ if most_recent_first:
+ frame_slice = reversed(frame_slice)
+ for frame in frame_slice:
lines.append(' File "%s", line %s'
% (frame.filename, frame.lineno))
line = linecache.getline(frame.filename, frame.lineno).strip()
diff --git a/Lib/warnings.py b/Lib/warnings.py
index d7ea057..4e7241f 100644
--- a/Lib/warnings.py
+++ b/Lib/warnings.py
@@ -62,7 +62,7 @@ def _formatwarnmsg_impl(msg):
tb = None
if tb is not None:
- s += 'Object allocated at (most recent call first):\n'
+ s += 'Object allocated at (most recent call last):\n'
for frame in tb:
s += (' File "%s", lineno %s\n'
% (frame.filename, frame.lineno))
diff --git a/Misc/NEWS.d/next/Library/2017-11-24-00-59-12.bpo-32121.ePbmwC.rst b/Misc/NEWS.d/next/Library/2017-11-24-00-59-12.bpo-32121.ePbmwC.rst
new file mode 100644
index 0000000..7701c86
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2017-11-24-00-59-12.bpo-32121.ePbmwC.rst
@@ -0,0 +1,6 @@
+Made ``tracemalloc.Traceback`` behave more like the traceback module,
+sorting the frames from oldest to most recent. ``Traceback.format()``
+now accepts negative *limit*, truncating the result to the ``abs(limit)``
+oldest frames. To get the old behaviour, one can use the new
+*most_recent_first* argument to ``Traceback.format()``.
+(Patch by Jesse Bakker.)