Revision: 406 http://rpy.svn.sourceforge.net/rpy/?rev=406&view=rev Author: lgautier Date: 2008-02-24 11:07:58 -0800 (Sun, 24 Feb 2008)
Log Message: ----------- - Added directory for tests (empty for the moment) - Switched order of arguments for VectorSexp_new - Added module object "globalEnv" - Fixed 'repr' for Sexp_type to give the actual address pointed by an SEXP - Added sanity check and error when calling ClosureSexp_call - Method "get" for EnviromentSexp objects - Subscript method for EnvironmentSexp objects (...but segfaults) Modified Paths: -------------- trunk/sandbox/rpy_nextgen/rinterface/rinterface.c Added Paths: ----------- trunk/sandbox/rpy_nextgen/rinterface/tests/ Modified: trunk/sandbox/rpy_nextgen/rinterface/rinterface.c =================================================================== --- trunk/sandbox/rpy_nextgen/rinterface/rinterface.c 2008-02-23 22:53:23 UTC (rev 405) +++ trunk/sandbox/rpy_nextgen/rinterface/rinterface.c 2008-02-24 19:07:58 UTC (rev 406) @@ -89,7 +89,7 @@ Example of usage:\ import rinterface\ rinterface.initEmbeddedR(\"foo\", \"--verbose\")\ -n = rinterface.SexpVector(rinterface.REALSXP, (100,))\ +n = rinterface.SexpVector((100, ), rinterface.REALSXP)\ hist = rinterface.findVarEmbeddedR(\"hist\")\ rnorm = rinterface.findVarEmbeddedR(\"rnorm\")\ x = rnorm(n)\ @@ -109,8 +109,8 @@ } SexpObject; +static SexpObject* globalEnv; - /* --- Initialize and terminate an embedded R --- */ /* Should having multiple threads of R become possible, * Useful routines deal with can could appear here... @@ -136,6 +136,9 @@ } int status = Rf_initEmbeddedR(n_opt, options); + + globalEnv->sexp = R_GlobalEnv; + PyObject *res = PyInt_FromLong(status); return res; } @@ -227,10 +230,11 @@ Sexp_repr(PyObject *self) { //FIXME: make sure this is making any sense + SEXP sexp = ((SexpObject *)self)->sexp; return PyString_FromFormat("<%s - Python:\%p / R:\%p>", self->ob_type->tp_name, self, - &(((SexpObject *)self)->sexp)); + sexp); } @@ -305,8 +309,8 @@ * Closure-type Sexp. */ -static SexpObject* newSexpObject(SEXP); -static SEXP newSEXP(PyObject *object, int rType); +static SexpObject* newSexpObject(const SEXP sexp); +static SEXP newSEXP(PyObject *object, const int rType); /* Evaluate a SEXP. It must be constructed by hand. It raises a Python exception if an error ocurred in the evaluation */ @@ -380,13 +384,22 @@ int arg_i; SEXP tmp_R; + PyObject *tmp_obj; + int is_SexpObject; for (arg_i=0; arg_i<largs; arg_i++) { //FIXME: assert that all are SexpObjects - tmp_R = ((SexpObject *)PyTuple_GetItem(args, arg_i))->sexp; + tmp_obj = PyTuple_GetItem(args, arg_i); + is_SexpObject = PyObject_TypeCheck(tmp_obj, &Sexp_Type); + if (! is_SexpObject) { + PyErr_Format(PyExc_ValueError, "All parameters must be of type Sexp_Type."); + return NULL; + } + tmp_R = ((SexpObject *)tmp_obj)->sexp; SETCAR(c_R, tmp_R); c_R = CDR(c_R); } + //FIXME: implement named parameters. /* if (!make_kwds(lkwds, kwds, &e)) { */ /* UNPROTECT(1); */ /* return NULL; */ @@ -490,14 +503,13 @@ { int rType = -1; PyObject *seq = 0; - if (!PyArg_ParseTuple(args, "iO:new", - &rType, &seq)) + if (!PyArg_ParseTuple(args, "Oi:new", + &seq, &rType)) return NULL; #ifdef VERBOSE printf("type: %i\n", rType); #endif - SEXP sexp; - sexp = newSEXP(seq, rType); + const SEXP sexp = newSEXP(seq, rType); PyObject *res = (PyObject *)newSexpObject(sexp); return res; } @@ -583,7 +595,7 @@ //FIXME: write more doc PyDoc_STRVAR(VectorSexp_Type_doc, -"An R object that is a vector.\ +"R object that is a vector.\ R vectors start their indexing at one,\ while Python lists or arrays start indexing\ at zero.\ @@ -657,6 +669,11 @@ } const SEXP rho_R = ((SexpObject *)self)->sexp; + + if (rho_R == NULL) { + PyErr_Format(PyExc_LookupError, "Fatal error: NULL environment."); + } + res_R = findVar(install(name), rho_R); @@ -670,29 +687,58 @@ "Find an R object in the environment."); static PyMethodDef EnvironmentSexp_methods[] = { - {"get", (PyCFunction)EnvironmentSexp_findVar, METH_O, + {"get", (PyCFunction)EnvironmentSexp_findVar, METH_VARARGS, EnvironmentSexp_findVar_doc}, {NULL, NULL} /* sentinel */ }; +//FIXME: segfault :/ +static SexpObject* +EnvironmentSexp_subscript(PyObject *self, PyObject *key) +{ + char *name; + SEXP res_R; + + if (!PyString_Check(key)) { + PyErr_Format(PyExc_ValueError, "Keys must be string objects."); + return NULL; + } + + name = PyString_AsString(key); + + SEXP rho_R = ((SexpObject *)self)->sexp; + res_R = findVarInFrame(install(name), rho_R); + + + if (res_R != R_UnboundValue) { + return newSexpObject(res_R); + } + PyErr_Format(PyExc_LookupError, "'%s' not found", name); + return NULL; +} +PyDoc_STRVAR(EnvironmentSexp_subscript_doc, + "Find an R object in the environment.\ + Not all R environment are hash tables, and this may\n\ +influence performances when doing repeated lookups."); + //FIXME: Is this still needed ? static PyMappingMethods EnvironmentSexp_mappignMethods = { 0, /* mp_length */ - 0, /* mp_subscript */ + EnvironmentSexp_subscript, /* mp_subscript */ 0 /* mp_ass_subscript */ }; //FIXME: write more doc - should the environments // be made like mappings at the Python level ? PyDoc_STRVAR(EnvironmentSexp_Type_doc, -"An R object that is an environment.\ - R environments can be seen as similar to Python\ +"R object that is an environment.\ + R environments can be seen as similar to Python\n\ dictionnaries, with the twist that looking for\ - a key can be recursively propagated to the enclosing\ + a key can be recursively propagated to the enclosing\n\ environment whenever the key is not found.\ \n\ - The subsetting operator is made to match Python's\ + The subsetting operator is made to match Python's\n\ behavior, that is the enclosing environments are not\ inspected upon absence of a given key.\ "); @@ -714,7 +760,7 @@ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ + &EnvironmentSexp_mappignMethods, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ 0,//Sexp_str, /*tp_str*/ @@ -748,7 +794,7 @@ //FIXME: write more doc PyDoc_STRVAR(S4Sexp_Type_doc, -"An R object that is an 'S4 object'.\ +"R object that is an 'S4 object'.\ "); static PyTypeObject S4Sexp_Type = { @@ -803,10 +849,10 @@ /* --- Create a SEXP object --- */ static SexpObject* -newSexpObject(SEXP sexp) +newSexpObject(const SEXP sexp) { SexpObject *object; - SEXP env_R; + SEXP sexp_ok, env_R; //FIXME: let the possibility to manipulate un-evaluated promises ? if (TYPEOF(sexp) == PROMSXP) { @@ -814,13 +860,16 @@ printf("evaluating promise..."); #endif env_R = PRENV(sexp); - sexp = eval(sexp, env_R); + sexp_ok = eval(sexp, env_R); #ifdef VERBOSE printf("done.\n"); #endif + } + else { + sexp_ok = sexp; } - switch (TYPEOF(sexp)) { + switch (TYPEOF(sexp_ok)) { case CLOSXP: object = (SexpObject *)_PyObject_New(&ClosureSexp_Type); break; @@ -851,9 +900,9 @@ } if (!object) PyErr_NoMemory(); - object->sexp = sexp; + object->sexp = sexp_ok; if (sexp) - R_PreserveObject(sexp); + R_PreserveObject(sexp_ok); return object; } @@ -862,11 +911,11 @@ { SEXP sexp; PyObject *seq_object, *item; - seq_object = PySequence_Fast(object, "Cannot create" - " R object from non-sequence Python object."); - if (! seq_object) + seq_object = PySequence_Fast(object, "Cannot create R object from non-sequence Python object."); + //FIXME: Isn't the call above supposed to fire an Exception ? + if (! seq_object) { return NULL; - + } const Py_ssize_t length = PySequence_Fast_GET_SIZE(seq_object); //FIXME: PROTECT THIS ? sexp = allocVector(rType, length); @@ -952,16 +1001,6 @@ //(PyTypeObject *)ClosureSexp_Type.tp_new = 0;//ClosureSexp_methods; -static PyObject* -Sexp_GlobalEnv(PyTypeObject* type) -{ - SexpObject* res = (SexpObject*)type->tp_alloc(type, 0); - res->sexp = R_GlobalEnv; - return (PyObject*)res; -} - - - /* --- Find a variable in an environment --- */ @@ -983,7 +1022,7 @@ if (res != R_UnboundValue) { return newSexpObject(res); } - PyErr_Format(ErrorObject, "'%s' not found", name); + PyErr_Format(PyExc_LookupError, "'%s' not found", name); return NULL; } PyDoc_STRVAR(EmbeddedR_findVar_doc, @@ -1013,6 +1052,7 @@ #define ADD_INT_CONSTANT(module, name) PyModule_AddIntConstant(module, #name, name) + PyMODINIT_FUNC initrinterface(void) { @@ -1031,10 +1071,11 @@ if (PyType_Ready(&S4Sexp_Type) < 0) return; - PyObject *m; + PyObject *m, *d; m = Py_InitModule3("rinterface", EmbeddedR_methods, module_doc); if (m == NULL) return; + d = PyModule_GetDict(m); PyModule_AddObject(m, "Sexp", (PyObject *)&Sexp_Type); PyModule_AddObject(m, "SexpClosure", (PyObject *)&ClosureSexp_Type); @@ -1051,6 +1092,12 @@ Py_INCREF(ErrorObject); PyModule_AddObject(m, "RobjectNotFound", ErrorObject); + globalEnv = (SexpObject*)_PyObject_New(&EnvironmentSexp_Type); + globalEnv->sexp = NULL; + if (PyDict_SetItemString(d, "globalEnv", (PyObject*)globalEnv) < 0) + return; + //FIXME: DECREF ? + //Py_DECREF(globalEnv); /* Add some symbolic constants to the module */ ADD_INT_CONSTANT(m, NILSXP); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ _______________________________________________ rpy-list mailing list rpy-list@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/rpy-list