self.assertEqual(D[int], 'D[int]')
self.assertEqual(D[D], 'D[D]')
+ def test_class_getitem_classmethod(self):
+ class C:
+ @classmethod
+ def __class_getitem__(cls, item):
+ return f'{cls.__name__}[{item.__name__}]'
+ class D(C): ...
+ self.assertEqual(D[int], 'D[int]')
+ self.assertEqual(D[D], 'D[D]')
+
def test_class_getitem_patched(self):
class C:
def __init_subclass__(cls):
def __class_getitem__(cls, item):
return f'{cls.__name__}[{item.__name__}]'
- cls.__class_getitem__ = __class_getitem__
+ cls.__class_getitem__ = classmethod(__class_getitem__)
class D(C): ...
self.assertEqual(D[int], 'D[int]')
self.assertEqual(D[D], 'D[D]')
def test_c_class(self):
from _testcapi import Generic, GenericAlias
- self.assertIsInstance(Generic.__class_getitem__(Generic, int), GenericAlias)
+ self.assertIsInstance(Generic.__class_getitem__(int), GenericAlias)
IntGeneric = Generic[int]
self.assertIs(type(IntGeneric), GenericAlias)
--- /dev/null
+``__class_getitem__`` is now an automatic class method.
} PyGenericObject;
static PyObject *
-generic_class_getitem(PyObject *self, PyObject *args)
+generic_class_getitem(PyObject *type, PyObject *item)
{
- PyObject *type, *item;
- if (!PyArg_UnpackTuple(args, "__class_getitem__", 2, 2, &type, &item)) {
- return NULL;
- }
return generic_alias_new(item);
}
static PyMethodDef generic_methods[] = {
- {"__class_getitem__", generic_class_getitem, METH_VARARGS|METH_STATIC, NULL},
+ {"__class_getitem__", generic_class_getitem, METH_O|METH_CLASS, NULL},
{NULL} /* sentinel */
};
}
if (PyType_Check(o)) {
- PyObject *meth, *result, *stack[2] = {o, key};
+ PyObject *meth, *result, *stack[1] = {key};
_Py_IDENTIFIER(__class_getitem__);
meth = _PyObject_GetAttrId(o, &PyId___class_getitem__);
if (meth) {
- result = _PyObject_FastCall(meth, stack, 2);
+ result = _PyObject_FastCall(meth, stack, 1);
Py_DECREF(meth);
return result;
}
/* alphabetical order */
_Py_IDENTIFIER(__abstractmethods__);
_Py_IDENTIFIER(__class__);
+_Py_IDENTIFIER(__class_getitem__);
_Py_IDENTIFIER(__delitem__);
_Py_IDENTIFIER(__dict__);
_Py_IDENTIFIER(__doc__);
Py_DECREF(tmp);
}
- /* Special-case __init_subclass__: if it's a plain function,
- make it a classmethod */
+ /* Special-case __init_subclass__ and __class_getitem__:
+ if they are plain functions, make them classmethods */
tmp = _PyDict_GetItemId(dict, &PyId___init_subclass__);
if (tmp != NULL && PyFunction_Check(tmp)) {
tmp = PyClassMethod_New(tmp);
Py_DECREF(tmp);
}
+ tmp = _PyDict_GetItemId(dict, &PyId___class_getitem__);
+ if (tmp != NULL && PyFunction_Check(tmp)) {
+ tmp = PyClassMethod_New(tmp);
+ if (tmp == NULL)
+ goto error;
+ if (_PyDict_SetItemId(dict, &PyId___class_getitem__, tmp) < 0) {
+ Py_DECREF(tmp);
+ goto error;
+ }
+ Py_DECREF(tmp);
+ }
+
/* Add descriptors for custom slots from __slots__, or for __dict__ */
mp = PyHeapType_GET_MEMBERS(et);
slotoffset = base->tp_basicsize;