Added proper reflection on instances of <type 'method-wrapper'>, e.g.

'[].__add__', to match what the other internal descriptor types provide:
'__objclass__' attribute, '__self__' member, and reasonable repr and
comparison.

Added a test.
This commit is contained in:
Armin Rigo 2005-11-07 08:38:00 +00:00
parent 64b414ad4c
commit c6686b7c7e
2 changed files with 59 additions and 13 deletions

View File

@ -3977,6 +3977,18 @@ def test_init():
else: else:
raise TestFailed, "did not test __init__() for None return" raise TestFailed, "did not test __init__() for None return"
def methodwrapper():
# <type 'method-wrapper'> did not support any reflection before 2.5
if verbose:
print "Testing method-wrapper objects..."
l = []
vereq(l.__add__, l.__add__)
verify(l.__add__ != [].__add__)
verify(l.__add__.__name__ == '__add__')
verify(l.__add__.__self__ is l)
verify(l.__add__.__objclass__ is list)
vereq(l.__add__.__doc__, list.__add__.__doc__)
def test_main(): def test_main():
weakref_segfault() # Must be first, somehow weakref_segfault() # Must be first, somehow
@ -4071,6 +4083,7 @@ def test_main():
filefault() filefault()
vicious_descriptor_nonsense() vicious_descriptor_nonsense()
test_init() test_init()
methodwrapper()
if verbose: print "All OK" if verbose: print "All OK"

View File

@ -50,7 +50,7 @@ getset_repr(PyGetSetDescrObject *descr)
} }
static PyObject * static PyObject *
wrapper_repr(PyWrapperDescrObject *descr) wrapperdescr_repr(PyWrapperDescrObject *descr)
{ {
return descr_repr((PyDescrObject *)descr, return descr_repr((PyDescrObject *)descr,
"<slot wrapper '%s' of '%s' objects>"); "<slot wrapper '%s' of '%s' objects>");
@ -152,7 +152,7 @@ getset_get(PyGetSetDescrObject *descr, PyObject *obj, PyObject *type)
} }
static PyObject * static PyObject *
wrapper_get(PyWrapperDescrObject *descr, PyObject *obj, PyObject *type) wrapperdescr_get(PyWrapperDescrObject *descr, PyObject *obj, PyObject *type)
{ {
PyObject *res; PyObject *res;
@ -359,7 +359,7 @@ static PyGetSetDef getset_getset[] = {
}; };
static PyObject * static PyObject *
wrapper_get_doc(PyWrapperDescrObject *descr, void *closure) wrapperdescr_get_doc(PyWrapperDescrObject *descr, void *closure)
{ {
if (descr->d_base->doc == NULL) { if (descr->d_base->doc == NULL) {
Py_INCREF(Py_None); Py_INCREF(Py_None);
@ -368,8 +368,8 @@ wrapper_get_doc(PyWrapperDescrObject *descr, void *closure)
return PyString_FromString(descr->d_base->doc); return PyString_FromString(descr->d_base->doc);
} }
static PyGetSetDef wrapper_getset[] = { static PyGetSetDef wrapperdescr_getset[] = {
{"__doc__", (getter)wrapper_get_doc}, {"__doc__", (getter)wrapperdescr_get_doc},
{0} {0}
}; };
@ -551,7 +551,7 @@ PyTypeObject PyWrapperDescr_Type = {
0, /* tp_getattr */ 0, /* tp_getattr */
0, /* tp_setattr */ 0, /* tp_setattr */
0, /* tp_compare */ 0, /* tp_compare */
(reprfunc)wrapper_repr, /* tp_repr */ (reprfunc)wrapperdescr_repr, /* tp_repr */
0, /* tp_as_number */ 0, /* tp_as_number */
0, /* tp_as_sequence */ 0, /* tp_as_sequence */
0, /* tp_as_mapping */ 0, /* tp_as_mapping */
@ -571,10 +571,10 @@ PyTypeObject PyWrapperDescr_Type = {
0, /* tp_iternext */ 0, /* tp_iternext */
0, /* tp_methods */ 0, /* tp_methods */
descr_members, /* tp_members */ descr_members, /* tp_members */
wrapper_getset, /* tp_getset */ wrapperdescr_getset, /* tp_getset */
0, /* tp_base */ 0, /* tp_base */
0, /* tp_dict */ 0, /* tp_dict */
(descrgetfunc)wrapper_get, /* tp_descr_get */ (descrgetfunc)wrapperdescr_get, /* tp_descr_get */
0, /* tp_descr_set */ 0, /* tp_descr_set */
}; };
@ -910,10 +910,42 @@ wrapper_dealloc(wrapperobject *wp)
PyObject_GC_Del(wp); PyObject_GC_Del(wp);
} }
static PyMethodDef wrapper_methods[] = { static int
wrapper_compare(wrapperobject *a, wrapperobject *b)
{
if (a->descr == b->descr) {
if (a->self == b->self)
return 0;
else
return (a->self < b->self) ? -1 : 1;
}
else
return (a->descr < b->descr) ? -1 : 1;
}
static PyObject *
wrapper_repr(wrapperobject *wp)
{
return PyString_FromFormat("<method-wrapper '%s' of %s object at %p>",
wp->descr->d_base->name,
wp->self->ob_type->tp_name,
wp->self);
}
static PyMemberDef wrapper_members[] = {
{"__self__", T_OBJECT, offsetof(wrapperobject, self), READONLY},
{0} {0}
}; };
static PyObject *
wrapper_objclass(wrapperobject *wp)
{
PyObject *c = (PyObject *)wp->descr->d_type;
Py_INCREF(c);
return c;
}
static PyObject * static PyObject *
wrapper_name(wrapperobject *wp) wrapper_name(wrapperobject *wp)
{ {
@ -937,6 +969,7 @@ wrapper_doc(wrapperobject *wp)
} }
static PyGetSetDef wrapper_getsets[] = { static PyGetSetDef wrapper_getsets[] = {
{"__objclass__", (getter)wrapper_objclass},
{"__name__", (getter)wrapper_name}, {"__name__", (getter)wrapper_name},
{"__doc__", (getter)wrapper_doc}, {"__doc__", (getter)wrapper_doc},
{0} {0}
@ -992,8 +1025,8 @@ static PyTypeObject wrappertype = {
0, /* tp_print */ 0, /* tp_print */
0, /* tp_getattr */ 0, /* tp_getattr */
0, /* tp_setattr */ 0, /* tp_setattr */
0, /* tp_compare */ (cmpfunc)wrapper_compare, /* tp_compare */
0, /* tp_repr */ (reprfunc)wrapper_repr, /* tp_repr */
0, /* tp_as_number */ 0, /* tp_as_number */
0, /* tp_as_sequence */ 0, /* tp_as_sequence */
0, /* tp_as_mapping */ 0, /* tp_as_mapping */
@ -1011,8 +1044,8 @@ static PyTypeObject wrappertype = {
0, /* tp_weaklistoffset */ 0, /* tp_weaklistoffset */
0, /* tp_iter */ 0, /* tp_iter */
0, /* tp_iternext */ 0, /* tp_iternext */
wrapper_methods, /* tp_methods */ 0, /* tp_methods */
0, /* tp_members */ wrapper_members, /* tp_members */
wrapper_getsets, /* tp_getset */ wrapper_getsets, /* tp_getset */
0, /* tp_base */ 0, /* tp_base */
0, /* tp_dict */ 0, /* tp_dict */