Revision: 407
http://rpy.svn.sourceforge.net/rpy/?rev=407&view=rev
Author: lgautier
Date: 2008-03-01 14:45:04 -0800 (Sat, 01 Mar 2008)
Log Message:
-----------
Added module robjects
Working subset operator for Environments Sexp
Too many fixes and additions
Modified Paths:
--------------
trunk/sandbox/rpy_nextgen/rinterface/rinterface.c
trunk/sandbox/rpy_nextgen/setup.py
Added Paths:
-----------
trunk/sandbox/rpy_nextgen/robjects/
trunk/sandbox/rpy_nextgen/robjects/__init__.py
Modified: trunk/sandbox/rpy_nextgen/rinterface/rinterface.c
===================================================================
--- trunk/sandbox/rpy_nextgen/rinterface/rinterface.c 2008-02-24 19:07:58 UTC
(rev 406)
+++ trunk/sandbox/rpy_nextgen/rinterface/rinterface.c 2008-03-01 22:45:04 UTC
(rev 407)
@@ -6,7 +6,7 @@
* of RPy.
*
* The authors for the original RPy code, as well as
- * belopolsky's contributed code, are listed here as authors;
+ * belopolsky for his contributed code, are listed here as authors;
* parts of this code is (sometimes shamelessly but with great
* respect for the work) "inspired" from their contributions.
*
@@ -29,6 +29,13 @@
* for the specific language governing rights and limitations under the
* License.
*
+ * original RPy Authors: Walter Moreira.
+ * Gregory R. Warnes <[EMAIL PROTECTED]> (Maintainer)
+ * Original code from wrapping R's C-level SEXPs: belopolsky
+ *
+ * This code: Laurent Gautier
+ *
+ *
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
@@ -86,18 +93,18 @@
Check the documentation for the module this is bundled into if\
you only wish to have an off-the-shelf interface with R.\
\n\
- Example of usage:\
-import rinterface\
-rinterface.initEmbeddedR(\"foo\", \"--verbose\")\
-n = rinterface.SexpVector((100, ), rinterface.REALSXP)\
-hist = rinterface.findVarEmbeddedR(\"hist\")\
-rnorm = rinterface.findVarEmbeddedR(\"rnorm\")\
-x = rnorm(n)\
-hist(x)\
+ Example of usage:n\
+import rinterface\n\
+rinterface.initEmbeddedR(\"foo\", \"--verbose\")\n\
+n = rinterface.SexpVector((100, ), rinterface.REALSXP)\n\
+hist = rinterface.globalEnv.get(\"hist\")\n\
+rnorm = rinterface.globalEnv.get(\"rnorm\")\n\
+x = rnorm(n)\n\
+hist(x)\n\
\
-len(x)\
+len(x)\n\
\n\
-$Id$");
+");
//FIXME: check example above
@@ -110,6 +117,7 @@
static SexpObject* globalEnv;
+static SexpObject* baseNameSpaceEnv;
/* --- Initialize and terminate an embedded R --- */
/* Should having multiple threads of R become possible,
@@ -117,6 +125,7 @@
*/
static PyObject* EmbeddedR_init(PyObject *self, PyObject *args)
{
+ //FIXME: arbitrary number of options
//char *defaultargv[] = {"rpython", "--verbose"};
char *options[5] = {"", "", "", "", ""};
@@ -154,7 +163,7 @@
//ending R will not be possible until all such objects are already
//deallocated in Python ?
//other possibility would be to have a fallback for "unreachable" objects ?
- //FIXME: rpy has something to terminate R. Check the details of what it is.
+ //FIXME: rpy has something to terminate R. Check the details of what they
are.
if (! PyInt_Check(arg)) {
} else {
/* sanity checks needed ? */
@@ -217,6 +226,21 @@
* 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)
{
@@ -299,7 +323,7 @@
0, /*tp_dictoffset*/
0, /*tp_init*/
0, /*tp_alloc*/
- 0,//Sexp_new, /*tp_new*/
+ 0, //Sexp_new, /*tp_new*/
0, /*tp_free*/
0, /*tp_is_gc*/
};
@@ -387,24 +411,49 @@
PyObject *tmp_obj;
int is_SexpObject;
for (arg_i=0; arg_i<largs; arg_i++) {
- //FIXME: assert that all are SexpObjects
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;
+ goto fail;
}
tmp_R = ((SexpObject *)tmp_obj)->sexp;
SETCAR(c_R, tmp_R);
c_R = CDR(c_R);
}
+
+ /* named args */
+ PyObject *citems, *argValue, *argName;
+ char *argNameString;
+
+ if (kwds) {
+ citems = PyMapping_Items(kwds);
+ }
+ for (arg_i=0; arg_i<lkwds; arg_i++) {
+ tmp_obj = PySequence_GetItem(citems, arg_i);
+ if (! tmp_obj)
+ goto fail;
+ argName = PyTuple_GetItem(tmp_obj, 0);
+ if (! PyString_Check(argName)) {
+ PyErr_SetString(PyExc_TypeError, "keywords must be strings");
+ goto fail;
+ }
+ argValue = PyTuple_GetItem(tmp_obj, 1);
+ is_SexpObject = PyObject_TypeCheck(argValue, &Sexp_Type);
+ if (! is_SexpObject) {
+ PyErr_Format(PyExc_ValueError, "All parameters must be of type
Sexp_Type.");
+ goto fail;
+ }
+ Py_DECREF(tmp_obj);
+ tmp_R = ((SexpObject *)argValue)->sexp;
+ SETCAR(c_R, tmp_R);
+ argNameString = PyString_AsString(argName);
+ SET_TAG(c_R, install(argNameString));
+ //printf("PyMem_Free...");
+ //PyMem_Free(argNameString);
+ }
+ Py_XDECREF(citems);
- //FIXME: implement named parameters.
-/* if (!make_kwds(lkwds, kwds, &e)) { */
-/* UNPROTECT(1); */
-/* return NULL; */
-/* } */
-
//FIXME: R_GlobalContext ?
PROTECT(res_R = do_eval_expr(call_R));
@@ -416,9 +465,17 @@
//FIXME: standardize R outputs
extern void Rf_PrintWarnings(void);
Rf_PrintWarnings(); /* show any warning messages */
-
+
PyObject *res = (PyObject *)newSexpObject(res_R);
return res;
+
+ fail:
+ printf("failed.\n");
+ Py_XDECREF(citems);
+ Py_DECREF(tmp_obj);
+ UNPROTECT(1);
+ return NULL;
+
}
@@ -506,9 +563,6 @@
if (!PyArg_ParseTuple(args, "Oi:new",
&seq, &rType))
return NULL;
- #ifdef VERBOSE
- printf("type: %i\n", rType);
- #endif
const SEXP sexp = newSEXP(seq, rType);
PyObject *res = (PyObject *)newSexpObject(sexp);
return res;
@@ -670,8 +724,8 @@
const SEXP rho_R = ((SexpObject *)self)->sexp;
- if (rho_R == NULL) {
- PyErr_Format(PyExc_LookupError, "Fatal error: NULL environment.");
+ if (rho_R == R_EmptyEnv) {
+ PyErr_Format(PyExc_LookupError, "Fatal error: R_UnboundValue.");
}
res_R = findVar(install(name), rho_R);
@@ -708,9 +762,8 @@
name = PyString_AsString(key);
SEXP rho_R = ((SexpObject *)self)->sexp;
- res_R = findVarInFrame(install(name), rho_R);
+ res_R = findVarInFrame(rho_R, install(name));
-
if (res_R != R_UnboundValue) {
return newSexpObject(res_R);
}
@@ -733,14 +786,17 @@
// be made like mappings at the Python level ?
PyDoc_STRVAR(EnvironmentSexp_Type_doc,
"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\n\
- environment whenever the key is not found.\
+ R environments can be seen as similar to Python\
+ dictionnaries, with the following twists:\n\
+ - an environment can be a list of frames to sequentially\
+ search into\n\
+- the search can be recursively propagated to the enclosing\
+ environment whenever the key is not found (in that respect\
+ they can be seen as scopings).\n\
\n\
- The subsetting operator is made to match Python's\n\
+ The subsetting operator \"[\" is made to match Python's\
behavior, that is the enclosing environments are not\
- inspected upon absence of a given key.\
+ inspected upon absence of a given key.\n\
");
static PyTypeObject EnvironmentSexp_Type = {
@@ -976,6 +1032,18 @@
}
}
break;
+ case LISTSXP:
+ 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) {
+ PyErr_Format(PyExc_ValueError, "All elements of the list must be of "
+ "type 'Sexp_Type'.");
+ return NULL;
+ }
+ SET_ELEMENT(sexp, i, ((SexpObject *)item)->sexp);
+ }
+ }
//FIXME: add complex
default:
PyErr_Format(PyExc_ValueError, "cannot handle type %d", rType);
@@ -1092,13 +1160,20 @@
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)
+ globalEnv = (SexpObject *)_PyObject_New(&EnvironmentSexp_Type);
+ globalEnv->sexp = R_EmptyEnv;
+ if (PyDict_SetItemString(d, "globalEnv", (PyObject *)globalEnv) < 0)
return;
//FIXME: DECREF ?
- //Py_DECREF(globalEnv);
+ Py_DECREF(globalEnv);
+ baseNameSpaceEnv = (SexpObject*)_PyObject_New(&EnvironmentSexp_Type);
+ globalEnv->sexp = R_EmptyEnv;
+ if (PyDict_SetItemString(d, "baseNameSpaceEnv", (PyObject
*)baseNameSpaceEnv) < 0)
+ return;
+ //FIXME: DECREF ?
+ Py_DECREF(baseNameSpaceEnv);
+
/* Add some symbolic constants to the module */
ADD_INT_CONSTANT(m, NILSXP);
ADD_INT_CONSTANT(m, SYMSXP);
@@ -1124,4 +1199,27 @@
ADD_INT_CONSTANT(m, RAWSXP);
ADD_INT_CONSTANT(m, S4SXP);
+ /* "Logical" (boolean) values */
+ ADD_INT_CONSTANT(m, TRUE);
+ ADD_INT_CONSTANT(m, FALSE);
+
+ /* R_ext/Arith.h */
+ ADD_INT_CONSTANT(m, NA_LOGICAL);
+ ADD_INT_CONSTANT(m, NA_INTEGER);
+ PyObject *na_real = PyFloat_FromDouble(NA_REAL);
+ if (PyDict_SetItemString(d, "NA_REAL", (PyObject *)na_real) < 0)
+ return;
+ //FIXME: DECREF ?
+ Py_DECREF(na_real);
+
+
+ /* Rinternals.h */
+ SexpObject *na_string = (SexpObject *)_PyObject_New(&VectorSexp_Type);
+ na_string->sexp = NA_STRING;
+ if (PyDict_SetItemString(d, "NA_STRING", (PyObject *)na_string) < 0)
+ return;
+ //FIXME: DECREF ?
+ Py_DECREF(na_string);
+
+
}
Added: trunk/sandbox/rpy_nextgen/robjects/__init__.py
===================================================================
--- trunk/sandbox/rpy_nextgen/robjects/__init__.py
(rev 0)
+++ trunk/sandbox/rpy_nextgen/robjects/__init__.py 2008-03-01 22:45:04 UTC
(rev 407)
@@ -0,0 +1,150 @@
+import array
+import rinterface
+
+
+#FIXME: close everything when leaving (check RPy for that).
+
+
+
+def defaultPy2RMapper(self, o):
+ if isinstance(o, Robject):
+ return o._sexp
+ if isinstance(o, array.array):
+ if o.typecode in ('h', 'H', 'i', 'I'):
+ res = rinterface.SexpVector(o, rinterface.INTSXP)
+ elif o.typecode in ('f', 'd'):
+ res = rinterface.SexpVector(o, rinterface.REALSXP)
+ else:
+ raise("Nothing can be done for this array type at the moment.")
+ elif isinstance(o, int):
+ res = rinterface.SexpVector([o, ], rinterface.INTSXP)
+ elif isinstance(o, float):
+ res = rinterface.SexpVector([o, ], rinterface.REALSXP)
+ elif isinstance(o, bool):
+ res = rinterface.SexpVector([o, ], rinterface.LGLSXP)
+ elif isinstance(o, str):
+ res = rinterface.SexpVector([o, ], rinterface.STRSXP)
+ else:
+ raise("Nothing can be done for this type at the moment.")
+ return res
+
+def defaultR2PyMapper(o):
+ if isinstance(o, rinterface.SexpVector):
+ res = Rvector(o)
+ elif isinstance(o, rinterface.SexpClosure):
+ res = Rfunction(o)
+ else:
+ res = o
+ return res
+
+
+#FIXME: clean and nice mechanism to allow user-specifier mapping function
+mapper = defaultR2PyMapper
+
+
+
+
+#FIXME: Looks hackish. inheritance should be used ?
+class Robject(object):
+ pass
+
+class Rvector(Robject):
+
+ def __init__(self, o):
+ if (isinstance(o, rinterface.SexpVector)):
+ self._sexp = o
+ else:
+ self._sexp = defaultPy2RMapper(self, o)
+
+ def subset(self, *args):
+ for a in args:
+ if not isinstance(a, rinterface.SexpVector):
+ raise(TypeError("Subset only take R vectors"))
+ res = r.globalEnv.get("[")([self._sexp, ] + args)#, drop=drop)
+ return res
+
+ def __getitem__(self, i):
+ res = self._sexp[i]
+ return res
+
+ def __add__(self, x):
+ res = r.globalEnv.get("+")(self._sexp, x)
+ return res
+
+ def __sub__(self, x):
+ res = r.globalEnv.get("-")(self._sexp, x)
+ return res
+
+ def __mul__(self, x):
+ res = r.globalEnv.get("*")(self._sexp, x)
+ return res
+
+ def __div__(self, x):
+ res = r.globalEnv.get("/")(self._sexp, x)
+ return res
+
+ def __divmod__(self, x):
+ res = r.globalEnv.get("%%")(self._sexp, x)
+ return res
+
+ def __or__(self, x):
+ res = r.globalEnv.get("|")(self._sexp, x)
+ return res
+
+ def __and__(self, x):
+ res = r.globalEnv.get("&")(self._sexp, x)
+ return res
+
+
+class Rfunction(Robject):
+
+ mapper = defaultPy2RMapper
+
+ def __init__(self, o):
+ if (isinstance(o, rinterface.SexpClosure)):
+ self._sexp = o
+ else:
+ raise("Cannot instantiate.")
+
+ def __call__(self, *args, **kwargs):
+ new_args = [self.mapper(a) for a in args]
+ new_kwargs = {}
+ for k, v in kwargs.iteritems():
+ new_kwargs[k] = self.mapper(v)
+ res = self._sexp(*new_args, **new_kwargs)
+ res = mapper(res)
+ return res
+
+
+class Renvironment(Robject):
+ def __init__(self, o):
+ if (isinstance(o, rinterface.SexpEnvironment)):
+ self._sexp = o
+ else:
+ raise("Cannot instantiate")
+
+ def __getattr__(self, attr):
+ res = self._sexp.get(attr)
+ return res
+
+
+
+class R(object):
+ _instance = None
+
+ def __init__(self, options):
+ if R._instance is None:
+ args = ["robjects", ] + options
+ rinterface.initEmbeddedR(*args)
+ R._instance = self
+ else:
+ raise("Only one instance of R can be created")
+
+ def __getattribute__(self, attr):
+ res = rinterface.globalEnv.get(attr)
+ res = mapper(res)
+ return res
+
+r = R(["--no-save", ])
+
+
Modified: trunk/sandbox/rpy_nextgen/setup.py
===================================================================
--- trunk/sandbox/rpy_nextgen/setup.py 2008-02-24 19:07:58 UTC (rev 406)
+++ trunk/sandbox/rpy_nextgen/setup.py 2008-03-01 22:45:04 UTC (rev 407)
@@ -9,7 +9,7 @@
print('R\'s home is:%s' %RHOME)
-r_libs = [os.path.join(RHOME, 'lib')]
+r_libs = [os.path.join(RHOME, 'lib'), os.path.join(RHOME, 'modules')]
rinterface = Extension(
@@ -26,7 +26,7 @@
version="0.0.1",
description="Python interface to the R language",
url="http://rpy.sourceforge.net",
- license="GPL",
+ license="(L)GPL",
ext_modules=[rinterface],
- #py_modules=['rpython']
+ py_modules=['robjects']
)
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
[email protected]
https://lists.sourceforge.net/lists/listinfo/rpy-list