Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Lib/test/test_typing.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import annotationlib
import atexit
import contextlib
import collections
import collections.abc
Expand Down Expand Up @@ -6550,6 +6551,14 @@ class F:
class InternalsTests(BaseTestCase):
def test_collect_parameters(self):
typing = import_helper.import_fresh_module("typing")
# Importing typing registers an internal function named _clear_caches
# with atexit. The throwaway module created here installs its own
# handler, which holds the module alive and keeps references until
# interpreter shutdown even after the test finishes. Each repetition
# of this test under -R would therefore leak another module copy. To
# avoid this, we unregister the handler once the test is done.
self.addCleanup(atexit.unregister, typing._clear_caches)

with self.assertWarnsRegex(
DeprecationWarning,
"The private _collect_parameters function is deprecated"
Expand Down Expand Up @@ -7719,6 +7728,10 @@ def test_bytestring(self):

with self.assertWarns(DeprecationWarning):
from typing import ByteString
# Drop the exit handler of this throwaway copy, see the comment in
# InternalsTests.test_collect_parameters.
self.addCleanup(atexit.unregister, sys.modules["typing"]._clear_caches)

with self.assertWarns(DeprecationWarning):
self.assertIsInstance(b'', ByteString)
with self.assertWarns(DeprecationWarning):
Expand Down
6 changes: 6 additions & 0 deletions Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"""

from abc import abstractmethod, ABCMeta
import atexit
import collections
from collections import defaultdict
import collections.abc
Expand Down Expand Up @@ -397,6 +398,11 @@ def _clear_caches():
cleanup()


# Release the LRU caches at shutdown, they otherwise redistribute reference
# leaks of one extension to types of unrelated ones. See GH-151728.
atexit.register(_clear_caches)


def _tp_cache(func=None, /, *, typed=False):
"""Internal wrapper caching __getitem__ of generic types.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Clear the internal :mod:`typing` caches from an exit handler. Previously, an
extension module that leaked a reference to :mod:`typing` would also keep every
subscripted type alive past interpreter shutdown, including types owned by
unrelated extension modules.
Loading