[3.9] bpo-42332: Add weakref slot to types.GenericAlias (GH-23250) (GH-23309)

(cherry picked from commit 384b7a4bd9)
This commit is contained in:
kj 2020-11-18 05:45:08 +07:00 committed by GitHub
parent 48a9c0eb2a
commit 71ba5f52d2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 59 additions and 38 deletions

View file

@ -13,7 +13,10 @@ from contextvars import ContextVar, Token
from dataclasses import Field from dataclasses import Field
from functools import partial, partialmethod, cached_property from functools import partial, partialmethod, cached_property
from mailbox import Mailbox, _PartialFile from mailbox import Mailbox, _PartialFile
from ctypes import Array, LibraryLoader try:
import ctypes
except ImportError:
ctypes = None
from difflib import SequenceMatcher from difflib import SequenceMatcher
from filecmp import dircmp from filecmp import dircmp
from fileinput import FileInput from fileinput import FileInput
@ -44,9 +47,7 @@ V = TypeVar('V')
class BaseTest(unittest.TestCase): class BaseTest(unittest.TestCase):
"""Test basics.""" """Test basics."""
generic_types = [type, tuple, list, dict, set, frozenset, enumerate,
def test_subscriptable(self):
for t in (type, tuple, list, dict, set, frozenset, enumerate,
defaultdict, deque, defaultdict, deque,
SequenceMatcher, SequenceMatcher,
dircmp, dircmp,
@ -75,14 +76,17 @@ class BaseTest(unittest.TestCase):
TemporaryDirectory, SpooledTemporaryFile, TemporaryDirectory, SpooledTemporaryFile,
Queue, SimpleQueue, Queue, SimpleQueue,
_AssertRaisesContext, _AssertRaisesContext,
Array, LibraryLoader,
SplitResult, ParseResult, SplitResult, ParseResult,
ValueProxy, ApplyResult, ValueProxy, ApplyResult,
WeakSet, ReferenceType, ref, WeakSet, ReferenceType, ref,
ShareableList, MPSimpleQueue, ShareableList, MPSimpleQueue,
Future, _WorkItem, Future, _WorkItem,
Morsel, Morsel]
): if ctypes is not None:
generic_types.extend((ctypes.Array, ctypes.LibraryLoader))
def test_subscriptable(self):
for t in self.generic_types:
if t is None: if t is None:
continue continue
tname = t.__name__ tname = t.__name__
@ -289,5 +293,15 @@ class BaseTest(unittest.TestCase):
for generic_alias_property in ("__origin__", "__args__", "__parameters__"): for generic_alias_property in ("__origin__", "__args__", "__parameters__"):
self.assertIn(generic_alias_property, dir_of_gen_alias) self.assertIn(generic_alias_property, dir_of_gen_alias)
def test_weakref(self):
for t in self.generic_types:
if t is None:
continue
tname = t.__name__
with self.subTest(f"Testing {tname}"):
alias = t[int]
self.assertEqual(ref(alias)(), alias)
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -0,0 +1 @@
:class:`types.GenericAlias` objects can now be the targets of weakrefs.

View file

@ -9,6 +9,7 @@ typedef struct {
PyObject *origin; PyObject *origin;
PyObject *args; PyObject *args;
PyObject *parameters; PyObject *parameters;
PyObject* weakreflist;
} gaobject; } gaobject;
static void static void
@ -17,6 +18,9 @@ ga_dealloc(PyObject *self)
gaobject *alias = (gaobject *)self; gaobject *alias = (gaobject *)self;
_PyObject_GC_UNTRACK(self); _PyObject_GC_UNTRACK(self);
if (alias->weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject *)alias);
}
Py_XDECREF(alias->origin); Py_XDECREF(alias->origin);
Py_XDECREF(alias->args); Py_XDECREF(alias->args);
Py_XDECREF(alias->parameters); Py_XDECREF(alias->parameters);
@ -593,6 +597,7 @@ PyTypeObject Py_GenericAliasType = {
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
.tp_traverse = ga_traverse, .tp_traverse = ga_traverse,
.tp_richcompare = ga_richcompare, .tp_richcompare = ga_richcompare,
.tp_weaklistoffset = offsetof(gaobject, weakreflist),
.tp_methods = ga_methods, .tp_methods = ga_methods,
.tp_members = ga_members, .tp_members = ga_members,
.tp_alloc = PyType_GenericAlloc, .tp_alloc = PyType_GenericAlloc,
@ -624,6 +629,7 @@ Py_GenericAlias(PyObject *origin, PyObject *args)
alias->origin = origin; alias->origin = origin;
alias->args = args; alias->args = args;
alias->parameters = NULL; alias->parameters = NULL;
alias->weakreflist = NULL;
_PyObject_GC_TRACK(alias); _PyObject_GC_TRACK(alias);
return (PyObject *)alias; return (PyObject *)alias;
} }