1283 lines · 31.1 KB · C
RawDownload
/* Descriptors -- a new, flexible way to describe attributes */ #include "Python.h"#include "structmember.h" /* Why is this not included in Python.h? */ static voiddescr_dealloc(PyDescrObject *descr){	_PyObject_GC_UNTRACK(descr);	Py_XDECREF(descr->d_type);	Py_XDECREF(descr->d_name);	PyObject_GC_Del(descr);} static char *descr_name(PyDescrObject *descr){	if (descr->d_name != NULL && PyString_Check(descr->d_name))		return PyString_AS_STRING(descr->d_name);	else		return "?";} static PyObject *descr_repr(PyDescrObject *descr, char *format){	return PyString_FromFormat(format, descr_name(descr),				   descr->d_type->tp_name);} static PyObject *method_repr(PyMethodDescrObject *descr){	return descr_repr((PyDescrObject *)descr, 			  "<method '%s' of '%s' objects>");} static PyObject *member_repr(PyMemberDescrObject *descr){	return descr_repr((PyDescrObject *)descr, 			  "<member '%s' of '%s' objects>");} static PyObject *getset_repr(PyGetSetDescrObject *descr){	return descr_repr((PyDescrObject *)descr, 			  "<attribute '%s' of '%s' objects>");} static PyObject *wrapperdescr_repr(PyWrapperDescrObject *descr){	return descr_repr((PyDescrObject *)descr, 			  "<slot wrapper '%s' of '%s' objects>");} static intdescr_check(PyDescrObject *descr, PyObject *obj, PyObject **pres){	if (obj == NULL) {		Py_INCREF(descr);		*pres = (PyObject *)descr;		return 1;	}	if (!PyObject_TypeCheck(obj, descr->d_type)) {		PyErr_Format(PyExc_TypeError,			     "descriptor '%s' for '%s' objects "			     "doesn't apply to '%s' object",			     descr_name((PyDescrObject *)descr),			     descr->d_type->tp_name,			     obj->ob_type->tp_name);		*pres = NULL;		return 1;	}	return 0;} static PyObject *classmethod_get(PyMethodDescrObject *descr, PyObject *obj, 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, PyObject *type){	PyObject *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, PyObject *type){	PyObject *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, PyObject *type){	PyObject *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);	PyErr_Format(PyExc_AttributeError,		     "attribute '%.300s' of '%.100s' objects is not readable",		     descr_name((PyDescrObject *)descr),		     descr->d_type->tp_name);	return NULL;} static PyObject *wrapperdescr_get(PyWrapperDescrObject *descr, PyObject *obj, PyObject *type){	PyObject *res; 	if (descr_check((PyDescrObject *)descr, obj, &res))		return res;	return PyWrapper_New((PyObject *)descr, obj);} static intdescr_setcheck(PyDescrObject *descr, PyObject *obj, PyObject *value,	       int *pres){	assert(obj != NULL);	if (!PyObject_IsInstance(obj, (PyObject *)(descr->d_type))) {		PyErr_Format(PyExc_TypeError,			     "descriptor '%.200s' for '%.100s' objects "			     "doesn't apply to '%.100s' object",			     descr_name(descr),			     descr->d_type->tp_name,			     obj->ob_type->tp_name);		*pres = -1;		return 1;	}	return 0;} static intmember_set(PyMemberDescrObject *descr, PyObject *obj, PyObject *value){	int res; 	if (descr_setcheck((PyDescrObject *)descr, obj, value, &res))		return res;	return PyMember_SetOne((char *)obj, descr->d_member, value);} static intgetset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value){	int res; 	if (descr_setcheck((PyDescrObject *)descr, obj, value, &res))		return res;	if (descr->d_getset->set != NULL)		return descr->d_getset->set(obj, value,					    descr->d_getset->closure);	PyErr_Format(PyExc_AttributeError,		     "attribute '%.300s' of '%.100s' objects is not writable",		     descr_name((PyDescrObject *)descr),		     descr->d_type->tp_name);	return -1;} static PyObject *methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds){	Py_ssize_t argc;	PyObject *self, *func, *result; 	/* 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 '%.300s' of '%.100s' "			     "object needs an argument",			     descr_name((PyDescrObject *)descr),			     descr->d_type->tp_name);		return NULL;	}	self = PyTuple_GET_ITEM(args, 0);	if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) {		PyErr_Format(PyExc_TypeError,			     "descriptor '%.200s' "			     "requires a '%.100s' object "			     "but received a '%.100s'",			     descr_name((PyDescrObject *)descr),			     descr->d_type->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(args);	Py_DECREF(func);	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){	Py_ssize_t argc;	PyObject *self, *func, *result; 	/* 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 '%.300s' of '%.100s' "			     "object needs an argument",			     descr_name((PyDescrObject *)descr),			     descr->d_type->tp_name);		return NULL;	}	self = PyTuple_GET_ITEM(args, 0);	if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) {		PyErr_Format(PyExc_TypeError,			     "descriptor '%.200s' "			     "requires a '%.100s' object "			     "but received a '%.100s'",			     descr_name((PyDescrObject *)descr),			     descr->d_type->tp_name,			     self->ob_type->tp_name);		return NULL;	} 	func = PyWrapper_New((PyObject *)descr, 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(args);	Py_DECREF(func);	return result;} static PyObject *method_get_doc(PyMethodDescrObject *descr, void *closure){	if (descr->d_method->ml_doc == NULL) {		Py_INCREF(Py_None);		return Py_None;	}	return PyString_FromString(descr->d_method->ml_doc);} static PyMemberDef descr_members[] = {	{"__objclass__", T_OBJECT, offsetof(PyDescrObject, d_type), READONLY},	{"__name__", T_OBJECT, offsetof(PyDescrObject, d_name), READONLY},	{0}}; static PyGetSetDef method_getset[] = {	{"__doc__", (getter)method_get_doc},	{0}}; static PyObject *member_get_doc(PyMemberDescrObject *descr, void *closure){	if (descr->d_member->doc == NULL) {		Py_INCREF(Py_None);		return Py_None;	}	return PyString_FromString(descr->d_member->doc);} static PyGetSetDef member_getset[] = {	{"__doc__", (getter)member_get_doc},	{0}}; static PyObject *getset_get_doc(PyGetSetDescrObject *descr, void *closure){	if (descr->d_getset->doc == NULL) {		Py_INCREF(Py_None);		return Py_None;	}	return PyString_FromString(descr->d_getset->doc);} static PyGetSetDef getset_getset[] = {	{"__doc__", (getter)getset_get_doc},	{0}}; static PyObject *wrapperdescr_get_doc(PyWrapperDescrObject *descr, void *closure){	if (descr->d_base->doc == NULL) {		Py_INCREF(Py_None);		return Py_None;	}	return PyString_FromString(descr->d_base->doc);} static PyGetSetDef wrapperdescr_getset[] = {	{"__doc__", (getter)wrapperdescr_get_doc},	{0}}; static intdescr_traverse(PyObject *self, visitproc visit, void *arg){	PyDescrObject *descr = (PyDescrObject *)self;	Py_VISIT(descr->d_type);	return 0;} static PyTypeObject PyMethodDescr_Type = {	PyObject_HEAD_INIT(&PyType_Type)	0,	"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)methoddescr_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)method_get,		/* tp_descr_get */	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,	"classmethod_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,	"member_descriptor",	sizeof(PyMemberDescrObject),	0,	(destructor)descr_dealloc,		/* tp_dealloc */	0,					/* tp_print */	0,					/* tp_getattr */	0,					/* tp_setattr */	0,					/* tp_compare */	(reprfunc)member_repr,			/* tp_repr */	0,					/* tp_as_number */	0,					/* tp_as_sequence */	0,					/* tp_as_mapping */	0,					/* tp_hash */	0,					/* 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 */	member_getset,				/* tp_getset */	0,					/* tp_base */	0,					/* tp_dict */	(descrgetfunc)member_get,		/* tp_descr_get */	(descrsetfunc)member_set,		/* tp_descr_set */}; static PyTypeObject PyGetSetDescr_Type = {	PyObject_HEAD_INIT(&PyType_Type)

Lines 1–500 of 1283.