Skip to content

Commit

Permalink
SF 548651: Fix the METH_CLASS implementation.
Browse files Browse the repository at this point in the history
Most of these patches are from Thomas Heller, with long lines folded
by Tim.  The change to test_descr.py is from Guido.  See the bug report.

Not a bugfix candidate -- METH_CLASS is new in 2.3.
  • Loading branch information
tim-one committed Dec 9, 2002
1 parent c7e3c5e commit bca1cbc
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 8 deletions.
1 change: 1 addition & 0 deletions Include/descrobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ typedef struct {
PyAPI_DATA(PyTypeObject) PyWrapperDescr_Type;

PyAPI_FUNC(PyObject *) PyDescr_NewMethod(PyTypeObject *, PyMethodDef *);
PyAPI_FUNC(PyObject *) PyDescr_NewClassMethod(PyTypeObject *, PyMethodDef *);
PyAPI_FUNC(PyObject *) PyDescr_NewMember(PyTypeObject *,
struct PyMemberDef *);
PyAPI_FUNC(PyObject *) PyDescr_NewGetSet(PyTypeObject *,
Expand Down
8 changes: 4 additions & 4 deletions Lib/test/test_descr.py
Original file line number Diff line number Diff line change
Expand Up @@ -1464,12 +1464,12 @@ def classmethods_in_c():
a = (1, 2, 3)
d = {'abc': 123}
x, a1, d1 = spam.spamlist.classmeth(*a, **d)
veris(x, None)
vereq((spam.spamlist,) + a, a1)
veris(x, spam.spamlist)
vereq(a, a1)
vereq(d, d1)
x, a1, d1 = spam.spamlist().classmeth(*a, **d)
veris(x, None)
vereq((spam.spamlist,) + a, a1)
veris(x, spam.spamlist)
vereq(a, a1)
vereq(d, d1)

def staticmethods():
Expand Down
72 changes: 72 additions & 0 deletions Objects/descrobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ descr_check(PyDescrObject *descr, PyObject *obj, PyTypeObject *type,
return 0;
}

static PyObject *
classmethod_get(PyMethodDescrObject *descr, PyObject *obj,
PyTypeObject *type)
{
return PyCFunction_New(descr->d_method, (PyObject *)type);
}

static PyObject *
method_get(PyMethodDescrObject *descr, PyObject *obj, PyTypeObject *type)
{
Expand Down Expand Up @@ -212,6 +219,21 @@ methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds)
return result;
}

static PyObject *
classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args,
PyObject *kwds)
{
PyObject *func, *result;

func = PyCFunction_New(descr->d_method, (PyObject *)descr->d_type);
if (func == NULL)
return NULL;

result = PyEval_CallObjectWithKeywords(func, args, kwds);
Py_DECREF(func);
return result;
}

static PyObject *
wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds)
{
Expand Down Expand Up @@ -373,6 +395,44 @@ static PyTypeObject PyMethodDescr_Type = {
0, /* tp_descr_set */
};

static PyTypeObject PyClassMethodDescr_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
"special_method_descriptor",
sizeof(PyMethodDescrObject),
0,
(destructor)descr_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
(reprfunc)method_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
(ternaryfunc)classmethoddescr_call, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
0, /* tp_doc */
descr_traverse, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
descr_members, /* tp_members */
method_getset, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
(descrgetfunc)classmethod_get, /* tp_descr_get */
0, /* tp_descr_set */
};

static PyTypeObject PyMemberDescr_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
Expand Down Expand Up @@ -517,6 +577,18 @@ PyDescr_NewMethod(PyTypeObject *type, PyMethodDef *method)
return (PyObject *)descr;
}

PyObject *
PyDescr_NewClassMethod(PyTypeObject *type, PyMethodDef *method)
{
PyMethodDescrObject *descr;

descr = (PyMethodDescrObject *)descr_new(&PyClassMethodDescr_Type,
type, method->ml_name);
if (descr != NULL)
descr->d_method = method;
return (PyObject *)descr;
}

PyObject *
PyDescr_NewMember(PyTypeObject *type, PyMemberDef *member)
{
Expand Down
5 changes: 2 additions & 3 deletions Objects/dictobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -963,17 +963,16 @@ dict_items(register dictobject *mp)
}

static PyObject *
dict_fromkeys(PyObject *mp, PyObject *args)
dict_fromkeys(PyObject *cls, PyObject *args)
{
PyObject *seq;
PyObject *value = Py_None;
PyObject *it; /* iter(seq) */
PyObject *key;
PyObject *d;
PyObject *cls;
int status;

if (!PyArg_ParseTuple(args, "OO|O:fromkeys", &cls, &seq, &value))
if (!PyArg_ParseTuple(args, "O|O:fromkeys", &seq, &value))
return NULL;

d = PyObject_CallObject(cls, NULL);
Expand Down
2 changes: 1 addition & 1 deletion Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -2435,7 +2435,7 @@ add_methods(PyTypeObject *type, PyMethodDef *meth)
"method cannot be both class and static");
return -1;
}
descr = create_specialmethod(meth, PyClassMethod_New);
descr = PyDescr_NewClassMethod(type, meth);
}
else if (meth->ml_flags & METH_STATIC) {
descr = create_specialmethod(meth, PyStaticMethod_New);
Expand Down

0 comments on commit bca1cbc

Please sign in to comment.