[Python-checkins] CVS: python/dist/src/Objects classobject.c,2.113,2.114 funcobject.c,2.30,2.31
Barry Warsaw
bwarsaw@users.sourceforge.net
Mon, 15 Jan 2001 12:40:21 -0800
Update of /cvsroot/python/python/dist/src/Objects
In directory usw-pr-cvs1:/tmp/cvs-serv17750/Objects
Modified Files:
classobject.c funcobject.c
Log Message:
Committing PEP 232, function attribute feature, approved by Guido.
Closes SF patch #103123.
funcobject.h:
PyFunctionObject: add the func_dict slot.
funcobject.c:
PyFunction_New(): Initialize the func_dict slot to NULL.
func_getattr(): Rename to func_getattro() and change the
signature. It's more efficient to use attro methods and dig the C
string out than it is to re-convert a C string to a PyString.
Also, add support for getting the __dict__ (a.k.a. func_dict)
attribute, and for getting an arbitrary function attribute.
func_setattr(): Rename to func_setattro() and change the signature
for the same reason. Also add support for setting __dict__
(a.k.a. func_dict) and any arbitrary function attribute.
func_dealloc(): Be sure to DECREF the func_dict slot.
func_traverse(): Be sure to traverse func_dict too.
PyFunction_Type: make the necessary func_?etattro() changes.
classobject.c:
instancemethod_memberlist: Add __dict__
instancemethod_setattro(): New method to set arbitrary attributes
on methods (really the underlying im_func). Raise TypeError when
the instance is bound or when you're trying to set one of the
reserved im_* attributes.
instancemethod_getattr(): Renamed to instancemethod_getattro()
since that's what it really is. Also, added support fo getting
arbitrary attributes through the im_func.
PyMethod_Type: Do the ?etattr{,o} dance.
Index: classobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/classobject.c,v
retrieving revision 2.113
retrieving revision 2.114
diff -C2 -r2.113 -r2.114
*** classobject.c 2001/01/04 01:43:46 2.113
--- classobject.c 2001/01/15 20:40:19 2.114
***************
*** 1694,1703 ****
{"__doc__", T_INT, 0},
{"__name__", T_INT, 0},
{NULL} /* Sentinel */
};
static PyObject *
! instancemethod_getattr(register PyMethodObject *im, PyObject *name)
{
char *sname = PyString_AsString(name);
if (sname[0] == '_') {
--- 1694,1729 ----
{"__doc__", T_INT, 0},
{"__name__", T_INT, 0},
+ {"__dict__", T_OBJECT, 0},
{NULL} /* Sentinel */
};
+ static int
+ instancemethod_setattro(register PyMethodObject *im, PyObject *name,
+ PyObject *v)
+ {
+ char *sname = PyString_AsString(name);
+
+ if (PyEval_GetRestricted() ||
+ strcmp(sname, "im_func") == 0 ||
+ strcmp(sname, "im_self") == 0 ||
+ strcmp(sname, "im_class") == 0)
+ {
+ PyErr_Format(PyExc_TypeError, "read-only attribute: %s",
+ sname);
+ return -1;
+ }
+ if (im->im_self != NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "cannot set attributes through bound methods");
+ return -1;
+ }
+ return PyObject_SetAttr(im->im_func, name, v);
+ }
+
+
static PyObject *
! instancemethod_getattro(register PyMethodObject *im, PyObject *name)
{
+ PyObject *rtn;
char *sname = PyString_AsString(name);
if (sname[0] == '_') {
***************
*** 1712,1717 ****
"instance-method attributes not accessible in restricted mode");
return NULL;
}
! return PyMember_Get((char *)im, instancemethod_memberlist, sname);
}
--- 1738,1751 ----
"instance-method attributes not accessible in restricted mode");
return NULL;
+ }
+ if (sname[0] == '_' && strcmp(sname, "__dict__") == 0)
+ return PyObject_GetAttr(im->im_func, name);
+
+ rtn = PyMember_Get((char *)im, instancemethod_memberlist, sname);
+ if (rtn == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
+ PyErr_Clear();
+ rtn = PyObject_GetAttr(im->im_func, name);
}
! return rtn;
}
***************
*** 1833,1838 ****
0, /*tp_call*/
0, /*tp_str*/
! (getattrofunc)instancemethod_getattr, /*tp_getattro*/
! 0, /*tp_setattro*/
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /*tp_flags*/
--- 1867,1872 ----
0, /*tp_call*/
0, /*tp_str*/
! (getattrofunc)instancemethod_getattro, /*tp_getattro*/
! (setattrofunc)instancemethod_setattro, /*tp_setattro*/
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /*tp_flags*/
Index: funcobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/funcobject.c,v
retrieving revision 2.30
retrieving revision 2.31
diff -C2 -r2.30 -r2.31
*** funcobject.c 2000/09/01 23:29:27 2.30
--- funcobject.c 2001/01/15 20:40:19 2.31
***************
*** 31,35 ****
--- 31,38 ----
Py_INCREF(doc);
op->func_doc = doc;
+ op->func_dict = NULL;
}
+ else
+ return NULL;
PyObject_GC_Init(op);
return (PyObject *)op;
***************
*** 103,119 ****
static PyObject *
! func_getattr(PyFunctionObject *op, char *name)
{
! if (name[0] != '_' && PyEval_GetRestricted()) {
PyErr_SetString(PyExc_RuntimeError,
"function attributes not accessible in restricted mode");
return NULL;
}
! return PyMember_Get((char *)op, func_memberlist, name);
}
static int
! func_setattr(PyFunctionObject *op, char *name, PyObject *value)
{
if (PyEval_GetRestricted()) {
PyErr_SetString(PyExc_RuntimeError,
--- 106,151 ----
static PyObject *
! func_getattro(PyFunctionObject *op, PyObject *name)
{
! PyObject *rtn;
! char *sname = PyString_AsString(name);
!
! if (sname[0] != '_' && PyEval_GetRestricted()) {
PyErr_SetString(PyExc_RuntimeError,
"function attributes not accessible in restricted mode");
return NULL;
+ }
+
+ if (!strcmp(sname, "__dict__") || !strcmp(sname, "func_dict")) {
+ if (op->func_dict == NULL)
+ rtn = Py_None;
+ else
+ rtn = op->func_dict;
+
+ Py_INCREF(rtn);
+ return rtn;
+ }
+
+ /* no API for PyMember_HasAttr() */
+ rtn = PyMember_Get((char *)op, func_memberlist, sname);
+
+ if (rtn == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
+ PyErr_Clear();
+ if (op->func_dict != NULL) {
+ rtn = PyDict_GetItem(op->func_dict, name);
+ Py_XINCREF(rtn);
+ }
+ if (rtn == NULL)
+ PyErr_SetObject(PyExc_AttributeError, name);
}
! return rtn;
}
static int
! func_setattro(PyFunctionObject *op, PyObject *name, PyObject *value)
{
+ int rtn;
+ char *sname = PyString_AsString(name);
+
if (PyEval_GetRestricted()) {
PyErr_SetString(PyExc_RuntimeError,
***************
*** 121,125 ****
return -1;
}
! if (strcmp(name, "func_code") == 0) {
if (value == NULL || !PyCode_Check(value)) {
PyErr_SetString(
--- 153,157 ----
return -1;
}
! if (strcmp(sname, "func_code") == 0) {
if (value == NULL || !PyCode_Check(value)) {
PyErr_SetString(
***************
*** 129,133 ****
}
}
! else if (strcmp(name, "func_defaults") == 0) {
if (value != Py_None && !PyTuple_Check(value)) {
PyErr_SetString(
--- 161,165 ----
}
}
! else if (strcmp(sname, "func_defaults") == 0) {
if (value != Py_None && !PyTuple_Check(value)) {
PyErr_SetString(
***************
*** 138,143 ****
if (value == Py_None)
value = NULL;
}
! return PyMember_Set((char *)op, func_memberlist, name, value);
}
--- 170,201 ----
if (value == Py_None)
value = NULL;
+ }
+ else if (!strcmp(sname, "func_dict") || !strcmp(sname, "__dict__")) {
+ if (value != Py_None && !PyDict_Check(value)) {
+ PyErr_SetString(
+ PyExc_TypeError,
+ "func_dict must be set to a dict object");
+ return -1;
+ }
+ if (value == Py_None)
+ value = NULL;
+
+ Py_XDECREF(op->func_dict);
+ Py_XINCREF(value);
+ op->func_dict = value;
+ return 0;
+ }
+
+ rtn = PyMember_Set((char *)op, func_memberlist, sname, value);
+ if (rtn < 0 && PyErr_ExceptionMatches(PyExc_AttributeError)) {
+ PyErr_Clear();
+ if (op->func_dict == NULL) {
+ op->func_dict = PyDict_New();
+ if (op->func_dict == NULL)
+ return -1;
+ }
+ rtn = PyDict_SetItem(op->func_dict, name, value);
}
! return rtn;
}
***************
*** 151,154 ****
--- 209,213 ----
Py_XDECREF(op->func_defaults);
Py_XDECREF(op->func_doc);
+ Py_XDECREF(op->func_dict);
op = (PyFunctionObject *) PyObject_AS_GC(op);
PyObject_DEL(op);
***************
*** 228,231 ****
--- 287,295 ----
return err;
}
+ if (f->func_dict) {
+ err = visit(f->func_dict, arg);
+ if (err)
+ return err;
+ }
return 0;
}
***************
*** 239,244 ****
(destructor)func_dealloc, /*tp_dealloc*/
0, /*tp_print*/
! (getattrfunc)func_getattr, /*tp_getattr*/
! (setattrfunc)func_setattr, /*tp_setattr*/
(cmpfunc)func_compare, /*tp_compare*/
(reprfunc)func_repr, /*tp_repr*/
--- 303,308 ----
(destructor)func_dealloc, /*tp_dealloc*/
0, /*tp_print*/
! 0, /*tp_getattr*/
! 0, /*tp_setattr*/
(cmpfunc)func_compare, /*tp_compare*/
(reprfunc)func_repr, /*tp_repr*/
***************
*** 249,254 ****
0, /*tp_call*/
0, /*tp_str*/
! 0, /*tp_getattro*/
! 0, /*tp_setattro*/
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /*tp_flags*/
--- 313,318 ----
0, /*tp_call*/
0, /*tp_str*/
! (getattrofunc)func_getattro, /*tp_getattro*/
! (setattrofunc)func_setattro, /*tp_setattro*/
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /*tp_flags*/