parent
bdbad91493
commit
9af3e23695
|
@ -0,0 +1,4 @@
|
||||||
|
More information about the location of resources that led Python to raise :class:`ResourceWarning` can now
|
||||||
|
be obtained by enabling :mod:`tracemalloc`.
|
||||||
|
|
||||||
|
See :ref:`resource-warnings` for more information.
|
|
@ -441,3 +441,18 @@ Please read our :ref:`backwards-compatibility` to learn how we proceed about dep
|
||||||
features.
|
features.
|
||||||
|
|
||||||
The full list of warnings is listed in :ref:`the reference documentation <warnings ref>`.
|
The full list of warnings is listed in :ref:`the reference documentation <warnings ref>`.
|
||||||
|
|
||||||
|
|
||||||
|
.. _`resource-warnings`:
|
||||||
|
|
||||||
|
Resource Warnings
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Additional information of the source of a :class:`ResourceWarning` can be obtained when captured by pytest if
|
||||||
|
:mod:`tracemalloc` module is enabled.
|
||||||
|
|
||||||
|
One convenient way to enable :mod:`tracemalloc` when running tests is to set the :envvar:`PYTHONTRACEMALLOC` to a large
|
||||||
|
enough number of frames (say ``20``, but that number is application dependent).
|
||||||
|
|
||||||
|
For more information, consult the `Python Development Mode <https://docs.python.org/3/library/devmode.html>`__
|
||||||
|
section in the Python documentation.
|
||||||
|
|
|
@ -81,6 +81,23 @@ def warning_record_to_str(warning_message: warnings.WarningMessage) -> str:
|
||||||
warning_message.lineno,
|
warning_message.lineno,
|
||||||
warning_message.line,
|
warning_message.line,
|
||||||
)
|
)
|
||||||
|
if warning_message.source is not None:
|
||||||
|
try:
|
||||||
|
import tracemalloc
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
tb = tracemalloc.get_object_traceback(warning_message.source)
|
||||||
|
if tb is not None:
|
||||||
|
formatted_tb = "\n".join(tb.format())
|
||||||
|
# Use a leading new line to better separate the (large) output
|
||||||
|
# from the traceback to the previous warning text.
|
||||||
|
msg += f"\nObject allocated at:\n{formatted_tb}"
|
||||||
|
else:
|
||||||
|
# No need for a leading new line.
|
||||||
|
url = "https://docs.pytest.org/en/stable/how-to/capture-warnings.html#resource-warnings"
|
||||||
|
msg += "Enable tracemalloc to get traceback where the object was allocated.\n"
|
||||||
|
msg += f"See {url} for more info."
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
from typing import List
|
from typing import List
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
@ -774,3 +775,57 @@ class TestStackLevel:
|
||||||
"*Unknown pytest.mark.unknown*",
|
"*Unknown pytest.mark.unknown*",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_resource_warning(pytester: Pytester, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||||
|
# Some platforms (notably PyPy) don't have tracemalloc.
|
||||||
|
# We choose to explicitly not skip this in case tracemalloc is not
|
||||||
|
# available, using `importorskip("tracemalloc")` for example,
|
||||||
|
# because we want to ensure the same code path does not break in those platforms.
|
||||||
|
try:
|
||||||
|
import tracemalloc # noqa
|
||||||
|
|
||||||
|
has_tracemalloc = True
|
||||||
|
except ImportError:
|
||||||
|
has_tracemalloc = False
|
||||||
|
|
||||||
|
# Explicitly disable PYTHONTRACEMALLOC in case pytest's test suite is running
|
||||||
|
# with it enabled.
|
||||||
|
monkeypatch.delenv("PYTHONTRACEMALLOC", raising=False)
|
||||||
|
|
||||||
|
pytester.makepyfile(
|
||||||
|
"""
|
||||||
|
def open_file(p):
|
||||||
|
f = p.open("r")
|
||||||
|
assert p.read_text() == "hello"
|
||||||
|
|
||||||
|
def test_resource_warning(tmp_path):
|
||||||
|
p = tmp_path.joinpath("foo.txt")
|
||||||
|
p.write_text("hello")
|
||||||
|
open_file(p)
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
result = pytester.run(sys.executable, "-Xdev", "-m", "pytest")
|
||||||
|
expected_extra = (
|
||||||
|
[
|
||||||
|
"*ResourceWarning* unclosed file*",
|
||||||
|
"*Enable tracemalloc to get traceback where the object was allocated*",
|
||||||
|
"*See https* for more info.",
|
||||||
|
]
|
||||||
|
if has_tracemalloc
|
||||||
|
else []
|
||||||
|
)
|
||||||
|
result.stdout.fnmatch_lines([*expected_extra, "*1 passed*"])
|
||||||
|
|
||||||
|
monkeypatch.setenv("PYTHONTRACEMALLOC", "20")
|
||||||
|
|
||||||
|
result = pytester.run(sys.executable, "-Xdev", "-m", "pytest")
|
||||||
|
expected_extra = (
|
||||||
|
[
|
||||||
|
"*ResourceWarning* unclosed file*",
|
||||||
|
"*Object allocated at*",
|
||||||
|
]
|
||||||
|
if has_tracemalloc
|
||||||
|
else []
|
||||||
|
)
|
||||||
|
result.stdout.fnmatch_lines([*expected_extra, "*1 passed*"])
|
||||||
|
|
Loading…
Reference in New Issue