[Python-checkins] python/dist/src/Objects funcobject.c,2.50.4.2,2.50.4.3

jhylton@users.sourceforge.net jhylton@users.sourceforge.net
Thu, 22 May 2003 11:11:23 -0700


Update of /cvsroot/python/python/dist/src/Objects
In directory sc8-pr-cvs1:/tmp/cvs-serv28591/Objects

Modified Files:
      Tag: release22-maint
	funcobject.c 
Log Message:
Backport fix for SF bug 692776.

Add a tp_new slot to function objects that handles the case of a
function requiring a closure.  Put the function type in the new
module, rather than having a function new.function().  Add tests.


Index: funcobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/funcobject.c,v
retrieving revision 2.50.4.2
retrieving revision 2.50.4.3
diff -C2 -d -r2.50.4.2 -r2.50.4.3
*** funcobject.c	9 May 2003 18:29:21 -0000	2.50.4.2
--- funcobject.c	22 May 2003 18:11:20 -0000	2.50.4.3
***************
*** 267,270 ****
--- 267,372 ----
  };
  
+ static char func_doc[] =
+ "function(code, globals[, name[, argdefs[, closure]]])\n\
+ \n\
+ Create a function object from a code object and a dictionary.\n\
+ The optional name string overrides the name from the code object.\n\
+ The optional argdefs tuple specifies the default argument values.\n\
+ The optional closure tuple supplies the bindings for free variables.";
+ 
+ /* func_new() maintains the following invariants for closures.  The
+    closure must correspond to the free variables of the code object.
+    
+    if len(code.co_freevars) == 0: 
+            closure = NULL
+    else:
+            len(closure) == len(code.co_freevars)
+    for every elt in closure, type(elt) == cell
+ */
+ 
+ static PyObject *
+ func_new(PyTypeObject* type, PyObject* args, PyObject* kw)
+ {
+ 	PyCodeObject *code;
+ 	PyObject *globals;
+ 	PyObject *name = Py_None;
+ 	PyObject *defaults = Py_None;
+ 	PyObject *closure = Py_None;
+ 	PyFunctionObject *newfunc;
+ 	int nfree, nclosure;
+ 	static char *kwlist[] = {"code", "globals", "name",
+ 				 "argdefs", "closure", 0};
+ 
+ 	if (!PyArg_ParseTupleAndKeywords(args, kw, "O!O!|OOO:function",
+ 			      kwlist,
+ 			      &PyCode_Type, &code,
+ 			      &PyDict_Type, &globals,
+ 			      &name, &defaults, &closure))
+ 		return NULL;
+ 	if (name != Py_None && !PyString_Check(name)) {
+ 		PyErr_SetString(PyExc_TypeError,
+ 				"arg 3 (name) must be None or string");
+ 		return NULL;
+ 	}
+ 	if (defaults != Py_None && !PyTuple_Check(defaults)) {
+ 		PyErr_SetString(PyExc_TypeError,
+ 				"arg 4 (defaults) must be None or tuple");
+ 		return NULL;
+ 	}
+ 	nfree = PyTuple_GET_SIZE(code->co_freevars);
+ 	if (!PyTuple_Check(closure)) {
+ 		if (nfree && closure == Py_None) {
+ 			PyErr_SetString(PyExc_TypeError,
+ 					"arg 5 (closure) must be tuple");
+ 			return NULL;
+ 		}
+ 		else if (closure != Py_None) {
+ 			PyErr_SetString(PyExc_TypeError,
+ 				"arg 5 (closure) must be None or tuple");
+ 			return NULL;
+ 		}
+ 	}
+ 
+ 	/* check that the closure is well-formed */
+ 	nclosure = closure == Py_None ? 0 : PyTuple_GET_SIZE(closure);
+ 	if (nfree != nclosure)
+ 		return PyErr_Format(PyExc_ValueError,
+ 				    "%s requires closure of length %d, not %d",
+ 				    PyString_AS_STRING(code->co_name),
+ 				    nfree, nclosure);
+ 	if (nclosure) {
+ 		int i;
+ 		for (i = 0; i < nclosure; i++) {
+ 			PyObject *o = PyTuple_GET_ITEM(closure, i);
+ 			if (!PyCell_Check(o)) {
+ 				return PyErr_Format(PyExc_TypeError,
+ 				    "arg 5 (closure) expected cell, found %s",
+ 						    o->ob_type->tp_name);
+ 			}
+ 		}
+ 	}
+ 	
+ 	newfunc = (PyFunctionObject *)PyFunction_New((PyObject *)code, 
+ 						     globals);
+ 	if (newfunc == NULL)
+ 		return NULL;
+ 	
+ 	if (name != Py_None) {
+ 		Py_INCREF(name);
+ 		Py_DECREF(newfunc->func_name);
+ 		newfunc->func_name = name;
+ 	}
+ 	if (defaults != Py_None) {
+ 		Py_INCREF(defaults);
+ 		newfunc->func_defaults  = defaults;
+ 	}
+ 	if (closure != Py_None) {
+ 		Py_INCREF(closure);
+ 		newfunc->func_closure = closure;
+ 	}
+ 
+ 	return (PyObject *)newfunc;
+ }
+ 
  static void
  func_dealloc(PyFunctionObject *op)
***************
*** 416,420 ****
  	0,					/* tp_as_buffer */
  	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
! 	0,					/* tp_doc */
  	(traverseproc)func_traverse,		/* tp_traverse */
  	0,					/* tp_clear */
--- 518,522 ----
  	0,					/* tp_as_buffer */
  	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
! 	func_doc,				/* tp_doc */
  	(traverseproc)func_traverse,		/* tp_traverse */
  	0,					/* tp_clear */
***************
*** 431,434 ****
--- 533,539 ----
  	0,					/* tp_descr_set */
  	offsetof(PyFunctionObject, func_dict),	/* tp_dictoffset */
+ 	0,					/* tp_init */
+ 	0,					/* tp_alloc */
+ 	func_new,				/* tp_new */
  };