Revision: 614 http://rpy.svn.sourceforge.net/rpy/?rev=614&view=rev Author: lgautier Date: 2008-08-04 19:17:23 +0000 (Mon, 04 Aug 2008)
Log Message: ----------- New function to allow Python callback for R console input Modified Paths: -------------- branches/rpy_nextgen/NEWS branches/rpy_nextgen/rpy/rinterface/__init__.py branches/rpy_nextgen/rpy/rinterface/rinterface.c branches/rpy_nextgen/rpy/rinterface/tests/test_EmbeddedR.py branches/rpy_nextgen/setup.py Modified: branches/rpy_nextgen/NEWS =================================================================== --- branches/rpy_nextgen/NEWS 2008-08-03 18:14:48 UTC (rev 613) +++ branches/rpy_nextgen/NEWS 2008-08-04 19:17:23 UTC (rev 614) @@ -1,4 +1,22 @@ +SVN +=== +New features +------------ + +:mod:`rpy2.rinterface`: + +- :func:`setReadConsole`: specify Python callback for console input + +Changes +------- + +:mod:`rpy2.rinterface`: + +- underlying handling of interruptions is being worked on + + + Release 2.0.0a2 =============== Modified: branches/rpy_nextgen/rpy/rinterface/__init__.py =================================================================== --- branches/rpy_nextgen/rpy/rinterface/__init__.py 2008-08-03 18:14:48 UTC (rev 613) +++ branches/rpy_nextgen/rpy/rinterface/__init__.py 2008-08-04 19:17:23 UTC (rev 614) @@ -66,3 +66,11 @@ print(x) setWriteConsole(consolePrint) + +def consoleRead(prompt): + input = raw_input(prompt) + input += "\n" + return input + +setReadConsole(consoleRead) + Modified: branches/rpy_nextgen/rpy/rinterface/rinterface.c =================================================================== --- branches/rpy_nextgen/rpy/rinterface/rinterface.c 2008-08-03 18:14:48 UTC (rev 613) +++ branches/rpy_nextgen/rpy/rinterface/rinterface.c 2008-08-04 19:17:23 UTC (rev 614) @@ -202,7 +202,7 @@ arglist = Py_BuildValue("(s)", buf); if (! arglist) { PyErr_NoMemory(); - signal(SIGINT, old_int); +/* signal(SIGINT, old_int); */ //return NULL; } @@ -213,7 +213,7 @@ result = PyEval_CallObject(writeConsoleCallback, arglist); Py_DECREF(arglist); - signal(SIGINT, old_int); +/* signal(SIGINT, old_int); */ if (result == NULL) { return; @@ -223,7 +223,95 @@ } +static PyObject* readConsoleCallback = NULL; +static PyObject* EmbeddedR_setReadConsole(PyObject *self, + PyObject *args) +{ + + PyObject *result = NULL; + PyObject *function; + + if ( PyArg_ParseTuple(args, "O:console", + &function)) { + + if (!PyCallable_Check(function)) { + PyErr_SetString(PyExc_TypeError, "parameter must be callable"); + return NULL; + } + + Py_XDECREF(readConsoleCallback); + Py_XINCREF(function); + readConsoleCallback = function; + Py_INCREF(Py_None); + result = Py_None; + } else { + PyErr_SetString(PyExc_TypeError, "The parameter should be a callable."); + } + return result; + +} + +PyDoc_STRVAR(EmbeddedR_setReadConsole_doc, + "Use the function to handle R console input."); + + +static void +EmbeddedR_ReadConsole(const char *prompt, unsigned char *buf, + int len, int addtohistory) +{ + PyOS_sighandler_t old_int; + PyObject *arglist; + PyObject *result; + + /* 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); */ + arglist = Py_BuildValue("(s)", prompt); + if (! arglist) { + PyErr_NoMemory(); +/* signal(SIGINT, old_int); */ + //return NULL; + } + + if (readConsoleCallback == NULL) { + Py_DECREF(arglist); + return; + } + + #ifdef RPY_DEBUG_CONSOLE + printf("Callback for console input..."); + #endif + result = PyEval_CallObject(readConsoleCallback, arglist); + #ifdef RPY_DEBUG_CONSOLE + printf("done.(%p)\n", result); + #endif + Py_XDECREF(arglist); + + if (result == NULL) { +/* signal(SIGINT, old_int); */ + return; + } + + char *input_str = PyString_AsString(result); + if (! input_str) { + Py_XDECREF(arglist); + return; + } + + /* Snatched from Rcallbacks.c in JRI */ + int l=strlen(input_str); + strncpy((char *)buf, input_str, (l>len-1)?len-1:l); + buf[(l>len-1)?len-1:l]=0; + /* --- */ + + Py_XDECREF(result); +/* signal(SIGINT, old_int); */ + +} + + /* --- Initialize and terminate an embedded R --- */ /* Should having multiple threads of R become possible, * useful routines could appear here... @@ -247,18 +335,23 @@ } +#ifdef RIF_HAS_RSIGHAND + R_SignalHandlers=0; +#endif /* int status = Rf_initEmbeddedR(n_args, options);*/ - int status = 1; - Rf_initialize_R(n_args, options); + int status = Rf_initialize_R(n_args, options); R_Interactive = TRUE; +#ifdef RIF_HAS_RSIGHAND + R_SignalHandlers=0; +#endif /* Taken from JRI: * disable stack checking, because threads will thow it off */ R_CStackLimit = (uintptr_t) -1; - #ifdef Win32 +#ifdef Win32 setup_term_ui(); - #endif +#endif setup_Rmainloop(); Py_XDECREF(embeddedR_isInitialized); @@ -271,6 +364,8 @@ ptr_R_WriteConsole = EmbeddedR_WriteConsole; R_Outputfile = NULL; R_Consolefile = NULL; + /* Redirect R console input */ + ptr_R_ReadConsole = EmbeddedR_ReadConsole; #endif RPY_SEXP(globalEnv) = R_GlobalEnv; @@ -673,7 +768,7 @@ #endif python_sigint = old_int; - signal(SIGINT, interrupt_R); +/* signal(SIGINT, interrupt_R); */ interrupted = 0; //FIXME: evaluate expression in the given @@ -2081,6 +2176,8 @@ EmbeddedR_end_doc}, {"setWriteConsole", (PyCFunction)EmbeddedR_setWriteConsole, METH_VARARGS, EmbeddedR_setWriteConsole_doc}, + {"setReadConsole", (PyCFunction)EmbeddedR_setReadConsole, METH_VARARGS, + EmbeddedR_setReadConsole_doc}, {"findVarEmbeddedR", (PyCFunction)EmbeddedR_findVar, METH_VARARGS, EmbeddedR_findVar_doc}, {"sexpTypeEmbeddedR", (PyCFunction)EmbeddedR_sexpType, METH_VARARGS, Modified: branches/rpy_nextgen/rpy/rinterface/tests/test_EmbeddedR.py =================================================================== --- branches/rpy_nextgen/rpy/rinterface/tests/test_EmbeddedR.py 2008-08-03 18:14:48 UTC (rev 613) +++ branches/rpy_nextgen/rpy/rinterface/tests/test_EmbeddedR.py 2008-08-04 19:17:23 UTC (rev 614) @@ -20,6 +20,15 @@ self.assertEquals('[1] "3"\n', str.join('', buf)) rinterface.setWriteConsole(rinterface.consolePrint) + def testSetReadConsole(self): + yes = "yes\n" + def sayyes(prompt): + return(yes) + rinterface.setReadConsole(sayyes) + res = rinterface.baseNameSpaceEnv["readline"]() + self.assertEquals(yes.strip(), res[0]) + rinterface.setReadConsole(rinterface.consoleRead) + def testCallErrorWhenEndedR(self): t = rinterface.baseNameSpaceEnv['date'] rinterface.endEmbeddedR(1) Modified: branches/rpy_nextgen/setup.py =================================================================== --- branches/rpy_nextgen/setup.py 2008-08-03 18:14:48 UTC (rev 613) +++ branches/rpy_nextgen/setup.py 2008-08-04 19:17:23 UTC (rev 614) @@ -4,7 +4,7 @@ pack_name = 'rpy2' -pack_version = '2.0.0-a2' +pack_version = '2.0.0-dev' RHOMES = os.getenv('RHOMES') @@ -99,11 +99,13 @@ define_macros.append(('R_INTERFACE_PTRS', 1)) define_macros.append(('CSTACK_DEFNS', 1)) + define_macros.append(('RIF_HAS_RSIGHAND', 1)) # defines for debugging #define_macros.append(('RPY_DEBUG_PRESERVE', 1)) #define_macros.append(('RPY_DEBUG_PROMISE', 1)) #define_macros.append(('RPY_DEBUG_OBJECTINIT', 1)) + #define_macros.append(('RPY_DEBUG_CONSOLE', 1)) rinterface_ext = Extension( 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 Moblin Your Move Developer's challenge Build the coolest Linux based applications with Moblin SDK & win great prizes Grand prize is a trip for two to an Open Source event anywhere in the world http://moblin-contest.org/redirect.php?banner_id=100&url=/ _______________________________________________ rpy-list mailing list rpy-list@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/rpy-list