Revision: 567 http://rpy.svn.sourceforge.net/rpy/?rev=567&view=rev Author: lgautier Date: 2008-07-02 07:57:48 -0700 (Wed, 02 Jul 2008)
Log Message: ----------- rinterface: - added sketchy systems for locking R when accessed - evaluation of expression in R_GlobalEnv rather than in R_CLOENV(fun_R) seems to be the right thing - added test on setClass (as it triggered a problem, and the fix above) - more docstrings Modified Paths: -------------- branches/rpy_nextgen/rpy/rinterface/rinterface.c branches/rpy_nextgen/rpy/rinterface/rinterface.h branches/rpy_nextgen/rpy/rinterface/tests/__init__.py branches/rpy_nextgen/rpy/rinterface/tests/test_SexpClosure.py Modified: branches/rpy_nextgen/rpy/rinterface/rinterface.c =================================================================== --- branches/rpy_nextgen/rpy/rinterface/rinterface.c 2008-06-25 21:31:56 UTC (rev 566) +++ branches/rpy_nextgen/rpy/rinterface/rinterface.c 2008-07-02 14:57:48 UTC (rev 567) @@ -110,11 +110,18 @@ error("Interrupted"); } -/* Helper variable to store whether the embedded R is initialized - * or not. +/* Helper variable to store R's status */ +static unsigned int embeddedR_status = 0; static PyObject *embeddedR_isInitialized; +inline void embeddedR_setlock() { + embeddedR_status = embeddedR_status | RPY_R_BUSY; +} +inline void embeddedR_freelock() { + embeddedR_status = embeddedR_status ^ RPY_R_BUSY; +} + /* The Python original SIGINT handler */ PyOS_sighandler_t python_sigint; @@ -219,7 +226,7 @@ static PyObject* EmbeddedR_init(PyObject *self) { - if (PyObject_IsTrue(embeddedR_isInitialized)) { + if (embeddedR_status & RPY_R_INITIALIZED) { PyErr_Format(PyExc_RuntimeError, "R can only be initialized once."); return NULL; } @@ -242,6 +249,7 @@ setup_Rmainloop(); Py_XDECREF(embeddedR_isInitialized); + embeddedR_status = RPY_R_INITIALIZED; embeddedR_isInitialized = Py_True; Py_INCREF(Py_True); @@ -316,7 +324,7 @@ EmbeddedR_exception_from_errmessage(void) { SEXP expr, res; - //PROTECT(GetErrMessage_SEXP); + //PROTECT(GetErrMessage_SEXP) PROTECT(expr = allocVector(LANGSXP, 1)); SETCAR(expr, GetErrMessage_SEXP); PROTECT(res = Rf_eval(expr, R_GlobalEnv)); @@ -606,7 +614,6 @@ int error = 0; PyOS_sighandler_t old_int; - //FIXME: if env_R is null, use R_BaseEnv //shouldn't it be R_GlobalContext (but then it throws a NULL error) ? if (isNull(env_R)) { @@ -630,19 +637,17 @@ python_sigint = old_int; signal(SIGINT, interrupt_R); - + interrupted = 0; //FIXME: evaluate expression in the given res_R = R_tryEval(expr_R, env_R, &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); @@ -652,7 +657,6 @@ } return NULL; } - return res_R; } @@ -661,6 +665,13 @@ static PyObject * Sexp_call(PyObject *self, PyObject *args, PyObject *kwds) { + + if (embeddedR_status & RPY_R_BUSY) { + PyErr_Format(PyExc_RuntimeError, "Concurrent access to R is not allowed."); + return NULL; + } + embeddedR_setlock(); + SEXP call_R, c_R, res_R; int largs, lkwds; SEXP tmp_R, fun_R; @@ -672,6 +683,7 @@ lkwds = PyObject_Length(kwds); if ((largs<0) || (lkwds<0)) { PyErr_Format(PyExc_ValueError, "Negative number of parameters !?."); + embeddedR_freelock(); return NULL; } @@ -756,10 +768,10 @@ } Py_XDECREF(citems); } - + //FIXME: R_GlobalContext ? - //PROTECT(res_R = do_eval_expr(call_R, R_GlobalEnv)); - PROTECT(res_R = do_eval_expr(call_R, CLOENV(fun_R))); + PROTECT(res_R = do_eval_expr(call_R, R_GlobalEnv)); + //PROTECT(res_R = do_eval_expr(call_R, CLOENV(fun_R))); /* if (!res) { */ /* UNPROTECT(2); */ @@ -770,6 +782,7 @@ if (! res_R) { EmbeddedR_exception_from_errmessage(); //PyErr_Format(PyExc_RuntimeError, "Error while running R code"); + embeddedR_freelock(); return NULL; } @@ -778,10 +791,12 @@ Rf_PrintWarnings(); /* show any warning messages */ PyObject *res = (PyObject *)newPySexpObject(res_R); + embeddedR_freelock(); return res; fail: UNPROTECT(1); + embeddedR_freelock(); return NULL; } @@ -798,7 +813,13 @@ PyErr_Format(PyExc_ValueError, "NULL SEXP."); return NULL; } + if (embeddedR_status & RPY_R_BUSY) { + PyErr_Format(PyExc_RuntimeError, "Concurrent access to R is not allowed."); + return NULL; + } + embeddedR_setlock(); closureEnv = CLOENV(sexp); + embeddedR_freelock(); return newPySexpObject(closureEnv); } PyDoc_STRVAR(Sexp_closureEnv_doc, @@ -1242,7 +1263,11 @@ return (PyObject *)res; } PyDoc_STRVAR(EnvironmentSexp_findVar_doc, - "Find an R object in a given environment."); + "Find a name/symbol in the environment, following the chain of enclosing\n" + " environment until either the topmost environment is reached or the name\n" + "is found, and returned the associated object. \n" + "The optional parameter `wantFun` indicates whether functions should be\n" + "returned or not."); static PyMethodDef EnvironmentSexp_methods[] = { {"get", (PyCFunction)EnvironmentSexp_findVar, METH_VARARGS | METH_KEYWORDS, @@ -1277,11 +1302,8 @@ PyErr_Format(PyExc_LookupError, "'%s' not found", name); return NULL; } -PyDoc_STRVAR(EnvironmentSexp_subscript_doc, - "Find an R object in the environment.\n" - "Not all R environment are hash tables, and this may" - " influence performances when doing repeated lookups."); + static int EnvironmentSexp_ass_subscript(PyObject *self, PyObject *key, PyObject *value) { @@ -1362,19 +1384,20 @@ } PyDoc_STRVAR(EnvironmentSexp_Type_doc, -"R object that is an environment.\ - 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\ - behavior, that is the enclosing environments are not\ - inspected upon absence of a given key.\n\ -"); +"R object that is an environment.\n" +"R environments can be seen as similar to Python\n" +"dictionnaries, with the following twists:\n" +"\n" +"- an environment can be a list of frames to sequentially\n" +"search into\n" +"\n" +"- the search can be recursively propagated to the enclosing\n" +"environment whenever the key is not found (in that respect\n" +"they can be seen as scopings).\n" +"\n" +"The subsetting operator \"[\" is made to match Python's\n" +"behavior, that is the enclosing environments are not\n" +"inspected upon absence of a given key.\n"); static int Modified: branches/rpy_nextgen/rpy/rinterface/rinterface.h =================================================================== --- branches/rpy_nextgen/rpy/rinterface/rinterface.h 2008-06-25 21:31:56 UTC (rev 566) +++ branches/rpy_nextgen/rpy/rinterface/rinterface.h 2008-07-02 14:57:48 UTC (rev 567) @@ -8,6 +8,10 @@ //#define RPY_VERBOSE + +const unsigned int RPY_R_INITIALIZED = 0x01; +const unsigned int RPY_R_BUSY = 0x02; + /* Representation of R objects (instances) as instances in Python. */ Modified: branches/rpy_nextgen/rpy/rinterface/tests/__init__.py =================================================================== --- branches/rpy_nextgen/rpy/rinterface/tests/__init__.py 2008-06-25 21:31:56 UTC (rev 566) +++ branches/rpy_nextgen/rpy/rinterface/tests/__init__.py 2008-07-02 14:57:48 UTC (rev 567) @@ -6,6 +6,7 @@ import test_SexpClosure import test_SexpVectorNumeric import test_EmbeddedR +import test_EmbeddedR_multithreaded def suite(): @@ -15,12 +16,15 @@ suite_SexpClosure = test_SexpClosure.suite() suite_SexpVectorNumeric = test_SexpVectorNumeric.suite() suite_EmbeddedR = test_EmbeddedR.suite() - alltests = unittest.TestSuite([suite_SexpVector, - suite_SexpEnvironment, - suite_Sexp, - suite_SexpClosure, - suite_SexpVectorNumeric, - suite_EmbeddedR]) + #suite_EmbeddedR_multithreaded = test_EmbeddedR_multithreaded.suite() + alltests = unittest.TestSuite([suite_SexpVector + ,suite_SexpEnvironment + ,suite_Sexp + ,suite_SexpClosure + ,suite_SexpVectorNumeric + ,suite_EmbeddedR + # suite_EmbeddedR_multithreaded + ]) return alltests def main(): Modified: branches/rpy_nextgen/rpy/rinterface/tests/test_SexpClosure.py =================================================================== --- branches/rpy_nextgen/rpy/rinterface/tests/test_SexpClosure.py 2008-06-25 21:31:56 UTC (rev 566) +++ branches/rpy_nextgen/rpy/rinterface/tests/test_SexpClosure.py 2008-07-02 14:57:48 UTC (rev 567) @@ -9,7 +9,7 @@ class SexpClosureTestCase(unittest.TestCase): - #def setUpt(self): + #def setUp(self): # rinterface.initEmbeddedR("foo", "--no-save") #def tearDown(self): @@ -45,6 +45,22 @@ self.assertEquals('b', fun(vec)[0]) + def testCallS4SetClass(self): + # R's package "methods" can perform uncommon operations + r_setClass = rinterface.globalEnv.get('setClass') + r_representation = rinterface.globalEnv.get('representation') + attrnumeric = rinterface.SexpVector(["numeric", ], + rinterface.STRSXP) + classname = rinterface.SexpVector(['Track', ], rinterface.STRSXP) + classrepr = r_representation(x = attrnumeric, + y = attrnumeric) + r_setClass(classname, + classrepr) + + + + + def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(SexpClosureTestCase) return suite This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ------------------------------------------------------------------------- Sponsored by: SourceForge.net Community Choice Awards: VOTE NOW! Studies have shown that voting for your favorite open source project, along with a healthy diet, reduces your potential for chronic lameness and boredom. Vote Now at http://www.sourceforge.net/community/cca08 _______________________________________________ rpy-list mailing list rpy-list@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/rpy-list