]> granicus.if.org Git - python/commitdiff
bpo-35992: Use PySequence_GetItem only if sq_item is not NULL (GH-11857)
authorIvan Levkivskyi <levkivskyi@gmail.com>
Sun, 17 Feb 2019 23:13:46 +0000 (23:13 +0000)
committerGitHub <noreply@github.com>
Sun, 17 Feb 2019 23:13:46 +0000 (23:13 +0000)
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.

Lib/test/test_genericclass.py
Misc/NEWS.d/next/Core and Builtins/2019-02-14-12-01-44.bpo-35992.nG9e2L.rst [new file with mode: 0644]
Objects/abstract.c

index 37e755b1167e83529c377975f6a0b889b75efc02..37a87bc6815ec2fb414f392db36a9ddd32dcdbd3 100644 (file)
@@ -248,7 +248,14 @@ class TestClassGetitem(unittest.TestCase):
                 return f'{cls.__name__}[{item.__name__}]'
         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):
             def __getitem__(cls, item):
                 return 'from metaclass'
diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-02-14-12-01-44.bpo-35992.nG9e2L.rst b/Misc/NEWS.d/next/Core and Builtins/2019-02-14-12-01-44.bpo-35992.nG9e2L.rst
new file mode 100644 (file)
index 0000000..3d8dcd4
--- /dev/null
@@ -0,0 +1,2 @@
+Fix ``__class_getitem__()`` not being called on a class with a custom\r
+non-subscriptable metaclass.\r
index 567da2d6b50c495bd70cc9a4959a7a2ae7f57a29..0565ba34f5b8234f4d6249be655de990f775005d 100644 (file)
@@ -143,6 +143,7 @@ PyObject *
 PyObject_GetItem(PyObject *o, PyObject *key)
 {
     PyMappingMethods *m;
+    PySequenceMethods *ms;
 
     if (o == NULL || key == NULL) {
         return null_error();
@@ -155,7 +156,8 @@ PyObject_GetItem(PyObject *o, PyObject *key)
         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)) {
             Py_ssize_t key_value;
             key_value = PyNumber_AsSsize_t(key, PyExc_IndexError);
@@ -163,9 +165,10 @@ PyObject_GetItem(PyObject *o, PyObject *key)
                 return NULL;
             return PySequence_GetItem(o, key_value);
         }
-        else if (o->ob_type->tp_as_sequence->sq_item)
+        else {
             return type_error("sequence index must "
                               "be integer, not '%.200s'", key);
+        }
     }
 
     if (PyType_Check(o)) {