summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2003-02-11 18:44:42 (GMT)
committerGuido van Rossum <guido@python.org>2003-02-11 18:44:42 (GMT)
commitb6e5a0c6587420ba666d5402a8aefd20b9f8c507 (patch)
tree0534e16d21d244db518e0c7de7ec22ba79f54c54
parent6bae46d8c14fc312f38a1087803c559b119c9bb5 (diff)
downloadcpython-b6e5a0c6587420ba666d5402a8aefd20b9f8c507.zip
cpython-b6e5a0c6587420ba666d5402a8aefd20b9f8c507.tar.gz
cpython-b6e5a0c6587420ba666d5402a8aefd20b9f8c507.tar.bz2
Put proper tests in classmethod_get(). Remove the type argument to
descr_check(); it wasn't useful. Change the type argument of the various _get() methods to PyObject * because the call signature of tp_descr_get doesn't guarantee its type.
-rw-r--r--Lib/test/test_descr.py40
-rw-r--r--Objects/descrobject.c63
2 files changed, 87 insertions, 16 deletions
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index d7368d3..f481205 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -3733,6 +3733,45 @@ def dict_type_with_metaclass():
__metaclass__ = M
veris(type(C.__dict__), type(B.__dict__))
+def meth_class_get():
+ # Full coverage of descrobject.c::classmethod_get()
+ if verbose: print "Testing __get__ method of METH_CLASS C methods..."
+ # Baseline
+ arg = [1, 2, 3]
+ res = {1: None, 2: None, 3: None}
+ vereq(dict.fromkeys(arg), res)
+ vereq({}.fromkeys(arg), res)
+ # Now get the descriptor
+ descr = dict.__dict__["fromkeys"]
+ # More baseline using the descriptor directly
+ vereq(descr.__get__(None, dict)(arg), res)
+ vereq(descr.__get__({})(arg), res)
+ # Now check various error cases
+ try:
+ descr.__get__(None, None)
+ except TypeError:
+ pass
+ else:
+ raise TestFailed, "shouldn't have allowed descr.__get__(None, None)"
+ try:
+ descr.__get__(42)
+ except TypeError:
+ pass
+ else:
+ raise TestFailed, "shouldn't have allowed descr.__get__(42)"
+ try:
+ descr.__get__(None, 42)
+ except TypeError:
+ pass
+ else:
+ raise TestFailed, "shouldn't have allowed descr.__get__(None, 42)"
+ try:
+ descr.__get__(None, int)
+ except TypeError:
+ pass
+ else:
+ raise TestFailed, "shouldn't have allowed descr.__get__(None, int)"
+
def test_main():
do_this_first()
@@ -3819,6 +3858,7 @@ def test_main():
mutable_names()
subclass_right_op()
dict_type_with_metaclass()
+ meth_class_get()
if verbose: print "All OK"
diff --git a/Objects/descrobject.c b/Objects/descrobject.c
index 6c78778..77ef359 100644
--- a/Objects/descrobject.c
+++ b/Objects/descrobject.c
@@ -57,10 +57,9 @@ wrapper_repr(PyWrapperDescrObject *descr)
}
static int
-descr_check(PyDescrObject *descr, PyObject *obj, PyTypeObject *type,
- PyObject **pres)
+descr_check(PyDescrObject *descr, PyObject *obj, PyObject **pres)
{
- if (obj == NULL || (obj == Py_None && type != Py_None->ob_type)) {
+ if (obj == NULL) {
Py_INCREF(descr);
*pres = (PyObject *)descr;
return 1;
@@ -79,38 +78,69 @@ descr_check(PyDescrObject *descr, PyObject *obj, PyTypeObject *type,
}
static PyObject *
-classmethod_get(PyMethodDescrObject *descr, PyObject *obj,
- PyTypeObject *type)
+classmethod_get(PyMethodDescrObject *descr, PyObject *obj, PyObject *type)
{
- return PyCFunction_New(descr->d_method, (PyObject *)type);
+ /* Ensure a valid type. Class methods ignore obj. */
+ if (type == NULL) {
+ if (obj != NULL)
+ type = (PyObject *)obj->ob_type;
+ else {
+ /* Wot - no type?! */
+ PyErr_Format(PyExc_TypeError,
+ "descriptor '%s' for type '%s' "
+ "needs either an object or a type",
+ descr_name((PyDescrObject *)descr),
+ descr->d_type->tp_name);
+ return NULL;
+ }
+ }
+ if (!PyType_Check(type)) {
+ PyErr_Format(PyExc_TypeError,
+ "descriptor '%s' for type '%s' "
+ "needs a type, not a '%s' as arg 2",
+ descr_name((PyDescrObject *)descr),
+ descr->d_type->tp_name,
+ type->ob_type->tp_name);
+ return NULL;
+ }
+ if (!PyType_IsSubtype((PyTypeObject *)type, descr->d_type)) {
+ PyErr_Format(PyExc_TypeError,
+ "descriptor '%s' for type '%s' "
+ "doesn't apply to type '%s'",
+ descr_name((PyDescrObject *)descr),
+ descr->d_type->tp_name,
+ ((PyTypeObject *)type)->tp_name);
+ return NULL;
+ }
+ return PyCFunction_New(descr->d_method, type);
}
static PyObject *
-method_get(PyMethodDescrObject *descr, PyObject *obj, PyTypeObject *type)
+method_get(PyMethodDescrObject *descr, PyObject *obj, PyObject *type)
{
PyObject *res;
- if (descr_check((PyDescrObject *)descr, obj, type, &res))
+ if (descr_check((PyDescrObject *)descr, obj, &res))
return res;
return PyCFunction_New(descr->d_method, obj);
}
static PyObject *
-member_get(PyMemberDescrObject *descr, PyObject *obj, PyTypeObject *type)
+member_get(PyMemberDescrObject *descr, PyObject *obj, PyObject *type)
{
PyObject *res;
- if (descr_check((PyDescrObject *)descr, obj, type, &res))
+ if (descr_check((PyDescrObject *)descr, obj, &res))
return res;
return PyMember_GetOne((char *)obj, descr->d_member);
}
static PyObject *
-getset_get(PyGetSetDescrObject *descr, PyObject *obj, PyTypeObject *type)
+getset_get(PyGetSetDescrObject *descr, PyObject *obj, PyObject *type)
{
PyObject *res;
- if (descr_check((PyDescrObject *)descr, obj, type, &res))
+ if (descr_check((PyDescrObject *)descr, obj, &res))
return res;
if (descr->d_getset->get != NULL)
return descr->d_getset->get(obj, descr->d_getset->closure);
@@ -122,11 +152,11 @@ getset_get(PyGetSetDescrObject *descr, PyObject *obj, PyTypeObject *type)
}
static PyObject *
-wrapper_get(PyWrapperDescrObject *descr, PyObject *obj, PyTypeObject *type)
+wrapper_get(PyWrapperDescrObject *descr, PyObject *obj, PyObject *type)
{
PyObject *res;
- if (descr_check((PyDescrObject *)descr, obj, type, &res))
+ if (descr_check((PyDescrObject *)descr, obj, &res))
return res;
return PyWrapper_New((PyObject *)descr, obj);
}
@@ -395,10 +425,11 @@ static PyTypeObject PyMethodDescr_Type = {
0, /* tp_descr_set */
};
+/* This is for METH_CLASS in C, not for "f = classmethod(f)" in Python! */
static PyTypeObject PyClassMethodDescr_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
- "special_method_descriptor",
+ "classmethod_descriptor",
sizeof(PyMethodDescrObject),
0,
(destructor)descr_dealloc, /* tp_dealloc */
@@ -411,7 +442,7 @@ static PyTypeObject PyClassMethodDescr_Type = {
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
- (ternaryfunc)classmethoddescr_call, /* tp_call */
+ (ternaryfunc)classmethoddescr_call, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */