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.
This commit is contained in:
Ivan Levkivskyi 2019-02-17 23:13:46 +00:00 committed by GitHub
parent 1bf8845f74
commit ac28147e78
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 15 additions and 3 deletions

View File

@ -248,7 +248,14 @@ class TestClassGetitem(unittest.TestCase):
return f'{cls.__name__}[{item.__name__}]' return f'{cls.__name__}[{item.__name__}]'
self.assertEqual(Meta[int], 'Meta[int]') self.assertEqual(Meta[int], 'Meta[int]')
def test_class_getitem_metaclass_2(self): def test_class_getitem_with_metaclass(self):
class Meta(type): pass
class C(metaclass=Meta):
def __class_getitem__(cls, item):
return f'{cls.__name__}[{item.__name__}]'
self.assertEqual(C[int], 'C[int]')
def test_class_getitem_metaclass_first(self):
class Meta(type): class Meta(type):
def __getitem__(cls, item): def __getitem__(cls, item):
return 'from metaclass' return 'from metaclass'

View File

@ -0,0 +1,2 @@
Fix ``__class_getitem__()`` not being called on a class with a custom
non-subscriptable metaclass.

View File

@ -143,6 +143,7 @@ PyObject *
PyObject_GetItem(PyObject *o, PyObject *key) PyObject_GetItem(PyObject *o, PyObject *key)
{ {
PyMappingMethods *m; PyMappingMethods *m;
PySequenceMethods *ms;
if (o == NULL || key == NULL) { if (o == NULL || key == NULL) {
return null_error(); return null_error();
@ -155,7 +156,8 @@ PyObject_GetItem(PyObject *o, PyObject *key)
return item; return item;
} }
if (o->ob_type->tp_as_sequence) { ms = o->ob_type->tp_as_sequence;
if (ms && ms->sq_item) {
if (PyIndex_Check(key)) { if (PyIndex_Check(key)) {
Py_ssize_t key_value; Py_ssize_t key_value;
key_value = PyNumber_AsSsize_t(key, PyExc_IndexError); key_value = PyNumber_AsSsize_t(key, PyExc_IndexError);
@ -163,9 +165,10 @@ PyObject_GetItem(PyObject *o, PyObject *key)
return NULL; return NULL;
return PySequence_GetItem(o, key_value); return PySequence_GetItem(o, key_value);
} }
else if (o->ob_type->tp_as_sequence->sq_item) else {
return type_error("sequence index must " return type_error("sequence index must "
"be integer, not '%.200s'", key); "be integer, not '%.200s'", key);
}
} }
if (PyType_Check(o)) { if (PyType_Check(o)) {