summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Peterson <benjamin@python.org>2012-05-01 13:51:46 (GMT)
committerBenjamin Peterson <benjamin@python.org>2012-05-01 13:51:46 (GMT)
commit8fbd2954583cbf252999991d7c58e4deacb2688c (patch)
treeff64dc8a51441dc21961c04a69b1e80fa759c254
parent49a69e4d48d68a36325ba9098e1962e8c2195339 (diff)
parent7295c6a871f9cc42a4209a8eebe2e0974194a2a3 (diff)
downloadcpython-8fbd2954583cbf252999991d7c58e4deacb2688c.zip
cpython-8fbd2954583cbf252999991d7c58e4deacb2688c.tar.gz
cpython-8fbd2954583cbf252999991d7c58e4deacb2688c.tar.bz2
merge 3.2 (#14699)
-rw-r--r--Lib/test/test_descr.py16
-rw-r--r--Misc/NEWS2
-rw-r--r--Objects/descrobject.c44
3 files changed, 59 insertions, 3 deletions
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index b9b1c72..079f60b 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -1466,6 +1466,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...
diff --git a/Misc/NEWS b/Misc/NEWS
index e788404..6251da6 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,8 @@ What's New in Python 3.3.0 Alpha 3?
Core and Builtins
-----------------
+- Issue #14699: Fix calling the classmethod descriptor directly.
+
- Issue #14433: Prevent msvcrt crash in interactive prompt when stdin
is closed.
diff --git a/Objects/descrobject.c b/Objects/descrobject.c
index b679c4bc..abcc002 100644
--- a/Objects/descrobject.c
+++ b/Objects/descrobject.c
@@ -257,14 +257,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 *)PyDescr_TYPE(descr));
- if (func == NULL)
+ /* 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), "?",
+ PyDescr_TYPE(descr)->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), "?",
+ PyDescr_TYPE(descr)->tp_name,
+ self->ob_type->tp_name);
+ return NULL;
+ }
+ if (!PyType_IsSubtype((PyTypeObject *)self, PyDescr_TYPE(descr))) {
+ PyErr_Format(PyExc_TypeError,
+ "descriptor '%V' "
+ "requires a subtype of '%.100s' "
+ "but received '%.100s",
+ descr_name((PyDescrObject *)descr), "?",
+ PyDescr_TYPE(descr)->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;
}