mirror of
https://github.com/python/cpython.git
synced 2025-12-31 04:23:37 +00:00
[3.14] gh-105487: Fix __dir__ entries of GenericAlias (GH-138578) (GH-138629)
(cherry picked from commit b0420b505e)
Co-authored-by: sobolevn <mail@sobolevn.me>
Co-authored-by: Emma Smith <emma@emmatyping.dev>
This commit is contained in:
parent
63bd8cfcdb
commit
09fdd219a5
3 changed files with 44 additions and 6 deletions
|
|
@ -402,7 +402,10 @@ def __deepcopy__(self, memo):
|
|||
aliases = [
|
||||
GenericAlias(list, T),
|
||||
GenericAlias(deque, T),
|
||||
GenericAlias(X, T)
|
||||
GenericAlias(X, T),
|
||||
X[T],
|
||||
list[T],
|
||||
deque[T],
|
||||
] + _UNPACKED_TUPLES
|
||||
for alias in aliases:
|
||||
with self.subTest(alias=alias):
|
||||
|
|
@ -432,10 +435,26 @@ def test_union_generic(self):
|
|||
self.assertEqual(a.__parameters__, (T,))
|
||||
|
||||
def test_dir(self):
|
||||
dir_of_gen_alias = set(dir(list[int]))
|
||||
ga = list[int]
|
||||
dir_of_gen_alias = set(dir(ga))
|
||||
self.assertTrue(dir_of_gen_alias.issuperset(dir(list)))
|
||||
for generic_alias_property in ("__origin__", "__args__", "__parameters__"):
|
||||
self.assertIn(generic_alias_property, dir_of_gen_alias)
|
||||
for generic_alias_property in (
|
||||
"__origin__", "__args__", "__parameters__",
|
||||
"__unpacked__",
|
||||
):
|
||||
with self.subTest(generic_alias_property=generic_alias_property):
|
||||
self.assertIn(generic_alias_property, dir_of_gen_alias)
|
||||
for blocked in (
|
||||
"__bases__",
|
||||
"__copy__",
|
||||
"__deepcopy__",
|
||||
):
|
||||
with self.subTest(blocked=blocked):
|
||||
self.assertNotIn(blocked, dir_of_gen_alias)
|
||||
|
||||
for entry in dir_of_gen_alias:
|
||||
with self.subTest(entry=entry):
|
||||
getattr(ga, entry) # must not raise `AttributeError`
|
||||
|
||||
def test_weakref(self):
|
||||
for t in self.generic_types:
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
Remove non-existent :meth:`~object.__copy__`, :meth:`~object.__deepcopy__`, and :attr:`~type.__bases__` from the :meth:`~object.__dir__` entries of :class:`types.GenericAlias`.
|
||||
|
|
@ -648,7 +648,6 @@ ga_vectorcall(PyObject *self, PyObject *const *args,
|
|||
|
||||
static const char* const attr_exceptions[] = {
|
||||
"__class__",
|
||||
"__bases__",
|
||||
"__origin__",
|
||||
"__args__",
|
||||
"__unpacked__",
|
||||
|
|
@ -657,6 +656,11 @@ static const char* const attr_exceptions[] = {
|
|||
"__mro_entries__",
|
||||
"__reduce_ex__", // needed so we don't look up object.__reduce_ex__
|
||||
"__reduce__",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const char* const attr_blocked[] = {
|
||||
"__bases__",
|
||||
"__copy__",
|
||||
"__deepcopy__",
|
||||
NULL,
|
||||
|
|
@ -667,15 +671,29 @@ ga_getattro(PyObject *self, PyObject *name)
|
|||
{
|
||||
gaobject *alias = (gaobject *)self;
|
||||
if (PyUnicode_Check(name)) {
|
||||
// When we check blocked attrs, we don't allow to proxy them to `__origin__`.
|
||||
// Otherwise, we can break existing code.
|
||||
for (const char * const *p = attr_blocked; ; p++) {
|
||||
if (*p == NULL) {
|
||||
break;
|
||||
}
|
||||
if (_PyUnicode_EqualToASCIIString(name, *p)) {
|
||||
goto generic_getattr;
|
||||
}
|
||||
}
|
||||
|
||||
// When we see own attrs, it has a priority over `__origin__`'s attr.
|
||||
for (const char * const *p = attr_exceptions; ; p++) {
|
||||
if (*p == NULL) {
|
||||
return PyObject_GetAttr(alias->origin, name);
|
||||
}
|
||||
if (_PyUnicode_EqualToASCIIString(name, *p)) {
|
||||
break;
|
||||
goto generic_getattr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
generic_getattr:
|
||||
return PyObject_GenericGetAttr(self, name);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue