mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 19:34:08 +00:00 
			
		
		
		
	fix calling the classmethod descriptor directly (closes #14699)
This commit is contained in:
		
							parent
							
								
									dc8cb3d08f
								
							
						
					
					
						commit
						042c47b2c7
					
				
					 3 changed files with 59 additions and 3 deletions
				
			
		| 
						 | 
				
			
			@ -1419,6 +1419,22 @@ order (MRO) for bases """
 | 
			
		|||
        self.assertEqual(x, spam.spamlist)
 | 
			
		||||
        self.assertEqual(a, a1)
 | 
			
		||||
        self.assertEqual(d, d1)
 | 
			
		||||
        spam_cm = spam.spamlist.__dict__['classmeth']
 | 
			
		||||
        x2, a2, d2 = spam_cm(spam.spamlist, *a, **d)
 | 
			
		||||
        self.assertEqual(x2, spam.spamlist)
 | 
			
		||||
        self.assertEqual(a2, a1)
 | 
			
		||||
        self.assertEqual(d2, d1)
 | 
			
		||||
        class SubSpam(spam.spamlist): pass
 | 
			
		||||
        x2, a2, d2 = spam_cm(SubSpam, *a, **d)
 | 
			
		||||
        self.assertEqual(x2, SubSpam)
 | 
			
		||||
        self.assertEqual(a2, a1)
 | 
			
		||||
        self.assertEqual(d2, d1)
 | 
			
		||||
        with self.assertRaises(TypeError):
 | 
			
		||||
            spam_cm()
 | 
			
		||||
        with self.assertRaises(TypeError):
 | 
			
		||||
            spam_cm(spam.spamlist())
 | 
			
		||||
        with self.assertRaises(TypeError):
 | 
			
		||||
            spam_cm(list)
 | 
			
		||||
 | 
			
		||||
    def test_staticmethods(self):
 | 
			
		||||
        # Testing static methods...
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,8 @@ What's New in Python 2.7.4
 | 
			
		|||
Core and Builtins
 | 
			
		||||
-----------------
 | 
			
		||||
 | 
			
		||||
- Issue #14699: Fix calling the classmethod descriptor directly.
 | 
			
		||||
 | 
			
		||||
- Issue #11603 (again): Setting __repr__ to __str__ now raises a RuntimeError
 | 
			
		||||
  when repr() or str() is called on such an object.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -254,14 +254,52 @@ static PyObject *
 | 
			
		|||
classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args,
 | 
			
		||||
                      PyObject *kwds)
 | 
			
		||||
{
 | 
			
		||||
    PyObject *func, *result;
 | 
			
		||||
    Py_ssize_t argc;
 | 
			
		||||
    PyObject *self, *func, *result;
 | 
			
		||||
 | 
			
		||||
    func = PyCFunction_New(descr->d_method, (PyObject *)descr->d_type);
 | 
			
		||||
    /* Make sure that the first argument is acceptable as 'self' */
 | 
			
		||||
    assert(PyTuple_Check(args));
 | 
			
		||||
    argc = PyTuple_GET_SIZE(args);
 | 
			
		||||
    if (argc < 1) {
 | 
			
		||||
        PyErr_Format(PyExc_TypeError,
 | 
			
		||||
                     "descriptor '%V' of '%.100s' "
 | 
			
		||||
                     "object needs an argument",
 | 
			
		||||
                     descr_name((PyDescrObject *)descr), "?",
 | 
			
		||||
                     descr->d_type->tp_name);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    self = PyTuple_GET_ITEM(args, 0);
 | 
			
		||||
    if (!PyType_Check(self)) {
 | 
			
		||||
        PyErr_Format(PyExc_TypeError,
 | 
			
		||||
                     "descriptor '%V' requires a type "
 | 
			
		||||
                     "but received a '%.100s'",
 | 
			
		||||
                     descr_name((PyDescrObject *)descr), "?",
 | 
			
		||||
                     descr->d_type->tp_name,
 | 
			
		||||
                     self->ob_type->tp_name);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    if (!PyType_IsSubtype((PyTypeObject *)self, descr->d_type)) {
 | 
			
		||||
        PyErr_Format(PyExc_TypeError,
 | 
			
		||||
                     "descriptor '%V' "
 | 
			
		||||
                     "requires a subtype of '%.100s' "
 | 
			
		||||
                     "but received '%.100s",
 | 
			
		||||
                     descr_name((PyDescrObject *)descr), "?",
 | 
			
		||||
                     descr->d_type->tp_name,
 | 
			
		||||
                     self->ob_type->tp_name);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    func = PyCFunction_New(descr->d_method, self);
 | 
			
		||||
    if (func == NULL)
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    args = PyTuple_GetSlice(args, 1, argc);
 | 
			
		||||
    if (args == NULL) {
 | 
			
		||||
        Py_DECREF(func);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    result = PyEval_CallObjectWithKeywords(func, args, kwds);
 | 
			
		||||
    Py_DECREF(func);
 | 
			
		||||
    Py_DECREF(args);
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue