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.

Author vstinner
Recipients graingert, vstinner
Date 2019-06-20.16:22:50
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1561047770.59.0.569548499914.issue37350@roundup.psfhosted.org>
In-reply-to
Content
You can implement this behavior using the new sys.unraisablehook (Python 3.8):
---
import sys
import tracemalloc

def foo():
    open('foo', 'wb')

def hook(unraisable):
    orig_unraisablehook(unraisable)
    if unraisable.object is not None:
        tb = tracemalloc.get_object_traceback(unraisable.object)
        if tb:
            print("Object allocated at:")
            for line in tb:
                print(line)


orig_unraisablehook = sys.unraisablehook
sys.unraisablehook = hook
tracemalloc.start(5)

foo()
---

Output:
---
Exception ignored in: <_io.FileIO name='foo' mode='wb' closefd=True>
Traceback (most recent call last):
  File "foo.py", line 5, in foo
    open('foo', 'wb')
ResourceWarning: unclosed file <_io.BufferedWriter name='foo'>
Object allocated at:
foo.py:21
foo.py:5
---

I understand that this issue is about modifying _PyErr_WriteUnraisableDefaultHook() in Python/errors.c (it's written in C) to implement the same logic than the default implementation of warnings._formatwarnmsg() when formatting a ResourceWarning with the source object:

        try:
            import tracemalloc
        # Logging a warning should not raise a new exception:
        # catch Exception, not only ImportError and RecursionError.
        except Exception:
            # don't suggest to enable tracemalloc if it's not available
            tracing = True
            tb = None
        else:
            tracing = tracemalloc.is_tracing()
            try:
                tb = tracemalloc.get_object_traceback(msg.source)
            except Exception:
                # When a warning is logged during Python shutdown, tracemalloc
                # and the import machinery don't work anymore
                tb = None

        if tb is not None:
            s += 'Object allocated at (most recent call last):\n'
            for frame in tb:
                s += ('  File "%s", lineno %s\n'
                      % (frame.filename, frame.lineno))

                try:
                    if linecache is not None:
                        line = linecache.getline(frame.filename, frame.lineno)
                    else:
                        line = None
                except Exception:
                    line = None
                if line:
                    line = line.strip()
                    s += '    %s\n' % line
        elif not tracing:
            s += (f'{category}: Enable tracemalloc to get the object '
                  f'allocation traceback\n')


In C, _PyTraceMalloc_GetTraceback() can be used to retrieve the traceback of an object saved by tracemalloc.

See also _PyMem_DumpTraceback() used to log the tracemaltoc when Python detects a buffer overflow:
https://pythondev.readthedocs.io/debug_tools.html#debug-memory-errors
History
Date User Action Args
2019-06-20 16:22:50vstinnersetrecipients: + vstinner, graingert
2019-06-20 16:22:50vstinnersetmessageid: <1561047770.59.0.569548499914.issue37350@roundup.psfhosted.org>
2019-06-20 16:22:50vstinnerlinkissue37350 messages
2019-06-20 16:22:50vstinnercreate