File tree Expand file tree Collapse file tree 4 files changed +39
-17
lines changed
Expand file tree Collapse file tree 4 files changed +39
-17
lines changed Original file line number Diff line number Diff line change @@ -173,6 +173,10 @@ filterwarnings= [
173173 # Ignore jupyter_client warnings
174174 " module:Jupyter is migrating its paths to use standard platformdirs:DeprecationWarning" ,
175175
176+ # we do not want to raise on resources warnings, or we will not have a chance to
177+ # collect the messages and print the location of the leak
178+ " always::ResourceWarning" ,
179+
176180 # ignore unclosed sqlite in traits
177181 " ignore:unclosed database in <sqlite3.Connection:ResourceWarning" ,
178182
Original file line number Diff line number Diff line change 11import asyncio
22import logging
33import os
4+ import tracemalloc
5+ import warnings
46from math import inf
57from typing import Any , Callable , no_type_check
68from unittest .mock import MagicMock
@@ -207,3 +209,34 @@ async def ipkernel(anyio_backend):
207209 yield kernel
208210 kernel .destroy ()
209211 ZMQInteractiveShell .clear_instance ()
212+
213+
214+ @pytest .fixture ()
215+ def tracemalloc_resource_warning (recwarn , N = 10 ):
216+ """fixture to enable tracemalloc for a single test, and report the
217+ location of the leaked resource
218+
219+ We cannot only enable tracemalloc, as otherwise it is stopped just after the test,
220+ the frame cache is clear by tracemalloc.stop() and thus the warning running code
221+ get None when doing `tracemalloc.get_object_traceback(r.source)`.
222+
223+ So we need to both filter the warnings to enable ResourceWarning,
224+ and loop through it print the stack before we stop tracemalloc and continue
225+
226+ """
227+
228+ tracemalloc .start (N )
229+ with warnings .catch_warnings ():
230+ warnings .simplefilter ("always" , category = ResourceWarning )
231+ yield None
232+ try :
233+ for r in recwarn :
234+ if r .category is ResourceWarning and r .source is not None :
235+ tb = tracemalloc .get_object_traceback (r .source )
236+ if tb :
237+ info = f"Leaking resource (-):{ r } \n |" + "\n |" .join (tb .format ())
238+ # technically an Error and not a failure as we fail in the fixture
239+ # and not the test
240+ pytest .fail (info )
241+ finally :
242+ tracemalloc .stop ()
Original file line number Diff line number Diff line change 1919
2020from .utils import TemporaryWorkingDirectory
2121
22-
23- @pytest .fixture (scope = "module" , autouse = True )
24- def _enable_tracemalloc ():
25- try :
26- import tracemalloc
27- except ModuleNotFoundError :
28- # pypy
29- tracemalloc = None
30- if tracemalloc is not None :
31- tracemalloc .start ()
32- yield
33- if tracemalloc is not None :
34- tracemalloc .stop ()
35-
36-
3722sample_info : dict = {
3823 "ip" : "1.2.3.4" ,
3924 "transport" : "ipc" ,
@@ -133,7 +118,7 @@ def test_port_bind_failure_recovery(request):
133118 app .init_sockets ()
134119
135120
136- def test_port_bind_failure_gives_up_retries (request ):
121+ def test_port_bind_failure_gives_up_retries (request , tracemalloc_resource_warning ):
137122 cfg = Config ()
138123 with TemporaryWorkingDirectory () as d :
139124 cfg .ProfileDir .location = d
Original file line number Diff line number Diff line change @@ -51,7 +51,7 @@ async def test_direct_execute_request_aborting(ipkernel):
5151 assert reply ["content" ]["status" ] == "aborted"
5252
5353
54- async def test_complete_request (ipkernel ):
54+ async def test_complete_request (ipkernel , tracemalloc_resource_warning ):
5555 reply = await ipkernel .test_shell_message ("complete_request" , dict (code = "hello" , cursor_pos = 0 ))
5656 assert reply ["header" ]["msg_type" ] == "complete_reply"
5757 ipkernel .use_experimental_completions = False
You can’t perform that action at this time.
0 commit comments