From c6686b7c7e0a10e7dc472a0256a9823c4d7136f2 Mon Sep 17 00:00:00 2001 From: Armin Rigo Date: Mon, 7 Nov 2005 08:38:00 +0000 Subject: [PATCH] Added proper reflection on instances of , e.g. '[].__add__', to match what the other internal descriptor types provide: '__objclass__' attribute, '__self__' member, and reasonable repr and comparison. Added a test. --- Lib/test/test_descr.py | 13 ++++++++++ Objects/descrobject.c | 59 ++++++++++++++++++++++++++++++++---------- 2 files changed, 59 insertions(+), 13 deletions(-) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 05fd72e4780..f594ca88750 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -3977,6 +3977,18 @@ def test_init(): else: raise TestFailed, "did not test __init__() for None return" +def methodwrapper(): + # 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(): weakref_segfault() # Must be first, somehow @@ -4071,6 +4083,7 @@ def test_main(): filefault() vicious_descriptor_nonsense() test_init() + methodwrapper() if verbose: print "All OK" diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 4aa131378d2..df7435aade2 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -50,7 +50,7 @@ getset_repr(PyGetSetDescrObject *descr) } static PyObject * -wrapper_repr(PyWrapperDescrObject *descr) +wrapperdescr_repr(PyWrapperDescrObject *descr) { return descr_repr((PyDescrObject *)descr, ""); @@ -152,7 +152,7 @@ getset_get(PyGetSetDescrObject *descr, PyObject *obj, PyObject *type) } static PyObject * -wrapper_get(PyWrapperDescrObject *descr, PyObject *obj, PyObject *type) +wrapperdescr_get(PyWrapperDescrObject *descr, PyObject *obj, PyObject *type) { PyObject *res; @@ -359,7 +359,7 @@ static PyGetSetDef getset_getset[] = { }; static PyObject * -wrapper_get_doc(PyWrapperDescrObject *descr, void *closure) +wrapperdescr_get_doc(PyWrapperDescrObject *descr, void *closure) { if (descr->d_base->doc == NULL) { Py_INCREF(Py_None); @@ -368,8 +368,8 @@ wrapper_get_doc(PyWrapperDescrObject *descr, void *closure) return PyString_FromString(descr->d_base->doc); } -static PyGetSetDef wrapper_getset[] = { - {"__doc__", (getter)wrapper_get_doc}, +static PyGetSetDef wrapperdescr_getset[] = { + {"__doc__", (getter)wrapperdescr_get_doc}, {0} }; @@ -551,7 +551,7 @@ PyTypeObject PyWrapperDescr_Type = { 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ - (reprfunc)wrapper_repr, /* tp_repr */ + (reprfunc)wrapperdescr_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ @@ -571,10 +571,10 @@ PyTypeObject PyWrapperDescr_Type = { 0, /* tp_iternext */ 0, /* tp_methods */ descr_members, /* tp_members */ - wrapper_getset, /* tp_getset */ + wrapperdescr_getset, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ - (descrgetfunc)wrapper_get, /* tp_descr_get */ + (descrgetfunc)wrapperdescr_get, /* tp_descr_get */ 0, /* tp_descr_set */ }; @@ -910,10 +910,42 @@ wrapper_dealloc(wrapperobject *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("", + 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} }; +static PyObject * +wrapper_objclass(wrapperobject *wp) +{ + PyObject *c = (PyObject *)wp->descr->d_type; + + Py_INCREF(c); + return c; +} + static PyObject * wrapper_name(wrapperobject *wp) { @@ -937,6 +969,7 @@ wrapper_doc(wrapperobject *wp) } static PyGetSetDef wrapper_getsets[] = { + {"__objclass__", (getter)wrapper_objclass}, {"__name__", (getter)wrapper_name}, {"__doc__", (getter)wrapper_doc}, {0} @@ -992,8 +1025,8 @@ static PyTypeObject wrappertype = { 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ + (cmpfunc)wrapper_compare, /* tp_compare */ + (reprfunc)wrapper_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ @@ -1011,8 +1044,8 @@ static PyTypeObject wrappertype = { 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ - wrapper_methods, /* tp_methods */ - 0, /* tp_members */ + 0, /* tp_methods */ + wrapper_members, /* tp_members */ wrapper_getsets, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */