[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*/