Skip to content

Commit ac28147

Browse files
authored
bpo-35992: Use PySequence_GetItem only if sq_item is not NULL (GH-11857)
Not using `__class_getitem__()` fallback if there is a non-subcriptable metaclass was caused by a certain asymmetry between how `PySequenceMethods` and `PyMappingMethods` are used in `PyObject_GetItem`. This PR removes this asymmetry. No tests failed, so I assume it was not intentional.
1 parent 1bf8845 commit ac28147

3 files changed

Lines changed: 15 additions & 3 deletions

File tree

Lib/test/test_genericclass.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,14 @@ def __class_getitem__(cls, item):
248248
return f'{cls.__name__}[{item.__name__}]'
249249
self.assertEqual(Meta[int], 'Meta[int]')
250250

251-
def test_class_getitem_metaclass_2(self):
251+
def test_class_getitem_with_metaclass(self):
252+
class Meta(type): pass
253+
class C(metaclass=Meta):
254+
def __class_getitem__(cls, item):
255+
return f'{cls.__name__}[{item.__name__}]'
256+
self.assertEqual(C[int], 'C[int]')
257+
258+
def test_class_getitem_metaclass_first(self):
252259
class Meta(type):
253260
def __getitem__(cls, item):
254261
return 'from metaclass'
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix ``__class_getitem__()`` not being called on a class with a custom
2+
non-subscriptable metaclass.

Objects/abstract.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ PyObject *
143143
PyObject_GetItem(PyObject *o, PyObject *key)
144144
{
145145
PyMappingMethods *m;
146+
PySequenceMethods *ms;
146147

147148
if (o == NULL || key == NULL) {
148149
return null_error();
@@ -155,17 +156,19 @@ PyObject_GetItem(PyObject *o, PyObject *key)
155156
return item;
156157
}
157158

158-
if (o->ob_type->tp_as_sequence) {
159+
ms = o->ob_type->tp_as_sequence;
160+
if (ms && ms->sq_item) {
159161
if (PyIndex_Check(key)) {
160162
Py_ssize_t key_value;
161163
key_value = PyNumber_AsSsize_t(key, PyExc_IndexError);
162164
if (key_value == -1 && PyErr_Occurred())
163165
return NULL;
164166
return PySequence_GetItem(o, key_value);
165167
}
166-
else if (o->ob_type->tp_as_sequence->sq_item)
168+
else {
167169
return type_error("sequence index must "
168170
"be integer, not '%.200s'", key);
171+
}
169172
}
170173

171174
if (PyType_Check(o)) {

0 commit comments

Comments
 (0)