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
[email protected]
https://lists.sourceforge.net/lists/listinfo/rpy-list