Revision: 501 http://rpy.svn.sourceforge.net/rpy/?rev=501&view=rev Author: lgautier Date: 2008-04-23 13:57:10 -0700 (Wed, 23 Apr 2008)
Log Message: ----------- - Rewrote the __new__ and __init__ methods at the C level (making chained instanciation possible) - Allow SEXP objects shared among several PyObjects (reference count) - All this breaks rpy2.robjects in weird ways (__init__ and inheritance seem to be involved) - More tests Modified Paths: -------------- branches/rpy_nextgen/rpy/rinterface/rinterface.c branches/rpy_nextgen/rpy/rinterface/rinterface.h branches/rpy_nextgen/rpy/rinterface/tests/test_Sexp.py branches/rpy_nextgen/rpy/rinterface/tests/test_SexpEnvironment.py branches/rpy_nextgen/rpy/rinterface/tests/test_SexpVector.py branches/rpy_nextgen/rpy/robjects/__init__.py branches/rpy_nextgen/rpy/robjects/tests/testRobjects.py Added Paths: ----------- branches/rpy_nextgen/rpy/robjects/tests/testRFunction.py branches/rpy_nextgen/rpy/robjects/tests/testRVector.py Modified: branches/rpy_nextgen/rpy/rinterface/rinterface.c =================================================================== --- branches/rpy_nextgen/rpy/rinterface/rinterface.c 2008-04-20 09:48:38 UTC (rev 500) +++ branches/rpy_nextgen/rpy/rinterface/rinterface.c 2008-04-23 20:57:10 UTC (rev 501) @@ -109,11 +109,11 @@ "); -static SexpObject* globalEnv; -static SexpObject* baseNameSpaceEnv; +static PySexpObject* globalEnv; +static PySexpObject* baseNameSpaceEnv; /* early definition of functions */ -static SexpObject* newSexpObject(const SEXP sexp); +static PySexpObject* newPySexpObject(const SEXP sexp); static SEXP newSEXP(PyObject *object, const int rType); @@ -147,9 +147,9 @@ embeddedR_isInitialized = PyBool_FromLong((long)1); - globalEnv->sexp = R_GlobalEnv; + RPY_GETSEXP(globalEnv) = R_GlobalEnv; - baseNameSpaceEnv->sexp = R_BaseNamespace; + RPY_GETSEXP(baseNameSpaceEnv) = R_BaseNamespace; PyObject *res = PyInt_FromLong(status); @@ -183,8 +183,8 @@ /* */ Rf_endEmbeddedR((int)fatal); - globalEnv->sexp = R_EmptyEnv; - baseNameSpaceEnv->sexp = R_EmptyEnv; + RPY_GETSEXP(globalEnv) = R_EmptyEnv; + RPY_GETSEXP(baseNameSpaceEnv) = R_EmptyEnv; Py_RETURN_NONE; } @@ -242,27 +242,30 @@ * Access to R objects through Python objects */ -/* static PyObject* */ -/* Sexp_new(PyTypeObject *type, PyObject *args) */ -/* { */ -/* PyObject object, res; */ -/* if (!PyArg_ParseTuple(args, "O:new", */ -/* &object)) */ -/* PyErr_Format(PyExc_ValueError, "Can only instanciate from SexpObject"); */ -/* return NULL; */ -/* res = (SexpObject *)_PyObject_New(&Sexp_Type); */ -/* if (!res) */ -/* PyErr_NoMemory(); */ -/* res->sexp = sexp; */ -/* return res; */ -/* } */ static void -Sexp_dealloc(SexpObject *self) +Sexp_dealloc(PySexpObject *self) { - if (self->sexp) - R_ReleaseObject(self->sexp); - //self->ob_type->tp_free((PyObject*)self); + RPY_DECREF(self); + +#ifdef RPY_VERBOSE + printf("%p: sexp count is %i\n", self, RPY_GETCOUNT(self)); +#endif + + if ((RPY_GETCOUNT(self) == 0) && RPY_GETSEXP(self)) { +#ifdef RPY_VERBOSE + printf("freeing SEXP resources..."); +#endif + + if (RPY_GETSEXP(self) != R_NilValue) { + R_ReleaseObject(RPY_GETSEXP(self)); + } + free(self->sObj); + ////self->ob_type->tp_free((PyObject*)self); +#ifdef RPY_VERBOSE + printf("done.\n"); +#endif + } PyObject_Del(self); } @@ -271,11 +274,11 @@ Sexp_repr(PyObject *self) { //FIXME: make sure this is making any sense - SEXP sexp = ((SexpObject *)self)->sexp; + SEXP sexp = RPY_GETSEXP((PySexpObject *)self); if (! sexp) { - PyErr_Format(PyExc_ValueError, "NULL SEXP."); - return NULL;; - } + PyErr_Format(PyExc_ValueError, "NULL SEXP."); + return NULL; + } return PyString_FromFormat("<%s - Python:\%p / R:\%p>", self->ob_type->tp_name, self, @@ -286,7 +289,7 @@ static PyObject* Sexp_typeof(PyObject *self) { - SEXP sexp =((SexpObject*)self)->sexp; + SEXP sexp = RPY_GETSEXP(((PySexpObject*)self)); if (! sexp) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return NULL;; @@ -301,7 +304,7 @@ static PyObject* Sexp_do_slot(PyObject *self, PyObject *name) { - SEXP sexp =((SexpObject*)self)->sexp; + SEXP sexp = RPY_GETSEXP(((PySexpObject*)self)); if (! sexp) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return NULL;; @@ -318,7 +321,7 @@ } SEXP res_R = GET_SLOT(sexp, install(name_str)); - PyObject *res = (PyObject *)newSexpObject(res_R); + PyObject *res = (PyObject *)newPySexpObject(res_R); return res; } PyDoc_STRVAR(Sexp_do_slot_doc, @@ -337,6 +340,13 @@ }; + +static PyObject* +Sexp_new(PyTypeObject *type, PyObject *args, PyObject *kwds); + +static int +Sexp_init(PySexpObject *self, PyObject *args, PyObject *kwds); + /* * Generic Sexp_Type. It represents SEXP objects at large. */ @@ -346,7 +356,7 @@ PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "rinterface.Sexp", /*tp_name*/ - sizeof(SexpObject), /*tp_basicsize*/ + sizeof(PySexpObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)Sexp_dealloc, /*tp_dealloc*/ @@ -380,14 +390,112 @@ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ - 0, /*tp_init*/ + (initproc)Sexp_init, /*tp_init*/ 0, /*tp_alloc*/ - 0, //Sexp_new, /*tp_new*/ + Sexp_new, /*tp_new*/ 0, /*tp_free*/ 0, /*tp_is_gc*/ }; +/* static PyObject* */ +/* Sexp_new(PyTypeObject *type, PyObject *args) */ +/* { */ +/* PyObject object, res; */ +/* if (!PyArg_ParseTuple(args, "O:new", */ +/* &object)) */ +/* PyErr_Format(PyExc_ValueError, "Can only instanciate from PySexpObject"); */ +/* return NULL; */ +/* res = (PySexpObject *)_PyObject_New(&Sexp_Type); */ +/* if (!res) */ +/* PyErr_NoMemory(); */ +/* res->sexp = sexp; */ +/* return res; */ +/* } */ +static PyObject* +Sexp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + + PySexpObject *self; + #ifdef RPY_VERBOSE + printf("new object @ %p...", self); + #endif + + //self = (PySexpObject *)_PyObject_New(&type); + self = (PySexpObject *)type->tp_alloc(type, 0); + if (! self) + PyErr_NoMemory(); + + self->sObj = (SexpObject *)calloc(1, sizeof(SexpObject)); + if (! self->sObj) + PyErr_NoMemory(); + + RPY_GETCOUNT(self) = 1; + RPY_GETSEXP(self) = R_NilValue; + + #ifdef RPY_VERBOSE + printf("done.\n"); + #endif + + return (PyObject *)self; + +} + + +static int +Sexp_init(PySexpObject *self, PyObject *args, PyObject *kwds) +{ +#ifdef RPY_VERBOSE + printf("%p: Sexp initializing...", self); +#endif + + PyObject *sourceObject; + PyObject *copy = Py_True; + Py_INCREF(Py_True); + static char *kwlist[] = {"sexp", "copy", NULL}; + //FIXME: handle the copy argument + + if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|O!", + kwlist, + &sourceObject, + &PyBool_Type, ©)) { + Py_DECREF(Py_True); + return -1; + } + + if (! PyObject_IsInstance(sourceObject, + (PyObject*)&Sexp_Type)) { + PyErr_Format(PyExc_ValueError, + "Can only instanciate from Sexp objects."); + return -1; + } + + if (PyObject_IsTrue(copy)) { + SEXP oldSexp; + oldSexp = RPY_GETSEXP((PySexpObject *)sourceObject); + RPY_GETSEXP(self) = oldSexp; + RPY_INCREF(self); +#ifdef RPY_VERBOSE + printf("%p: sexp count is increased to %i.\n", self, RPY_GETCOUNT(self)); +#endif + + } else { + PyErr_Format(PyExc_ValueError, "Cast without copy is not yet implemented."); + Py_DECREF(Py_True); + return -1; + } + Py_DECREF(Py_True); + +#ifdef RPY_VERBOSE + printf("done\n."); +#endif + + + return 0; +} + + + /* * Closure-type Sexp. */ @@ -463,7 +571,7 @@ /* A SEXP with the function to call and the arguments and keywords. */ PROTECT(c_R = call_R = allocList(largs+lkwds+1)); SET_TYPEOF(c_R, LANGSXP); - fun_R = ((SexpObject *)self)->sexp; + fun_R = RPY_GETSEXP((PySexpObject *)self); if (! fun_R) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); goto fail; @@ -473,17 +581,17 @@ int arg_i; PyObject *tmp_obj; - int is_SexpObject; + int is_PySexpObject; for (arg_i=0; arg_i<largs; arg_i++) { tmp_obj = PyTuple_GetItem(args, arg_i); - is_SexpObject = PyObject_TypeCheck(tmp_obj, &Sexp_Type); - if (! is_SexpObject) { + is_PySexpObject = PyObject_TypeCheck(tmp_obj, &Sexp_Type); + if (! is_PySexpObject) { PyErr_Format(PyExc_ValueError, "All parameters must be of type Sexp_Type."); Py_DECREF(tmp_obj); goto fail; } - tmp_R = ((SexpObject *)tmp_obj)->sexp; + tmp_R = RPY_GETSEXP((PySexpObject *)tmp_obj); if (! tmp_R) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); Py_DECREF(tmp_obj); @@ -516,8 +624,8 @@ goto fail; } argValue = PyTuple_GetItem(tmp_obj, 1); - is_SexpObject = PyObject_TypeCheck(argValue, &Sexp_Type); - if (! is_SexpObject) { + is_PySexpObject = PyObject_TypeCheck(argValue, &Sexp_Type); + if (! is_PySexpObject) { PyErr_Format(PyExc_ValueError, "All named parameters must be of type Sexp_Type."); Py_DECREF(tmp_obj); @@ -525,7 +633,7 @@ goto fail; } Py_DECREF(tmp_obj); - tmp_R = ((SexpObject *)argValue)->sexp; + tmp_R = RPY_GETSEXP((PySexpObject *)argValue); if (! tmp_R) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); Py_DECREF(tmp_obj); @@ -555,7 +663,7 @@ extern void Rf_PrintWarnings(void); Rf_PrintWarnings(); /* show any warning messages */ - PyObject *res = (PyObject *)newSexpObject(res_R); + PyObject *res = (PyObject *)newPySexpObject(res_R); return res; fail: @@ -568,17 +676,17 @@ -static SexpObject* +static PySexpObject* Sexp_closureEnv(PyObject *self) { SEXP closureEnv, sexp; - sexp = ((SexpObject*)self)->sexp; + sexp = RPY_GETSEXP((PySexpObject*)self); if (! sexp) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return NULL; } closureEnv = CLOENV(sexp); - return newSexpObject(closureEnv); + return newPySexpObject(closureEnv); } PyDoc_STRVAR(Sexp_closureEnv_doc, "\n\ @@ -601,13 +709,17 @@ The closure can be accessed with the method 'closureEnv'.\ "); +static int +ClosureSexp_init(PySexpObject *self, PyObject *args, PyObject *kwds); + + static PyTypeObject ClosureSexp_Type = { /* The ob_type field must be initialized in the module init function * to be portable to Windows without using C++. */ PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "rinterface.SexpClosure", /*tp_name*/ - sizeof(SexpObject), /*tp_basicsize*/ + sizeof(PySexpObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ 0, /*tp_dealloc*/ @@ -641,34 +753,51 @@ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ - 0, /*tp_init*/ + ClosureSexp_init, /*tp_init*/ 0, /*tp_alloc*/ 0,//Sexp_new, /*tp_new*/ 0, /*tp_free*/ 0 /*tp_is_gc*/ }; -static PyObject* -VectorSexp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) + +static int +ClosureSexp_init(PySexpObject *self, PyObject *args, PyObject *kwds) { - int rType = -1; - PyObject *seq = 0; - if (!PyArg_ParseTuple(args, "Oi:new", - &seq, &rType)) - return NULL; - const SEXP sexp = newSEXP(seq, rType); - if (! sexp) - return NULL; - PyObject *res = (PyObject *)newSexpObject(sexp); - return res; + PyObject *object; + int sexptype = -1; + PyObject *copy; + static char *kwlist[] = {"sexpclos", "copy", NULL}; + //FIXME: handle the copy argument + if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|O!", + kwlist, + &object, + &PyBool_Type, ©)) { + return -1; + } + if (PyObject_IsInstance(object, + (PyObject*)&ClosureSexp_Type)) { + //call parent's constructor + if (Sexp_init(self, args, kwds) == -1) { + PyErr_Format(PyExc_RuntimeError, "Error initializing instance."); + return -1; + } + } else { + PyErr_Format(PyExc_ValueError, "Cannot instantiate from this type."); + return -1; + } + return 0; } + + + /* len(x) */ static Py_ssize_t VectorSexp_len(PyObject *object) { Py_ssize_t len; //FIXME: sanity checks. - SEXP sexp = ((SexpObject *)object)->sexp; + SEXP sexp = RPY_GETSEXP((PySexpObject *)object); if (! sexp) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return -1; @@ -683,7 +812,7 @@ { PyObject* res; R_len_t i_R; - SEXP *sexp = &(((SexpObject *)object)->sexp); + SEXP *sexp = &(RPY_GETSEXP((PySexpObject *)object)); if (! sexp) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); @@ -727,7 +856,7 @@ res = PyString_FromString(vs); break; case VECSXP: - res = (PyObject *)newSexpObject(VECTOR_ELT(*sexp, i_R)); + res = (PyObject *)newPySexpObject(VECTOR_ELT(*sexp, i_R)); break; default: PyErr_Format(PyExc_ValueError, "cannot handle type %d", @@ -751,7 +880,7 @@ return -1; } - SEXP *sexp = &(((SexpObject *)object)->sexp); + SEXP *sexp = &(RPY_GETSEXP((PySexpObject *)object)); if (i >= GET_LENGTH(*sexp)) { PyErr_Format(PyExc_IndexError, "Index out of range."); return -1; @@ -762,13 +891,13 @@ return -1; } - int is_SexpObject = PyObject_TypeCheck(val, &Sexp_Type); - if (! is_SexpObject) { + int is_PySexpObject = PyObject_TypeCheck(val, &Sexp_Type); + if (! is_PySexpObject) { PyErr_Format(PyExc_ValueError, "Any new value must be of " "type 'Sexp_Type'."); return -1; } - SEXP *sexp_val = &(((SexpObject *)val)->sexp); + SEXP *sexp_val = &(RPY_GETSEXP((PySexpObject *)val)); if (! sexp_val) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return -1; @@ -854,13 +983,16 @@ /* That other method is also performing indexing."); */ //FIXME: implement offset-one indexing. +static int +VectorSexp_init(PySexpObject *self, PyObject *args, PyObject *kwds); + static PyTypeObject VectorSexp_Type = { /* The ob_type field must be initialized in the module init function * to be portable to Windows without using C++. */ PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "rinterface.SexpVector", /*tp_name*/ - sizeof(SexpObject), /*tp_basicsize*/ + sizeof(PySexpObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ 0, /*tp_dealloc*/ @@ -894,17 +1026,63 @@ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ - 0, /*tp_init*/ + (initproc)VectorSexp_init, /*tp_init*/ 0, /*tp_alloc*/ - VectorSexp_new, /*tp_new*/ + 0, /*tp_new*/ 0, /*tp_free*/ 0 /*tp_is_gc*/ }; + +static int +VectorSexp_init(PySexpObject *self, PyObject *args, PyObject *kwds) +{ +#ifdef RPY_VERBOSE + printf("%p: VectorSexp initializing...", self); +#endif + PyObject *object; + int sexptype = -1; + PyObject *copy; + static char *kwlist[] = {"sexpvector", "sexptype", "copy", NULL}; + + //FIXME: handle the copy argument + if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|iO!", + kwlist, + &object, + &sexptype, + &PyBool_Type, ©)) { + return -1; + } + if (PyObject_IsInstance(object, + (PyObject*)&VectorSexp_Type)) { + + //call parent's constructor + if (Sexp_init(self, args, kwds) == -1) { + PyErr_Format(PyExc_RuntimeError, "Error initializing instance."); + return -1; + } + } else { + if (sexptype == -1) { + //FIXME: implemement automagic type + //(RPy has something). + + PyErr_Format(PyExc_ValueError, "Missing type."); + return -1; + } + RPY_GETSEXP(self) = newSEXP(object, sexptype); + } +#ifdef RPY_VERBOSE + printf("done.\n"); +#endif + + return 0; +} + + /* --- */ -static SexpObject* +static PySexpObject* EnvironmentSexp_findVar(PyObject *self, PyObject *args) { char *name; @@ -914,7 +1092,7 @@ return NULL; } - const SEXP rho_R = ((SexpObject *)self)->sexp; + const SEXP rho_R = RPY_GETSEXP((PySexpObject *)self); if (! rho_R) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return NULL; @@ -928,7 +1106,7 @@ if (res_R != R_UnboundValue) { - return newSexpObject(res_R); + return newPySexpObject(res_R); } PyErr_Format(PyExc_LookupError, "'%s' not found", name); return NULL; @@ -943,7 +1121,7 @@ }; -static SexpObject* +static PySexpObject* EnvironmentSexp_subscript(PyObject *self, PyObject *key) { char *name; @@ -956,7 +1134,7 @@ name = PyString_AsString(key); - SEXP rho_R = ((SexpObject *)self)->sexp; + SEXP rho_R = RPY_GETSEXP((PySexpObject *)self); if (! rho_R) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return NULL; @@ -964,7 +1142,7 @@ res_R = findVarInFrame(rho_R, install(name)); if (res_R != R_UnboundValue) { - return newSexpObject(res_R); + return newPySexpObject(res_R); } PyErr_Format(PyExc_LookupError, "'%s' not found", name); return NULL; @@ -984,8 +1162,8 @@ return -1; } - int is_SexpObject = PyObject_TypeCheck(value, &Sexp_Type); - if (! is_SexpObject) { + int is_PySexpObject = PyObject_TypeCheck(value, &Sexp_Type); + if (! is_PySexpObject) { PyErr_Format(PyExc_ValueError, "All parameters must be of type Sexp_Type."); //PyDecRef(value); @@ -994,14 +1172,14 @@ name = PyString_AsString(key); - SEXP rho_R = ((SexpObject *)self)->sexp; + SEXP rho_R = RPY_GETSEXP((PySexpObject *)self); if (! rho_R) { PyErr_Format(PyExc_ValueError, "The environment has NULL SEXP."); return -1; } SEXP sexp_copy; - SEXP sexp = ((SexpObject *)value)->sexp; + SEXP sexp = RPY_GETSEXP((PySexpObject *)value); if (! sexp) { PyErr_Format(PyExc_ValueError, "The value has NULL SEXP."); return -1; @@ -1015,7 +1193,7 @@ static Py_ssize_t EnvironmentSexp_length(PyObject *self) { - SEXP rho_R = ((SexpObject *)self)->sexp; + SEXP rho_R = RPY_GETSEXP((PySexpObject *)self); if (! rho_R) { PyErr_Format(PyExc_ValueError, "The environment has NULL SEXP."); return -1; @@ -1036,7 +1214,7 @@ static PyObject* EnvironmentSexp_iter(PyObject *sexpEnvironment) { - SEXP rho_R = ((SexpObject *)sexpEnvironment)->sexp; + SEXP rho_R = RPY_GETSEXP((PySexpObject *)sexpEnvironment); if (! rho_R) { PyErr_Format(PyExc_ValueError, "The environment has NULL SEXP."); @@ -1044,7 +1222,7 @@ } SEXP symbols; PROTECT(symbols = R_lsInternal(rho_R, TRUE)); - SexpObject *seq = newSexpObject(symbols); + PySexpObject *seq = newPySexpObject(symbols); Py_INCREF(seq); UNPROTECT(1); @@ -1068,13 +1246,17 @@ inspected upon absence of a given key.\n\ "); + +static int +EnvironmentSexp_init(PySexpObject *self, PyObject *args, PyObject *kwds); + static PyTypeObject EnvironmentSexp_Type = { /* The ob_type field must be initialized in the module init function * to be portable to Windows without using C++. */ PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "rinterface.SexpEnvironment", /*tp_name*/ - sizeof(SexpObject), /*tp_basicsize*/ + sizeof(PySexpObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ 0, /*tp_dealloc*/ @@ -1108,7 +1290,7 @@ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ - 0, /*tp_init*/ + EnvironmentSexp_init, /*tp_init*/ 0, /*tp_alloc*/ //FIXME: add new method 0, //EnvironmentSexp_new, /*tp_new*/ @@ -1116,19 +1298,54 @@ 0 /*tp_is_gc*/ }; +static int +EnvironmentSexp_init(PySexpObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *object; + int sexptype = -1; + PyObject *copy; + static char *kwlist[] = {"sexpenv", "copy", NULL}; + //FIXME: handle the copy argument + if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|O!", + kwlist, + &object, + &PyBool_Type, ©)) { + return -1; + } + if (PyObject_IsInstance(object, + (PyObject*)&EnvironmentSexp_Type)) { + //call parent's constructor + if (Sexp_init(self, args, kwds) == -1) { + PyErr_Format(PyExc_RuntimeError, "Error initializing instance."); + return -1; + } + } else { + PyErr_Format(PyExc_ValueError, "Cannot instantiate from this type."); + return -1; + } + return 0; +} + + + + + + + //FIXME: write more doc PyDoc_STRVAR(S4Sexp_Type_doc, "R object that is an 'S4 object'.\ "); + static PyTypeObject S4Sexp_Type = { /* The ob_type field must be initialized in the module init function * to be portable to Windows without using C++. */ PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "rinterface.SexpS4", /*tp_name*/ - sizeof(SexpObject), /*tp_basicsize*/ + sizeof(PySexpObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ 0, /*tp_dealloc*/ @@ -1173,10 +1390,10 @@ /* --- Create a SEXP object --- */ -static SexpObject* -newSexpObject(const SEXP sexp) +static PySexpObject* +newPySexpObject(const SEXP sexp) { - SexpObject *object; + PySexpObject *object; SEXP sexp_ok, env_R; if (! sexp) { @@ -1198,8 +1415,7 @@ case CLOSXP: case BUILTINSXP: case SPECIALSXP: - object = (SexpObject *)PyObject_New(SexpObject, - &ClosureSexp_Type); + object = (PySexpObject *)Sexp_new(&ClosureSexp_Type, Py_None, Py_None); break; //FIXME: BUILTINSXP and SPECIALSXP really like CLOSXP ? case REALSXP: @@ -1208,20 +1424,16 @@ case CPLXSXP: case VECSXP: case STRSXP: - object = (SexpObject *)PyObject_New(SexpObject, - &VectorSexp_Type); + object = (PySexpObject *)Sexp_new(&VectorSexp_Type, Py_None, Py_None); break; case ENVSXP: - object = (SexpObject *)PyObject_New(SexpObject, - &EnvironmentSexp_Type); + object = (PySexpObject *)Sexp_new(&EnvironmentSexp_Type, Py_None, Py_None); break; case S4SXP: - object = (SexpObject *)PyObject_New(SexpObject, - &S4Sexp_Type); + object = (PySexpObject *)Sexp_new(&S4Sexp_Type, Py_None, Py_None); break; default: - object = (SexpObject *)PyObject_New(SexpObject, - &Sexp_Type); + object = (PySexpObject *)Sexp_new(&Sexp_Type, Py_None, Py_None); break; } if (!object) { @@ -1230,7 +1442,7 @@ return NULL; } //PyObject_Init(&object, &ClosureSexp_Type); - object->sexp = sexp_ok; + RPY_GETSEXP(object) = sexp_ok; //FIXME: Increment reference ? //Py_INCREF(object); return object; @@ -1312,14 +1524,14 @@ case VECSXP: for (i = 0; i < length; ++i) { if((item = PySequence_Fast_GET_ITEM(seq_object, i))) { - int is_SexpObject = PyObject_TypeCheck(item, &Sexp_Type); - if (! is_SexpObject) { + int is_PySexpObject = PyObject_TypeCheck(item, &Sexp_Type); + if (! is_PySexpObject) { Py_DECREF(item); PyErr_Format(PyExc_ValueError, "All elements of the list must be of " "type 'Sexp_Type'."); return NULL; } - SET_ELEMENT(sexp, i, ((SexpObject *)item)->sexp); + SET_ELEMENT(sexp, i, RPY_GETSEXP((PySexpObject *)item)); Py_DECREF(item); } } @@ -1341,7 +1553,7 @@ } break; default: - PyErr_Format(PyExc_ValueError, "cannot handle type %d", rType); + PyErr_Format(PyExc_ValueError, "Cannot handle type %d", rType); sexp = NULL; } UNPROTECT(1); @@ -1353,7 +1565,7 @@ /* --- Find a variable in an environment --- */ -static SexpObject* +static PySexpObject* EmbeddedR_findVar(PyObject *self, PyObject *args) { char *name; @@ -1369,7 +1581,7 @@ if (res != R_UnboundValue) { - return newSexpObject(res); + return newPySexpObject(res); } PyErr_Format(PyExc_LookupError, "'%s' not found", name); return NULL; @@ -1454,7 +1666,7 @@ PyList_Append(pyargs, (PyObject *)R_ExternalPtrAddr(sexp)); } else { - PyList_Append(pyargs, (PyObject *)newSexpObject(sexp)); + PyList_Append(pyargs, (PyObject *)newPySexpObject(sexp)); } } PyObject *pyargstup = PyList_AsTuple(pyargs); @@ -1480,7 +1692,7 @@ Py_DECREF(pyargstup); if (PyObject_IsInstance((PyObject*)pyres, (PyObject*)&Sexp_Type)) { - res = ((SexpObject*)pyres)->sexp; + res = RPY_GETSEXP((PySexpObject*)pyres); } else { res = mkPyObject(pyres); @@ -1505,7 +1717,7 @@ PyMODINIT_FUNC initrinterface(void) { - + /* Finalize the type object including setting type of the new type * object; doing it here is required for portability to Windows * without requiring C++. */ @@ -1547,21 +1759,25 @@ //FIXME: DECREF ? //Py_DECREF(embeddedR_isInitialized); - globalEnv = (SexpObject *)PyObject_New(SexpObject, - &EnvironmentSexp_Type); - globalEnv->sexp = R_EmptyEnv; + globalEnv = (PySexpObject *)Sexp_new(&EnvironmentSexp_Type, + Py_None, Py_None); + RPY_GETSEXP(globalEnv) = R_EmptyEnv; + //SexpObject *sObj = globalEnv->sObj; + //SEXP sexp = sObj->sexp; + //sexp = R_EmptyEnv; + //(globalEnv->sObj)->sexp = R_EmptyEnv; if (PyDict_SetItemString(d, "globalEnv", (PyObject *)globalEnv) < 0) return; //FIXME: DECREF ? - Py_DECREF(globalEnv); + //Py_DECREF(globalEnv); - baseNameSpaceEnv = (SexpObject*)PyObject_New(SexpObject, - &EnvironmentSexp_Type); - baseNameSpaceEnv->sexp = R_EmptyEnv; + baseNameSpaceEnv = (PySexpObject*)Sexp_new(&EnvironmentSexp_Type, + Py_None, Py_None); + RPY_GETSEXP(baseNameSpaceEnv) = R_EmptyEnv; if (PyDict_SetItemString(d, "baseNameSpaceEnv", (PyObject *)baseNameSpaceEnv) < 0) return; - //FIXME: DECREF ? - Py_DECREF(baseNameSpaceEnv); +/* //FIXME: DECREF ? */ +/* Py_DECREF(baseNameSpaceEnv); */ /* Add SXP types */ ADD_INT_CONSTANT(m, NILSXP); @@ -1605,14 +1821,15 @@ Py_DECREF(na_real); - /* Rinternals.h */ - SexpObject *na_string = (SexpObject *)PyObject_New(SexpObject, - &VectorSexp_Type); - na_string->sexp = NA_STRING; +/* /\* Rinternals.h *\/ */ + PySexpObject *na_string = (PySexpObject *)Sexp_new(&VectorSexp_Type, + Py_None, Py_None); + + RPY_GETSEXP(na_string) = NA_STRING; if (PyDict_SetItemString(d, "NA_STRING", (PyObject *)na_string) < 0) return; - //FIXME: DECREF ? - Py_DECREF(na_string); +/* //FIXME: DECREF ? */ + //Py_DECREF(na_string); } Modified: branches/rpy_nextgen/rpy/rinterface/rinterface.h =================================================================== --- branches/rpy_nextgen/rpy/rinterface/rinterface.h 2008-04-20 09:48:38 UTC (rev 500) +++ branches/rpy_nextgen/rpy/rinterface/rinterface.h 2008-04-23 20:57:10 UTC (rev 501) @@ -5,12 +5,31 @@ #include <R.h> #include <Python.h> + +//#define RPY_VERBOSE + /* Representation of R objects (instances) as instances in Python. */ + typedef struct { - PyObject_HEAD + int count; SEXP sexp; } SexpObject; +typedef struct { + PyObject_HEAD + SexpObject *sObj; + //SEXP sexp; +} PySexpObject; + + +#define RPY_GETCOUNT(obj) (((obj)->sObj)->count) +#define RPY_GETSEXP(obj) (((obj)->sObj)->sexp) +//#define RPY_GETSEXP(obj) ((obj)->sexp) + +#define RPY_INCREF(obj) ((obj->sObj)->count++) +#define RPY_DECREF(obj) ((obj->sObj)->count--) + + #endif /* !RPY_RI_H */ Modified: branches/rpy_nextgen/rpy/rinterface/tests/test_Sexp.py =================================================================== --- branches/rpy_nextgen/rpy/rinterface/tests/test_Sexp.py 2008-04-20 09:48:38 UTC (rev 500) +++ branches/rpy_nextgen/rpy/rinterface/tests/test_Sexp.py 2008-04-23 20:57:10 UTC (rev 501) @@ -15,6 +15,23 @@ #def tearDown(self): # rinterface.endEmbeddedR(1); + def testNew(self): + + x = "a" + self.assertRaises(ValueError, rinterface.Sexp, x) + + sexp = rinterface.globalEnv.get("letters") + sexp_new = rinterface.Sexp(sexp) + + idem = rinterface.globalEnv.get("identical") + self.assertTrue(idem(sexp, sexp_new)[0]) + + sexp_new2 = rinterface.Sexp(sexp) + self.assertTrue(idem(sexp, sexp_new2)[0]) + del(sexp) + self.assertTrue(idem(sexp_new, sexp_new2)[0]) + + def testTypeof(self): sexp = rinterface.globalEnv.get("letters") self.assertEquals(sexp.typeof(), rinterface.STRSXP) Modified: branches/rpy_nextgen/rpy/rinterface/tests/test_SexpEnvironment.py =================================================================== --- branches/rpy_nextgen/rpy/rinterface/tests/test_SexpEnvironment.py 2008-04-20 09:48:38 UTC (rev 500) +++ branches/rpy_nextgen/rpy/rinterface/tests/test_SexpEnvironment.py 2008-04-23 20:57:10 UTC (rev 501) @@ -14,6 +14,20 @@ #def tearDown(self): # rinterface.endEmbeddedR(0); + def testNew(self): + sexp = rinterface.globalEnv + sexp_new = rinterface.SexpEnvironment(sexp) + + idem = rinterface.globalEnv.get("identical") + self.assertTrue(idem(sexp, sexp_new)[0]) + + sexp_new2 = rinterface.Sexp(sexp) + self.assertTrue(idem(sexp, sexp_new2)[0]) + del(sexp) + self.assertTrue(idem(sexp_new, sexp_new2)[0]) + + self.assertRaises(ValueError, rinterface.SexpEnvironment, '2') + def testGlobalEnv(self): ok = isinstance(rinterface.globalEnv, rinterface.SexpEnvironment) self.assertTrue(ok) Modified: branches/rpy_nextgen/rpy/rinterface/tests/test_SexpVector.py =================================================================== --- branches/rpy_nextgen/rpy/rinterface/tests/test_SexpVector.py 2008-04-20 09:48:38 UTC (rev 500) +++ branches/rpy_nextgen/rpy/rinterface/tests/test_SexpVector.py 2008-04-23 20:57:10 UTC (rev 501) @@ -17,6 +17,9 @@ #def tearDown(self): # rinterface.endEmbeddedR(1); + def testMissinfType(self): + self.assertRaises(ValueError, rinterface.SexpVector, [2, ]) + def testNewBool(self): sexp = rinterface.SexpVector([True, ], rinterface.LGLSXP) isLogical = rinterface.globalEnv.get("is.logical") Modified: branches/rpy_nextgen/rpy/robjects/__init__.py =================================================================== --- branches/rpy_nextgen/rpy/robjects/__init__.py 2008-04-20 09:48:38 UTC (rev 500) +++ branches/rpy_nextgen/rpy/robjects/__init__.py 2008-04-23 20:57:10 UTC (rev 501) @@ -26,7 +26,7 @@ res = Robject(o) return res -#FIXME: clean and nice mechanism to allow user-specifier mapping function +#FIXME: clean and nice mechanism to allow user-specified mapping function #FIXME: better names for the functions mapperR2Py = defaultRobjects2PyMapper @@ -63,12 +63,17 @@ mapperPy2R = defaultPy2RobjectsMapper -#FIXME: Looks hackish. inheritance should be used ? -class Robject(object): +def repr_robject(o): + s = r.deparse(o) + s = str.join(os.linesep, o) + return s + + +class Robject(rinterface.Sexp): name = None - def __init__(self, o): - self._sexp = o + def __init__(self, sexp, copy=True): + super(Robject, self).__init__(sexp, copy=copy) def __str__(self): tmp = r.fifo("") @@ -77,25 +82,22 @@ r.sink() s = r.readLines(tmp) r.close(tmp) - s = str.join(os.linesep, s._sexp) + s = str.join(os.linesep, self) return s def __repr__(self): - s = r.deparse(self) - s = str.join(os.linesep, s._sexp) - return s + return repr_robject(self) - -class Rvector(Robject): +class Rvector(rinterface.SexpVector): """ R vector-like object. Items in those instances can be accessed with the method "__getitem__" ("[" operator), or with the method "subset".""" def __init__(self, o): - if (isinstance(o, rinterface.SexpVector)): - self._sexp = o - else: - self._sexp = mapperPy2R(o)._sexp + if not isinstance(o, rinterface.SexpVector): + o = mapperPy2R(o) + super(Rvector, self).__init__(o) + def subset(self, *args, **kwargs): """ Subset the "R-way.", using R's "[" function. @@ -114,13 +116,12 @@ for k, v in kwargs.itervalues(): args[k] = mapperPy2R(v) - res = r["["](*([self._sexp, ] + [x._sexp for x in args]), **kwargs) + res = r["["](*([self, ] + [x for x in args]), **kwargs) return res - def __getitem__(self, i): - res = mapperPy2R(self._sexp[i]) - return res - + def __repr__(self): + return repr_robject(self) + def __add__(self, x): res = r.get("+")(self, x) return res @@ -150,19 +151,14 @@ return res def __len__(self): - return len(self._sexp) + return len(sexp) -class Rfunction(Robject): +class Rfunction(rinterface.SexpClosure): """ An R function (aka "closure"). """ - - def __init__(self, o): - if (isinstance(o, rinterface.SexpClosure)): - self._sexp = o - else: - raise(ValueError("Cannot instantiate.")) + super(Rfunction, self).__init__(o) def __call__(self, *args, **kwargs): new_args = [mapperPy2R(a)._sexp for a in args] @@ -174,25 +170,20 @@ return res -class Renvironment(Robject): +class Renvironment(rinterface.SexpEnvironment): """ An R environement. """ + def __init__(self, o): - if (isinstance(o, rinterface.SexpEnvironment)): - self._sexp = o - else: - raise(ValueError("Cannot instantiate")) + super(Renvironment, self).__init__(o) def __getitem__(self, item): - res = self._sexp[item] + res = super(Renvironment, self).__getitem__(item) res = mapperR2Py(res) return res def __setitem__(self, item, value): - robj = mapperPy2R(value) - self._sexp[item] = robj._sexp + self[item] = robj - def __iter__(self): - return iter(self._sexp) class RS4(Robject): def __init__(self, o): Added: branches/rpy_nextgen/rpy/robjects/tests/testRFunction.py =================================================================== --- branches/rpy_nextgen/rpy/robjects/tests/testRFunction.py (rev 0) +++ branches/rpy_nextgen/rpy/robjects/tests/testRFunction.py 2008-04-23 20:57:10 UTC (rev 501) @@ -0,0 +1,27 @@ +import unittest +import rpy2.robjects as robjects +rinterface = robjects.rinterface +import array + +class RFunctionTestCase(unittest.TestCase): + def testNew(self): + self.assertRaises(ValueError, robjects.Rfunction, 'a') + + ri_f = rinterface.baseNameSpaceEnv.get('help') + + ro_f = robjects.Rfunction(ri_f) + + #self.assertEquals(ro_v.typeof(), rinterface.INTSXP) + + #ri_v = rinterface.SexpVector(py_a) + #ri_o = rinterface.Sexp(ri_v) + + #r_v_new = robject.Rvector(ri_v) + #r_v_new = robject.Rvector(ro_v) + +def suite(): + suite = unittest.TestLoader().loadTestsFromTestCase(RFunctionTestCase) + return suite + +if __name__ == '__main__': + unittest.main() Property changes on: branches/rpy_nextgen/rpy/robjects/tests/testRFunction.py ___________________________________________________________________ Name: svn:eol-style + native Added: branches/rpy_nextgen/rpy/robjects/tests/testRVector.py =================================================================== --- branches/rpy_nextgen/rpy/robjects/tests/testRVector.py (rev 0) +++ branches/rpy_nextgen/rpy/robjects/tests/testRVector.py 2008-04-23 20:57:10 UTC (rev 501) @@ -0,0 +1,22 @@ +import unittest +import rpy2.robjects as robjects +rinterface = robjects.rinterface +import array + +class RvectorTestCase(unittest.TestCase): + def testNew(self): + py_a = array.array('i', [1,2,3]) + ro_v = robjects.Rvector(py_a) + self.assertEquals(ro_v.typeof(), rinterface.INTSXP) + + ri_v = rinterface.SexpVector(py_a) + + #r_v_new = robject.Rvector(ri_v) + #r_v_new = robject.Rvector(ro_v) + +def suite(): + suite = unittest.TestLoader().loadTestsFromTestCase(RvectorTestCase) + return suite + +if __name__ == '__main__': + unittest.main() Property changes on: branches/rpy_nextgen/rpy/robjects/tests/testRVector.py ___________________________________________________________________ Name: svn:eol-style + native Modified: branches/rpy_nextgen/rpy/robjects/tests/testRobjects.py =================================================================== --- branches/rpy_nextgen/rpy/robjects/tests/testRobjects.py 2008-04-20 09:48:38 UTC (rev 500) +++ branches/rpy_nextgen/rpy/robjects/tests/testRobjects.py 2008-04-23 20:57:10 UTC (rev 501) @@ -3,14 +3,14 @@ rinterface = robjects.rinterface import array -class RvectorTestCase(unittest.TestCase): +class RObjectTestCase(unittest.TestCase): def testGetItem(self): letters_R = robjects.r["letters"] self.assertTrue(isinstance(letters_R, robjects.Rvector)) letters = (('a', 0), ('b', 1), ('c', 2), ('x', 23), ('y', 24), ('z', 25)) for l, i in letters: - self.assertTrue(letters_R[i]._sexp[0] == l) + self.assertTrue(letters_R[i] == l) as_list_R = robjects.r["as.list"] seq_R = robjects.r["seq"] @@ -20,18 +20,18 @@ myList = as_list_R(mySeq) for i, li in enumerate(myList): - self.assertEquals(i, myList[i][0]._sexp[0]) + self.assertEquals(i, myList[i][0]) def testOperators(self): seq_R = robjects.r["seq"] mySeq = seq_R(0, 10) mySeqAdd = mySeq + 2 for i, li in enumerate(mySeq): - self.assertEquals(i + 2, mySeqAdd[i]._sexp[0]) + self.assertEquals(i + 2, mySeqAdd[i]) mySeqAdd = mySeq + mySeq for i, li in enumerate(mySeq): - self.assertEquals(mySeq[i]._sexp[0] * 2, mySeqAdd[i]._sexp[0]) + self.assertEquals(mySeq[i] * 2, mySeqAdd[i]) def testSubset(self): @@ -43,7 +43,7 @@ mySubset = mySeq.subset(myIndex) #import pdb; pdb.set_trace() for i, si in enumerate(myIndex): - self.assertEquals(mySeq[si._sexp[0]-1]._sexp[0], mySubset[i]._sexp[0]) + self.assertEquals(mySeq[si-1], mySubset[i]) # recycling rule v = robjects.Rvector(array.array('i', range(1, 23))) @@ -83,12 +83,12 @@ py = True rob = robjects.defaultPy2RobjectsMapper(py) self.assertTrue(isinstance(rob, robjects.Rvector)) - self.assertEquals(rinterface.LGLSXP, rob._sexp.typeof()) + self.assertEquals(rinterface.LGLSXP, rob.typeof()) #FIXME: more tests def suite(): - suite = unittest.TestLoader().loadTestsFromTestCase(RvectorTestCase) + suite = unittest.TestLoader().loadTestsFromTestCase(RObjectTestCase) return suite if __name__ == '__main__': 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 the 2008 JavaOne(SM) Conference Don't miss this year's exciting event. There's still time to save $100. Use priority code J8TL2D2. http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone _______________________________________________ rpy-list mailing list rpy-list@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/rpy-list