Revision: 639 http://rpy.svn.sourceforge.net/rpy/?rev=639&view=rev Author: lgautier Date: 2008-08-23 10:15:04 +0000 (Sat, 23 Aug 2008)
Log Message: ----------- rinterface: - Sexp.typeof is now a getter (no longer method) - new method Sexp.rsame (check if the same underlying R object is used) - new getter Sexp.__sexp__ (return opaque C pointer to the underlying R object) documentation: - updated to recent changes - fixes/addition/editing - version is now 2.0.0a3 (as there might be one more alpha, as this might be slipping a couple of weeks behind schedule) Modified Paths: -------------- branches/rpy_nextgen/NEWS branches/rpy_nextgen/doc/source/conf.py branches/rpy_nextgen/doc/source/rinterface.rst branches/rpy_nextgen/doc/source/rlike.rst branches/rpy_nextgen/doc/source/robjects.rst branches/rpy_nextgen/rpy/rinterface/rinterface.c branches/rpy_nextgen/rpy/rinterface/tests/test_Sexp.py branches/rpy_nextgen/rpy/rinterface/tests/test_SexpClosure.py branches/rpy_nextgen/rpy/rinterface/tests/test_SexpEnvironment.py branches/rpy_nextgen/rpy/robjects/tests/testREnvironment.py branches/rpy_nextgen/rpy/robjects/tests/testRObject.py branches/rpy_nextgen/rpy/robjects/tests/testRVector.py branches/rpy_nextgen/rpy/robjects/tests/testRobjects.py Modified: branches/rpy_nextgen/NEWS =================================================================== --- branches/rpy_nextgen/NEWS 2008-08-22 13:50:03 UTC (rev 638) +++ branches/rpy_nextgen/NEWS 2008-08-23 10:15:04 UTC (rev 639) @@ -8,6 +8,14 @@ - :func:`setReadConsole`: specify Python callback for console input +- `R` string vectors can now be built from Python unicode objects + +- getter :attr:`__sexp__` to return an opaque C pointer to the underlying R object + +- method :meth:`rsame` to test if the underlying R objects for two :class:`Sexp` are the same. + +:mod:`rpy2.robjects`: + - R string vectors can now be built from Python unicode objects @@ -18,10 +26,13 @@ - :func:`initEmbeddedR` is only initializing if R is not started (no effect otherwise, and no exception thrown anymore) +- the method :meth:`typeof` was replaced by a Python `getter` :attr:`typeof`. + :mod:`rpy2.robjects`: - :class:`R` remains a singleton, but does not throw an exception when multiple instances are requested + Bugs fixed ---------- @@ -35,8 +46,11 @@ - experimental method :meth:`enclos` was not properly exported +- setup.py was exiting prematurely when R was compiled against an existing BLAS library +- complex vectors should now be handled properly by :mod:`rpy2.rinterface.robjects`. + Release 2.0.0a2 =============== Modified: branches/rpy_nextgen/doc/source/conf.py =================================================================== --- branches/rpy_nextgen/doc/source/conf.py 2008-08-22 13:50:03 UTC (rev 638) +++ branches/rpy_nextgen/doc/source/conf.py 2008-08-23 10:15:04 UTC (rev 639) @@ -45,7 +45,7 @@ # The short X.Y version. version = '2.0' # The full version, including alpha/beta/rc tags. -release = '2.0.0a2' +release = '2.0.0a3' releaselevel = 'alpha' # There are two options for replacing |today|: either, you set today to some Modified: branches/rpy_nextgen/doc/source/rinterface.rst =================================================================== --- branches/rpy_nextgen/doc/source/rinterface.rst 2008-08-22 13:50:03 UTC (rev 638) +++ branches/rpy_nextgen/doc/source/rinterface.rst 2008-08-23 10:15:04 UTC (rev 639) @@ -163,9 +163,14 @@ # output from the R console will now be appended to the list 'buf' rinterface.setWriteConsole(f) + date = rinterface.baseNamespaceEnv['date'] rprint = rinterface.baseNamespaceEnv['print'] - rprint(rinterface.baseNamespaceEnv['date']) + rprint(date()) + # the output is in our list (as defined in the function f above) + print(buf) + + # restore default function rinterface.setWriteConsole(rinterface.consolePrint) @@ -191,20 +196,19 @@ .. class:: Sexp - .. method:: typeof() + .. attribute:: __sexp__ - The internal R type in which an object is stored can be - accessed with the method :meth:`typeof`. + Opaque C pointer to the underlying R object - :rtype: integer + .. attribute:: typeof + Internal R type for the underlying R object .. doctest:: - >>> letters.typeof() + >>> letters.typeof 16 - .. method:: do_slot(name) R objects can be given attributes. In R the function @@ -229,6 +233,13 @@ :rtype: integer + .. method:: rsame(sexp_obj) + + Tell whether the underlying R object for sexp_obj is the same or not. + + :rtype: boolean + + .. .. autoclass:: rpy2.rinterface.Sexp .. :members: @@ -414,7 +425,7 @@ that contains R's base objects: >>> base = rinterface.baseNameSpace ->>> basetypes = [x.typeof() for x in base] +>>> basetypes = [x.typeof for x in base] .. warning:: @@ -438,8 +449,9 @@ >>> rinterface.globalEnv.get("pi")[0] 3.1415926535897931 -The constant pi is defined in the package base, that -is by default in the search path. The call to :meth:`get` will +The constant `pi` is defined in the package `base`, that +is always in the search path (and in the last position, as it is +attached first). The call to :meth:`get` will look for `pi` first in `globalEnv`, then in the next environment in the search path and repeat this until an object is found or the sequence of environments to explore is exhausted. @@ -456,8 +468,8 @@ File "<stdin>", line 1, in <module> LookupError: 'pi' not found -`R` can look specifically for functions, this is the case when -a function call is performed. +`R` can look specifically for functions, which is happening when +a parsed function call is evaluated. The following example of an `R` interactive session should demonstrate it: .. code-block:: r @@ -482,17 +494,90 @@ 'hohoho' >>> ri.globalEnv.get("date", wantFun=True) <rinterface.SexpClosure - Python:0x7f142aa96198 / R:0x16e9500> ->>> ri.globalEnv.get("date", wantFun=True)()[0] +>>> date = ri.globalEnv.get("date", wantFun=True) +>>> date()[0] 'Sat Aug 9 15:48:42 2008' +R packages as environments +^^^^^^^^^^^^^^^^^^^^^^^^^^ +In a `Python` programmer's perspective, it would be nice to map loaded `R` +packages as modules and provide access to `R` objects in packages the +same way than `Python` object in modules are accessed. + +This is unfortunately not possible in a robust way: the dot character `.` +can be used for symbol names in R (like pretty much any character), and +this can prevent an exact correspondance between `R` and `Python` names. +`rpy` uses transformation functions that translates '.' to '_' and back, +but this can lead to complications since '_' can also be used for R symbols. + +There is a way to provide explict access to object in R packages, since +loaded packages can be considered as environments. + +For example, we can reimplement in `Python` the `R` function +returning the search path (`search`). + +.. code-block:: python + + def rsearch(): + """ Return a list of package environments corresponding to the + R search path. """ + emptyenv = ri.baseNameSpaceEnv.get('emptyenv')() + spath = [ri.globalEnv, ] + item = ri.globalEnv.enclos() + while not item.rsame(emptyenv): + spath.append(item) + item = item.enclos() + spath.append(ri.baseNameSpaceEnv) + return spath + + +As an other example, one can implement simply a function that +returns from which environment an object called by :meth:`get` comes +from. + +.. code-block:: python + + def wherefrom(name, startenv=ri.globalEnv): + """ when calling 'get', where the R object is coming from. """ + emptyenv = ri.baseNameSpaceEnv.get('emptyenv')() + env = startenv + obj = None + retry = True + while retry: + try: + obj = env[name] + retry = False + except LookupError, knf: + env = env.enclos() + if env.rsame(emptyenv): + retry = False + else: + retry = True + return env + + +>>> wherefrom('plot').do_slot('name')[0] +'package:graphics' +>>> wherefrom('help').do_slot('name')[0] +'package:utils' + +.. note:: + There is a gotcha: the base package does not have a name. + + >>> wherefrom('get').do_slot('name')[0] + Traceback (most recent call last): + File "<stdin>", line 1, in <module> + LookupError: The object has no such attribute. + .. index:: single: closure single: SexpClosure single: rinterface; SexpClosure pair: rinterface; function + :class:`SexpClosure` -------------------- @@ -511,7 +596,7 @@ .. index:: - single: rcall + single: rcall; order of parameters .. rubric:: Order for named parameters @@ -535,7 +620,6 @@ >>> [x for x in rl.do_slot("names")] ['x', '', 'y'] - .. index:: single: closureEnv @@ -551,7 +635,6 @@ >>> [x for x in envplot_ls] >>> - :class:`SexpS4` --------------- Modified: branches/rpy_nextgen/doc/source/rlike.rst =================================================================== --- branches/rpy_nextgen/doc/source/rlike.rst 2008-08-22 13:50:03 UTC (rev 638) +++ branches/rpy_nextgen/doc/source/rlike.rst 2008-08-23 10:15:04 UTC (rev 639) @@ -15,11 +15,17 @@ +.. module:: rpy2.rlike.container + Containers ========== -.. module:: rpy2.rlike.container +The module contains data collection-type data structures. +:class:`ArgsDict` and :class:`TaggedList` are structures +with which containeed items/elements can be tagged. +The module can be imported as follows: + >>> import rpy2.rlike.container as rlc Modified: branches/rpy_nextgen/doc/source/robjects.rst =================================================================== --- branches/rpy_nextgen/doc/source/robjects.rst 2008-08-22 13:50:03 UTC (rev 638) +++ branches/rpy_nextgen/doc/source/robjects.rst 2008-08-23 10:15:04 UTC (rev 639) @@ -418,12 +418,12 @@ Once this is done, we can verify immediately that this is working with: >>> pi = robjects.r.pi ->> type(pi) +>>> type(pi) <type 'float'> >>> -The docstrings for :meth:`default_ri2py`, :meth:`default_py2ri`, and :meth:`ri2py` are: +The docstrings for :meth:`default_ri2py`, :meth:`default_py2ri`, and :meth:`py2ro` are: .. autofunction:: rpy2.robjects.default_ri2py .. autofunction:: rpy2.robjects.default_py2ri @@ -458,7 +458,8 @@ .. note:: Since the named parameters are a Python :class:`dict`, - the order of the parameters is lost. Check :meth:`rpy2.rinterface.rcall` + the order of the parameters is lost. + Check :meth:`rpy2.rinterface.SexpClosure.rcall` to know how to keep the order of parameters. Linear models Modified: branches/rpy_nextgen/rpy/rinterface/rinterface.c =================================================================== --- branches/rpy_nextgen/rpy/rinterface/rinterface.c 2008-08-22 13:50:03 UTC (rev 638) +++ branches/rpy_nextgen/rpy/rinterface/rinterface.c 2008-08-23 10:15:04 UTC (rev 639) @@ -443,6 +443,8 @@ * Access to R objects through Python objects */ +staticforward PyTypeObject Sexp_Type; + static void Sexp_clear(PySexpObject *self) { @@ -500,7 +502,7 @@ static PyObject* -Sexp_typeof(PyObject *self) +Sexp_typeof_get(PyObject *self) { PySexpObject *pso = (PySexpObject*)self; SEXP sexp = RPY_SEXP(pso); @@ -511,8 +513,7 @@ return PyInt_FromLong(TYPEOF(sexp)); } PyDoc_STRVAR(Sexp_typeof_doc, - "\n\ - Returns the R internal SEXPREC type."); + "R internal SEXPREC type."); static PyObject* @@ -561,20 +562,76 @@ This method corresponds to the macro NAMED.\n\ See the R-extensions manual for further details."); +static PyObject* +Sexp_sexp_get(PyObject *self) +{ + SEXP sexp = RPY_SEXP(((PySexpObject*)self)); + if (! sexp) { + PyErr_Format(PyExc_ValueError, "NULL SEXP."); + return NULL;; + } + + PyObject *res = PyCObject_FromVoidPtr(sexp, NULL); + return res; +} +PyDoc_STRVAR(Sexp_sexp_doc, + "Opaque C pointer to the underlying R object"); + +static PyObject* +Sexp_rsame(PyObject *self, PyObject *other) +{ + + if (! PyObject_IsInstance(other, + (PyObject*)&Sexp_Type)) { + PyErr_Format(PyExc_ValueError, + "Can only compare Sexp objects."); + return NULL; + } + + SEXP sexp_self = RPY_SEXP(((PySexpObject*)self)); + if (! sexp_self) { + PyErr_Format(PyExc_ValueError, "NULL SEXP."); + return NULL;; + } + + SEXP sexp_other = RPY_SEXP(((PySexpObject*)other)); + if (! sexp_other) { + PyErr_Format(PyExc_ValueError, "NULL SEXP."); + return NULL;; + } + + long same = (sexp_self == sexp_other); + return PyBool_FromLong(same); +} +PyDoc_STRVAR(Sexp_rsame_doc, + "Are the two object representing the same underlying R object."); + + static PyMethodDef Sexp_methods[] = { - {"typeof", (PyCFunction)Sexp_typeof, METH_NOARGS, - Sexp_typeof_doc}, {"do_slot", (PyCFunction)Sexp_do_slot, METH_O, Sexp_do_slot_doc}, + {"rsame", (PyCFunction)Sexp_rsame, METH_O, + Sexp_rsame_doc}, {"named", (PyCFunction)Sexp_named, METH_NOARGS, Sexp_named_doc}, {NULL, NULL} /* sentinel */ }; -staticforward PyTypeObject Sexp_Type; +static PyGetSetDef Sexp_getsets[] = { + {"typeof", + (getter)Sexp_typeof_get, + (setter)0, + Sexp_typeof_doc}, + {"__sexp__", + (getter)Sexp_sexp_get, + (setter)0, + Sexp_sexp_doc}, + {NULL, NULL, NULL, NULL} /* sentinel */ +}; + static PyObject* Sexp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { @@ -711,7 +768,7 @@ 0, /*tp_iternext*/ Sexp_methods, /*tp_methods*/ 0, /*tp_members*/ - 0,//Sexp_getset, /*tp_getset*/ + Sexp_getsets, /*tp_getset*/ 0, /*tp_base*/ 0, /*tp_dict*/ 0, /*tp_descr_get*/ Modified: branches/rpy_nextgen/rpy/rinterface/tests/test_Sexp.py =================================================================== --- branches/rpy_nextgen/rpy/rinterface/tests/test_Sexp.py 2008-08-22 13:50:03 UTC (rev 638) +++ branches/rpy_nextgen/rpy/rinterface/tests/test_Sexp.py 2008-08-23 10:15:04 UTC (rev 639) @@ -28,15 +28,15 @@ self.assertTrue(idem(sexp_new, sexp_new2)[0]) - def testTypeof(self): + def testTypeof_get(self): sexp = rinterface.globalEnv.get("letters") - self.assertEquals(sexp.typeof(), rinterface.STRSXP) + self.assertEquals(sexp.typeof, rinterface.STRSXP) sexp = rinterface.globalEnv.get("pi") - self.assertEquals(sexp.typeof(), rinterface.REALSXP) + self.assertEquals(sexp.typeof, rinterface.REALSXP) sexp = rinterface.globalEnv.get("plot") - self.assertEquals(sexp.typeof(), rinterface.CLOSXP) + self.assertEquals(sexp.typeof, rinterface.CLOSXP) def testDo_slot(self): data_func = rinterface.globalEnv.get("data") @@ -52,6 +52,21 @@ self.assertRaises(LookupError, sexp.do_slot, "foo") + def testSexp_rsame_true(self): + sexp_a = rinterface.globalEnv.get("letters") + sexp_b = rinterface.globalEnv.get("letters") + self.assertTrue(sexp_a.rsame(sexp_b)) + + def testSexp_rsame_false(self): + sexp_a = rinterface.globalEnv.get("letters") + sexp_b = rinterface.globalEnv.get("pi") + self.assertFalse(sexp_a.rsame(sexp_b)) + + def testSexp_rsame_wrongType(self): + sexp_a = rinterface.globalEnv.get("letters") + self.assertRaises(ValueError, sexp_a.rsame, 'foo') + + def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(SexpTestCase) return suite Modified: branches/rpy_nextgen/rpy/rinterface/tests/test_SexpClosure.py =================================================================== --- branches/rpy_nextgen/rpy/rinterface/tests/test_SexpClosure.py 2008-08-22 13:50:03 UTC (rev 638) +++ branches/rpy_nextgen/rpy/rinterface/tests/test_SexpClosure.py 2008-08-23 10:15:04 UTC (rev 639) @@ -17,7 +17,7 @@ def testTypeof(self): sexp = rinterface.globalEnv.get("plot") - self.assertEquals(sexp.typeof(), rinterface.CLOSXP) + self.assertEquals(sexp.typeof, rinterface.CLOSXP) def testRError(self): sum = rinterface.baseNameSpaceEnv["sum"] Modified: branches/rpy_nextgen/rpy/rinterface/tests/test_SexpEnvironment.py =================================================================== --- branches/rpy_nextgen/rpy/rinterface/tests/test_SexpEnvironment.py 2008-08-22 13:50:03 UTC (rev 638) +++ branches/rpy_nextgen/rpy/rinterface/tests/test_SexpEnvironment.py 2008-08-23 10:15:04 UTC (rev 639) @@ -57,12 +57,12 @@ def testGet_functionOnly(self): hist = rinterface.globalEnv.get("hist", wantFun = False) - self.assertEquals(rinterface.CLOSXP, hist.typeof()) + self.assertEquals(rinterface.CLOSXP, hist.typeof) rinterface.globalEnv["hist"] = rinterface.SexpVector(["foo", ], rinterface.STRSXP) hist = rinterface.globalEnv.get("hist", wantFun = True) - self.assertEquals(rinterface.CLOSXP, hist.typeof()) + self.assertEquals(rinterface.CLOSXP, hist.typeof) def testSubscript(self): Modified: branches/rpy_nextgen/rpy/robjects/tests/testREnvironment.py =================================================================== --- branches/rpy_nextgen/rpy/robjects/tests/testREnvironment.py 2008-08-22 13:50:03 UTC (rev 638) +++ branches/rpy_nextgen/rpy/robjects/tests/testREnvironment.py 2008-08-23 10:15:04 UTC (rev 639) @@ -6,7 +6,7 @@ class REnvironmentTestCase(unittest.TestCase): def testNew(self): env = robjects.REnvironment() - self.assertEquals(rinterface.ENVSXP, env.typeof()) + self.assertEquals(rinterface.ENVSXP, env.typeof) def testNewValueError(self): self.assertRaises(ValueError, robjects.REnvironment, 'a') Modified: branches/rpy_nextgen/rpy/robjects/tests/testRObject.py =================================================================== --- branches/rpy_nextgen/rpy/robjects/tests/testRObject.py 2008-08-22 13:50:03 UTC (rev 638) +++ branches/rpy_nextgen/rpy/robjects/tests/testRObject.py 2008-08-23 10:15:04 UTC (rev 639) @@ -16,7 +16,7 @@ self.assertTrue(identical(ro_v, ri_v)[0]) del(ri_v) - self.assertEquals(rinterface.INTSXP, ro_v.typeof()) + self.assertEquals(rinterface.INTSXP, ro_v.typeof) def testRepr(self): obj = robjects.baseNameSpaceEnv["pi"] Modified: branches/rpy_nextgen/rpy/robjects/tests/testRVector.py =================================================================== --- branches/rpy_nextgen/rpy/robjects/tests/testRVector.py 2008-08-22 13:50:03 UTC (rev 638) +++ branches/rpy_nextgen/rpy/robjects/tests/testRVector.py 2008-08-23 10:15:04 UTC (rev 639) @@ -12,7 +12,7 @@ identical = ri.baseNameSpaceEnv["identical"] py_a = array.array('i', [1,2,3]) ro_v = robjects.RVector(py_a) - self.assertEquals(ro_v.typeof(), ri.INTSXP) + self.assertEquals(ro_v.typeof, ri.INTSXP) ri_v = ri.SexpVector(py_a, ri.INTSXP) ro_v = robjects.RVector(ri_v) @@ -20,7 +20,7 @@ self.assertTrue(identical(ro_v, ri_v)[0]) del(ri_v) - self.assertEquals(ri.INTSXP, ro_v.typeof()) + self.assertEquals(ri.INTSXP, ro_v.typeof) def testAddOperators(self): seq_R = robjects.r["seq"] Modified: branches/rpy_nextgen/rpy/robjects/tests/testRobjects.py =================================================================== --- branches/rpy_nextgen/rpy/robjects/tests/testRobjects.py 2008-08-22 13:50:03 UTC (rev 638) +++ branches/rpy_nextgen/rpy/robjects/tests/testRobjects.py 2008-08-23 10:15:04 UTC (rev 639) @@ -67,39 +67,39 @@ py = 1 rob = robjects.default_py2ro(py) self.assertTrue(isinstance(rob, robjects.RVector)) - self.assertEquals(rinterface.INTSXP, rob.typeof()) + self.assertEquals(rinterface.INTSXP, rob.typeof) def testMapperPy2R_boolean(self): py = True rob = robjects.default_py2ro(py) self.assertTrue(isinstance(rob, robjects.RVector)) - self.assertEquals(rinterface.LGLSXP, rob.typeof()) + self.assertEquals(rinterface.LGLSXP, rob.typeof) def testMapperPy2R_str(self): py = 'houba' rob = robjects.default_py2ro(py) self.assertTrue(isinstance(rob, robjects.RVector)) - self.assertEquals(rinterface.STRSXP, rob.typeof()) + self.assertEquals(rinterface.STRSXP, rob.typeof) def testMapperPy2R_unicode(self): py = u'houba' self.assertTrue(isinstance(py, unicode)) rob = robjects.default_py2ro(py) self.assertTrue(isinstance(rob, robjects.RVector)) - self.assertEquals(rinterface.STRSXP, rob.typeof()) + self.assertEquals(rinterface.STRSXP, rob.typeof) #FIXME: more tests def testMapperPy2R_float(self): py = 1.0 rob = robjects.default_py2ro(py) self.assertTrue(isinstance(rob, robjects.RVector)) - self.assertEquals(rinterface.REALSXP, rob.typeof()) + self.assertEquals(rinterface.REALSXP, rob.typeof) def testMapperPy2R_complex(self): py = 1.0 + 2j rob = robjects.default_py2ro(py) self.assertTrue(isinstance(rob, robjects.RVector)) - self.assertEquals(rinterface.CPLXSXP, rob.typeof()) + self.assertEquals(rinterface.CPLXSXP, rob.typeof) def testOverride_ri2py(self): 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