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
[email protected]
https://lists.sourceforge.net/lists/listinfo/rpy-list