From df59646acfdc5a8d07259eb6639b0a3c6062444b Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Tue, 4 Jul 2023 07:26:00 -0700 Subject: [PATCH] gh-106403: Restore weakref support for TypeVar and friends --- Lib/test/test_type_params.py | 31 +++++++++++++++++++ ...-07-04-07-25-30.gh-issue-106403.GmefbV.rst | 4 +++ Objects/typevarobject.c | 12 ++++--- 3 files changed, 42 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-04-07-25-30.gh-issue-106403.GmefbV.rst diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py index 3026cc22476619..bced641a9661fd 100644 --- a/Lib/test/test_type_params.py +++ b/Lib/test/test_type_params.py @@ -3,6 +3,7 @@ import types import unittest import pickle +import weakref from test.support import requires_working_socket, check_syntax_error, run_code from typing import Generic, Sequence, TypeVar, TypeVarTuple, ParamSpec, get_args @@ -921,3 +922,33 @@ def test_pickling_classes(self): # These instances are not equal, # but class check is good enough: self.assertIsInstance(pickle.loads(pickled), real_class) + + +class TypeParamsWeakRefTest(unittest.TestCase): + def test_weakrefs(self): + T = TypeVar('T') + P = ParamSpec('P') + class OldStyle(Generic[T]): + pass + + class NewStyle[T]: + pass + + cases = [ + T, + TypeVar('T', bound=int), + P, + P.args, + P.kwargs, + TypeVarTuple('Ts'), + OldStyle, + OldStyle[int], + OldStyle(), + NewStyle, + NewStyle[int], + NewStyle(), + Generic[T], + ] + for case in cases: + with self.subTest(case=case): + weakref.ref(case) diff --git a/Misc/NEWS.d/next/Library/2023-07-04-07-25-30.gh-issue-106403.GmefbV.rst b/Misc/NEWS.d/next/Library/2023-07-04-07-25-30.gh-issue-106403.GmefbV.rst new file mode 100644 index 00000000000000..4fea45f16c4f8e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-04-07-25-30.gh-issue-106403.GmefbV.rst @@ -0,0 +1,4 @@ +Instances of :class:`typing.TypeVar`, :class:`typing.ParamSpec`, +:class:`typing.ParamSpecArgs`, :class:`typing.ParamSpecKwargs`, and +:class:`typing.TypeVarTuple` once again support weak references, fixing a +regression introduced in Python 3.12.0 beta 1. Patch by Jelle Zijlstra. diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c index 0b44f84b6f01d2..5605662f0e6d5e 100644 --- a/Objects/typevarobject.c +++ b/Objects/typevarobject.c @@ -500,7 +500,7 @@ PyType_Spec typevar_spec = { .name = "typing.TypeVar", .basicsize = sizeof(typevarobject), .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE - | Py_TPFLAGS_MANAGED_DICT, + | Py_TPFLAGS_MANAGED_DICT | Py_TPFLAGS_MANAGED_WEAKREF, .slots = typevar_slots, }; @@ -647,7 +647,8 @@ static PyType_Slot paramspecargs_slots[] = { PyType_Spec paramspecargs_spec = { .name = "typing.ParamSpecArgs", .basicsize = sizeof(paramspecattrobject), - .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE, + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE + | Py_TPFLAGS_MANAGED_WEAKREF, .slots = paramspecargs_slots, }; @@ -726,7 +727,8 @@ static PyType_Slot paramspeckwargs_slots[] = { PyType_Spec paramspeckwargs_spec = { .name = "typing.ParamSpecKwargs", .basicsize = sizeof(paramspecattrobject), - .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE, + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE + | Py_TPFLAGS_MANAGED_WEAKREF, .slots = paramspeckwargs_slots, }; @@ -1007,7 +1009,7 @@ PyType_Spec paramspec_spec = { .name = "typing.ParamSpec", .basicsize = sizeof(paramspecobject), .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE - | Py_TPFLAGS_MANAGED_DICT, + | Py_TPFLAGS_MANAGED_DICT | Py_TPFLAGS_MANAGED_WEAKREF, .slots = paramspec_slots, }; @@ -1228,7 +1230,7 @@ PyType_Spec typevartuple_spec = { .name = "typing.TypeVarTuple", .basicsize = sizeof(typevartupleobject), .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_MANAGED_DICT - | Py_TPFLAGS_HAVE_GC, + | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_MANAGED_WEAKREF, .slots = typevartuple_slots, };