Revision: 404 http://rpy.svn.sourceforge.net/rpy/?rev=404&view=rev Author: lgautier Date: 2008-02-23 07:24:21 -0800 (Sat, 23 Feb 2008)
Log Message: ----------- Initial commit on sourceforge. Status is: kinda-almost-pre-alpha Added Paths: ----------- trunk/sandbox/rpy_nextgen/ trunk/sandbox/rpy_nextgen/rinterface/ trunk/sandbox/rpy_nextgen/rinterface/rinterface.c trunk/sandbox/rpy_nextgen/setup.py Added: trunk/sandbox/rpy_nextgen/rinterface/rinterface.c =================================================================== --- trunk/sandbox/rpy_nextgen/rinterface/rinterface.c (rev 0) +++ trunk/sandbox/rpy_nextgen/rinterface/rinterface.c 2008-02-23 15:24:21 UTC (rev 404) @@ -0,0 +1,976 @@ +/* A python-R interface*/ + +/* + * This is an attempt at cleaning up RPy, while adding features + * at the same time. In other words, this can be seen as a rewrite + * of RPy. + * + * The authors for the original RPy code, as well as + * belopolsky's 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. + * + * FIXME: get everyone's name in the license block + * + * Laurent Gautier - 2008 + */ + +/* + ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * 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"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "Python.h" + +#include <R.h> +#include <Rinternals.h> +#include <Rdefines.h> +#include <Rinterface.h> +#include <Rembedded.h> + +/* FIXME: consider the use of parsing */ +/* #include <R_ext/Parse.h> */ +#include <R_ext/Rdynload.h> + +#include <signal.h> + +//FIXME: get this out ASAP +#define VERBOSE + +//FIXME: see the details of error handling +static PyObject *ErrorObject; + +//FIXME: see the details of interruption +/* Indicates whether the R interpreter was interrupted by a SIGINT */ +int interrupted = 0; +/* Abort the current R computation due to a SIGINT */ +static void +interrupt_R(int signum) +{ + interrupted = 1; + error("Interrupted"); +} + + + + +/* The Python original SIGINT handler */ +PyOS_sighandler_t python_sigint; + +PyDoc_STRVAR(module_doc, + "Low-level functions to interface with R.\n\ + One should mostly consider calling the functions defined here when\ + writing a higher level interface between python and R.\ + 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(rinterface.REALSXP, (100,))\ +hist = rinterface.findVarEmbeddedR(\"hist\")\ +rnorm = rinterface.findVarEmbeddedR(\"rnorm\")\ +x = rnorm(n)\ +hist(x)\ +"); +//FIXME: check example above + + +/* Representation of R objects (instances) as instances in Python. + */ +typedef struct { + PyObject_HEAD + SEXP sexp; +} SexpObject; + + + + +/* --- Initialize and terminate an embedded R --- */ +/* Should having multiple threads of R become possible, + * Useful routines deal with can could appear here... + */ +static PyObject* EmbeddedR_init(PyObject *self, PyObject *args) +{ + //char *defaultargv[] = {"rpython", "--verbose"}; + char *options[5] = {"", "", "", "", ""}; + + if (!PyArg_ParseTuple(args, "s|ssss", + &options[0], &options[1], + &options[2], &options[3], + &options[4] + )) { + return NULL; + } + + int n_opt; + for (n_opt=0; n_opt<5; n_opt++) { + if (options[n_opt] == "") { + break; + } + } + + int status = Rf_initEmbeddedR(n_opt, options); + PyObject *res = PyInt_FromLong(status); + return res; +} +PyDoc_STRVAR(EmbeddedR_init_doc, + "initEmbeddedR()\n\ +\n\ +Initialize an embedded R."); + + +static PyObject* EmbeddedR_end(PyObject *self, PyObject *arg) +{ + //FIXME: Have a reference count for R objects known to Python. + //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. + if (! PyInt_Check(arg)) { + } else { + /* sanity checks needed ? */ + const long fatal = PyInt_AsLong(arg); + Rf_endEmbeddedR((int)fatal); + } + Py_RETURN_NONE; +} +PyDoc_STRVAR(EmbeddedR_end_doc, + "endEmbeddedR()\n\ +\n\ +Terminate an embedded R."); + + +/* --- set output from the R console ---*/ + +static void +EmbeddedR_WriteConsole(char *buf, int len) +{ + PyOS_sighandler_t old_int; + + /* It is necessary to restore the Python handler when using a Python + function for I/O. */ + old_int = PyOS_getsig(SIGINT); + PyOS_setsig(SIGINT, python_sigint); + PySys_WriteStdout(buf); + signal(SIGINT, old_int); +} + + +/* Redirect R console output */ +// R_Outputfile = NULL; + + +/* FIXME: implement possibility to specify arbitrary callback functions */ +extern void (*ptr_R_WriteConsole)(char *, int); +static PyObject* EmbeddedR_setWriteConsole(PyObject *self) +{ + ptr_R_WriteConsole = EmbeddedR_WriteConsole; + Py_RETURN_NONE; +} +PyDoc_STRVAR(EmbeddedR_setWriteConsole_doc, + "setWriteConsoleEmbeddedR()\n\ +\n\ +Set the R console output to the Python console."); + + +static PyObject* +EmbeddedR_exception_from_errmessage(void) +{ + //FIXME: sort the error message thing geterrmessage + PyErr_SetString(ErrorObject, "Error."); + return NULL; +} + + + + +/* + * Access to R objects through Python objects + */ + +static void +Sexp_dealloc(SexpObject *self) +{ + if (self->sexp) + R_ReleaseObject(self->sexp); + self->ob_type->tp_free((PyObject*)self); +} + + +static PyObject* +Sexp_repr(PyObject *self) +{ + return PyString_FromFormat("<%s - Python:\%p / R:\%p>", + self->ob_type->tp_name, + self, + &(((SexpObject *)self)->sexp)); +} + + +static PyObject* +Sexp_typeof(PyObject *self) +{ + return PyInt_FromLong(TYPEOF(((SexpObject*)self)->sexp)); +} +PyDoc_STRVAR(Sexp_typeof_doc, +"\n\ +Returns the R internal SEXP type."); + +static PyMethodDef Sexp_methods[] = { + {"typeof", (PyCFunction)Sexp_typeof, METH_NOARGS, + Sexp_typeof_doc}, + {NULL, NULL} /* sentinel */ +}; + + +/* + * Generic Sexp_Type. It represents SEXP objects at large. + */ +static PyTypeObject Sexp_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.Sexp", /*tp_name*/ + sizeof(SexpObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)Sexp_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + Sexp_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0,//Sexp_str, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + Sexp_methods, /*tp_methods*/ + 0, /*tp_members*/ + 0,//Sexp_getset, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + 0, /*tp_init*/ + 0, /*tp_alloc*/ + 0,//Sexp_new, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ +}; + + +/* + * Closure-type Sexp. + */ + +static SexpObject* newSexpObject(SEXP); +static SEXP newSEXP(PyObject *object, int rType); + +/* Evaluate a SEXP. It must be constructed by hand. It raises a Python + exception if an error ocurred in the evaluation */ +SEXP do_eval_expr(SEXP expr_R) { + SEXP res_R; + int error = 0; + PyOS_sighandler_t old_int; + + /* Enable our handler for SIGINT inside the R + interpreter. Otherwise, we cannot stop R calculations, since + SIGINT is only processed between Python bytecodes. Also, save the + Python SIGINT handler because it is necessary to temporally + restore it in user defined I/O Python functions. */ + /* stop_events(); */ + +#ifdef _WIN32 + old_int = PyOS_getsig(SIGBREAK); +#else + old_int = PyOS_getsig(SIGINT); +#endif + python_sigint = old_int; + + signal(SIGINT, interrupt_R); + + interrupted = 0; + //FIXME: evaluate expression in the given + res_R = R_tryEval(expr_R, R_GlobalEnv, &error); + +#ifdef _WIN32 + PyOS_setsig(SIGBREAK, old_int); +#else + PyOS_setsig(SIGINT, old_int); +#endif + + /* start_events(); */ + + if (error) { + if (interrupted) { + PyErr_SetNone(PyExc_KeyboardInterrupt); + //FIXME: handling of interruptions + } else { + EmbeddedR_exception_from_errmessage(); + } + return NULL; + } + + return res_R; +} + + +/* This is the method to call when invoking an 'Sexp' */ +static PyObject * +Sexp_call(PyObject *self, PyObject *args, PyObject *kwds) +{ + SEXP call_R, c_R, res_R; + int largs, lkwds; + + largs = lkwds = 0; + if (args) + largs = PyObject_Length(args); + if (kwds) + lkwds = PyObject_Length(kwds); + if ((largs<0) || (lkwds<0)) + return NULL; + + /* 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); + SETCAR(c_R, ((SexpObject *)self)->sexp); + c_R = CDR(c_R); + + int arg_i; + SEXP tmp_R; + for (arg_i=0; arg_i<largs; arg_i++) { + //FIXME: assert that all are SexpObjects + tmp_R = ((SexpObject *)PyTuple_GetItem(args, arg_i))->sexp; + SETCAR(c_R, tmp_R); + c_R = CDR(c_R); + } + +/* if (!make_kwds(lkwds, kwds, &e)) { */ +/* UNPROTECT(1); */ +/* return NULL; */ +/* } */ + +//FIXME: R_GlobalContext ? + PROTECT(res_R = do_eval_expr(call_R)); + +/* if (!res) { */ +/* UNPROTECT(2); */ +/* return NULL; */ +/* } */ + UNPROTECT(2); + //FIXME: standardize R outputs + extern void Rf_PrintWarnings(void); + Rf_PrintWarnings(); /* show any warning messages */ + + PyObject *res = (PyObject *)newSexpObject(res_R); + return res; +} + + + + +static SexpObject* +Sexp_closureEnv(PyObject *self) +{ + SEXP closureEnv = CLOENV(((SexpObject*)self)->sexp); + return newSexpObject(closureEnv); +} +PyDoc_STRVAR(Sexp_closureEnv_doc, + "\n\ +Returns the environment the object is defined in.\ +This corresponds to the C-level function CLOENV(SEXP)."); + +static PyMethodDef ClosureSexp_methods[] = { + {"closureEnv", (PyCFunction)Sexp_closureEnv, METH_NOARGS, + Sexp_closureEnv_doc}, + {NULL, NULL} /* sentinel */ +}; + +//FIXME: write more doc +PyDoc_STRVAR(ClosureSexp_Type_doc, +"A R object that is a closure, that is a function. \ +In R a function a function is defined in an enclosing \ +environement, thus the name of closure. \ +\n\ +The closure can be accessed with the method 'closureEnv'.\ +"); + +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.ClosureSexp", /*tp_name*/ + sizeof(SexpObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + Sexp_call, /*tp_call*/ + 0,//Sexp_str, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + ClosureSexp_methods, /*tp_methods*/ + 0, /*tp_members*/ + 0,//Sexp_getset, /*tp_getset*/ + &Sexp_Type, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + 0, /*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) +{ + int rType = -1; + PyObject *seq = 0; + if (!PyArg_ParseTuple(args, "iO:new", + &rType, &seq)) + return NULL; + #ifdef VERBOSE + printf("type: %i\n", rType); + #endif + SEXP sexp; + sexp = newSEXP(seq, rType); + PyObject *res = (PyObject *)newSexpObject(sexp); + return res; +} + +static Py_ssize_t VectorSexp_len(PyObject *object) +{ + Py_ssize_t len; + //FIXME: sanity checks. + len = (Py_ssize_t)LENGTH(((SexpObject *)object)->sexp); + return len; +} + +static PySequenceMethods VectorSexp_sequenceMethods = { + (inquiry)VectorSexp_len, /* sq_length */ + 0, /* sq_concat */ + 0, /* sq_repeat */ + //FIXME: implement + 0, //(ssizeargfunc)Sexp_item, /* sq_item */ + //FIXME: implement + 0, //(ssizessizeargfunc)Sexp_slice, /* sq_slice */ + //FIXME: implement + 0, //(ssizeobjargproc)Sexp_ass_item, /* sq_ass_item */ + 0, /* sq_ass_slice */ + 0, /* sq_contains */ + 0, /* sq_inplace_concat */ + 0 /* sq_inplace_repeat */ +}; + +//FIXME: write more doc +PyDoc_STRVAR(VectorSexp_Type_doc, +"An R object that is a vector.\ + R vectors start their indexing at one,\ + while Python lists or arrays start indexing\ + at zero.\ +\n\ +In the hope to avoid confusion, the indexing\ + from the Python subset operator (__getitem__)\ + is done at zero."); +/* ", while an other method to perform\ */ +/* it at one is provided (_not yet implemented_).\ */ +/* That other method is also performing indexing."); */ +//FIXME: implement offset-one indexing. + +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.VectorSexp", /*tp_name*/ + sizeof(SexpObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + &VectorSexp_sequenceMethods, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0,//Sexp_str, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + VectorSexp_Type_doc, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0,//Sexp_getset, /*tp_getset*/ + &Sexp_Type, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + 0, /*tp_init*/ + 0, /*tp_alloc*/ + VectorSexp_new, /*tp_new*/ + 0, /*tp_free*/ + 0 /*tp_is_gc*/ +}; + + +//FIXME: write more doc +PyDoc_STRVAR(EnvironmentSexp_Type_doc, +"An R object that is an environment.\ + R environments can be seen as similar to Python\ + dictionnaries, with the twist that looking for\ + a key can be recursively propagated to the enclosing\ + environment whenever the key is not found.\ +\n\ + The subsetting operator is made to match Python's\ + behavior, that is the enclosing environment are not\ + inspect upon absence of a given key.\ +"); + +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.EnvironmentSexp", /*tp_name*/ + sizeof(SexpObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0,//Sexp_str, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + EnvironmentSexp_Type_doc, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0,//Sexp_getset, /*tp_getset*/ + &Sexp_Type, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + 0, /*tp_init*/ + 0, /*tp_alloc*/ + //FIXME: add new method + 0, //EnvironmentSexp_new, /*tp_new*/ + 0, /*tp_free*/ + 0 /*tp_is_gc*/ +}; + + +//FIXME: write more doc +PyDoc_STRVAR(S4Sexp_Type_doc, +"An 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.S4Sexp", /*tp_name*/ + sizeof(SexpObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0,//Sexp_str, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + S4Sexp_Type_doc, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0,//Sexp_getset, /*tp_getset*/ + &Sexp_Type, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + 0, /*tp_init*/ + 0, /*tp_alloc*/ + //FIXME: add new method + 0, //S4Sexp_new, /*tp_new*/ + 0, /*tp_free*/ + 0 /*tp_is_gc*/ +}; + + + +/* --- Create a SEXP object --- */ +static SexpObject* +newSexpObject(SEXP sexp) +{ + SexpObject *object; + SEXP env_R; + + //FIXME: let the possibility to manipulate un-evaluated promises ? + if (TYPEOF(sexp) == PROMSXP) { + #ifdef VERBOSE + printf("evaluating promise..."); + #endif + env_R = PRENV(sexp); + sexp = eval(sexp, env_R); + #ifdef VERBOSE + printf("done.\n"); + #endif + } + + switch (TYPEOF(sexp)) { + case CLOSXP: + object = (SexpObject *)_PyObject_New(&ClosureSexp_Type); + break; + //FIXME: handle other callable types ? + //case SPECIALSXP: + //callable type + //break; + //case BUILTINSXP: + //callable type + //break; + case REALSXP: + case INTSXP: + case LGLSXP: + case STRSXP: + object = (SexpObject *)_PyObject_New(&VectorSexp_Type); + break; + case ENVSXP: + object = (SexpObject *)_PyObject_New(&EnvironmentSexp_Type); + break; + case S4SXP: + object = (SexpObject *)_PyObject_New(&S4Sexp_Type); + break; + default: + object = (SexpObject *)_PyObject_New(&Sexp_Type); + break; + } + if (!object) + PyErr_NoMemory(); + object->sexp = sexp; + if (sexp) + R_PreserveObject(sexp); + return object; +} + +static SEXP +newSEXP(PyObject *object, int rType) +{ + SEXP sexp; + PyObject *seq_object, *item; + seq_object = PySequence_Fast(object, "Cannot create" + " R object from non-sequence Python object."); + if (! seq_object) + return NULL; + + const Py_ssize_t length = PySequence_Fast_GET_SIZE(seq_object); + //FIXME: PROTECT THIS + #ifdef VERBOSE + printf("size: %i", length); + #endif + sexp = allocVector(rType, length); + + int i; + + switch(rType) { + case REALSXP: + for (i = 0; i < length; ++i) { + if((item = PyNumber_Float(PySequence_Fast_GET_ITEM(seq_object, i)))) { + REAL(sexp)[i] = PyFloat_AS_DOUBLE(item); + Py_DECREF(item); + } + else { + PyErr_Clear(); + REAL(sexp)[i] = NA_REAL; + } + } + break; + case INTSXP: + for (i = 0; i < length; ++i) { + if((item = PyNumber_Int(PySequence_Fast_GET_ITEM(seq_object, i)))) { + long l = PyInt_AS_LONG(item); + INTEGER(sexp)[i] = (l<=INT_MAX && l>=INT_MIN)?l:NA_INTEGER; + Py_DECREF(item); + } + else { + PyErr_Clear(); + INTEGER(sexp)[i] = NA_INTEGER; + } + } + break; + case LGLSXP: + for (i = 0; i < length; ++i) { + int q = PyObject_IsTrue(PySequence_Fast_GET_ITEM(seq_object, i)); + if (q != -1) + LOGICAL(sexp)[i] = q; + else { + PyErr_Clear(); + LOGICAL(sexp)[i] = NA_LOGICAL; + } + } + break; + case STRSXP: + for (i = 0; i < length; ++i) { + if((item = PyObject_Str(PySequence_Fast_GET_ITEM(seq_object, i)))) { + SEXP str_R = mkChar(PyString_AS_STRING(item)); + if (!str_R) { + PyErr_NoMemory(); + sexp = NULL; + break; + } + SET_STRING_ELT(sexp, i, str_R); + } + else { + PyErr_Clear(); + SET_STRING_ELT(sexp, i, NA_STRING); + } + } + break; + default: + PyErr_Format(PyExc_ValueError, "cannot handle type %d", rType); + sexp = NULL; + } + return sexp; +} + + + +static PyObject* +EmbeddedR_newSexpObject(SEXP sexp) +{ + SexpObject *res; + + return (PyObject *)res; +} + +//ClosureSexp_Type.tp_call = &Sexp_call; +//ClosureSexp_Type.tp_call = 0; + + +//(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 --- */ + + +static SexpObject* +EmbeddedR_findVar(PyObject *self, PyObject *args) +//EmbeddedR_findVar(PyTypeObject *type, PyObject *args) +{ + char *name; + SEXP rho = R_GlobalEnv, res; + PyObject *ErrorObject; + + if (!PyArg_ParseTuple(args, "s", &name)) { + //, "s|O&", &name, Get_SEXP, &rho)) { + return NULL; + } + res = findVar(install(name), rho); + if (res != R_UnboundValue) { + #ifdef VERBOSE + printf("found.\n"); + #endif + return newSexpObject(res); + } + PyErr_Format(ErrorObject, "'%s' not found", name); + return NULL; +} +PyDoc_STRVAR(EmbeddedR_findVar_doc, + "Find a variable in R's .GlobalEnv."); + + + + +/* --- List of functions defined in the module --- */ + +static PyMethodDef EmbeddedR_methods[] = { + {"initEmbeddedR", (PyCFunction)EmbeddedR_init, METH_VARARGS, + EmbeddedR_init_doc}, + {"endEmbeddedR", (PyCFunction)EmbeddedR_end, METH_O, + EmbeddedR_end_doc}, + {"setWriteConsole", (PyCFunction)EmbeddedR_setWriteConsole, METH_NOARGS, + EmbeddedR_setWriteConsole_doc}, + {"findVarEmbeddedR", (PyCFunction)EmbeddedR_findVar, METH_VARARGS, + EmbeddedR_findVar_doc}, + {NULL, NULL} /* sentinel */ +}; + + + + +/* --- Initialize the module ---*/ + +#define ADD_INT_CONSTANT(module, name) PyModule_AddIntConstant(module, #name, name) + +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++. */ + if (PyType_Ready(&Sexp_Type) < 0) + return; + if (PyType_Ready(&ClosureSexp_Type) < 0) + return; + if (PyType_Ready(&VectorSexp_Type) < 0) + return; + + PyObject *m; + m = Py_InitModule3("rinterface", EmbeddedR_methods, module_doc); + if (m == NULL) + return; + + PyModule_AddObject(m, "Sexp", (PyObject *)&Sexp_Type); + PyModule_AddObject(m, "SexpClosure", (PyObject *)&ClosureSexp_Type); + PyModule_AddObject(m, "SexpVector", (PyObject *)&VectorSexp_Type); + + //FIXME: clean the exception stuff + if (ErrorObject == NULL) { + ErrorObject = PyErr_NewException("rinterface.error", NULL, NULL); + if (ErrorObject == NULL) + return; + } + Py_INCREF(ErrorObject); + PyModule_AddObject(m, "RobjectNotFound", ErrorObject); + + + /* Add some symbolic constants to the module */ + ADD_INT_CONSTANT(m, NILSXP); + ADD_INT_CONSTANT(m, SYMSXP); + ADD_INT_CONSTANT(m, LISTSXP); + ADD_INT_CONSTANT(m, CLOSXP); + ADD_INT_CONSTANT(m, ENVSXP); + ADD_INT_CONSTANT(m, PROMSXP); + ADD_INT_CONSTANT(m, LANGSXP); + ADD_INT_CONSTANT(m, SPECIALSXP); + ADD_INT_CONSTANT(m, BUILTINSXP); + ADD_INT_CONSTANT(m, CHARSXP); + ADD_INT_CONSTANT(m, STRSXP); + ADD_INT_CONSTANT(m, LGLSXP); + ADD_INT_CONSTANT(m, INTSXP); + ADD_INT_CONSTANT(m, REALSXP); + ADD_INT_CONSTANT(m, CPLXSXP); + ADD_INT_CONSTANT(m, DOTSXP); + ADD_INT_CONSTANT(m, ANYSXP); + ADD_INT_CONSTANT(m, VECSXP); + ADD_INT_CONSTANT(m, VECSXP); + ADD_INT_CONSTANT(m, EXPRSXP); + ADD_INT_CONSTANT(m, BCODESXP); + ADD_INT_CONSTANT(m, EXTPTRSXP); + ADD_INT_CONSTANT(m, RAWSXP); + ADD_INT_CONSTANT(m, S4SXP); +} Property changes on: trunk/sandbox/rpy_nextgen/rinterface/rinterface.c ___________________________________________________________________ Name: svn:executable + * Added: trunk/sandbox/rpy_nextgen/setup.py =================================================================== --- trunk/sandbox/rpy_nextgen/setup.py (rev 0) +++ trunk/sandbox/rpy_nextgen/setup.py 2008-02-23 15:24:21 UTC (rev 404) @@ -0,0 +1,32 @@ + +import os, os.path, sys, shutil +from distutils.core import setup, Extension +from subprocess import Popen, PIPE + +RHOME = os.getenv("R_HOME") +if RHOME is None: + RHOME = Popen(["R", "RHOME"], stdout=PIPE).communicate()[0].strip() + +print('R\'s home is:%s' %RHOME) + +r_libs = [os.path.join(RHOME, 'lib')] + + +rinterface = Extension( + "rinterface", + ["rinterface/rinterface.c", ], + include_dirs=[ os.path.join(RHOME, 'include'),], + libraries=['R'], + library_dirs=r_libs, + runtime_library_dirs=r_libs, + #extra_link_args=[], + ) + +setup(name="rpython", + version="0.0.1", + description="Python interface to the R language", + url="http://rpy.sourceforge.net", + license="GPL", + ext_modules=[rinterface], + #py_modules=['rpython'] + ) Property changes on: trunk/sandbox/rpy_nextgen/setup.py ___________________________________________________________________ Name: svn:executable + * 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