Revision: 640 http://rpy.svn.sourceforge.net/rpy/?rev=640&view=rev Author: lgautier Date: 2008-08-24 13:47:05 +0000 (Sun, 24 Aug 2008)
Log Message: ----------- rinterface: - Sexp.named is not a getter (no longer a method) - fixes for LANGSXP and EXPRSXP rlike: - TaggedList.sort() implemented - new module 'functional' - new module 'indexing' Still misc. editing of the documentation Modified Paths: -------------- branches/rpy_nextgen/NEWS branches/rpy_nextgen/doc/source/overview.rst branches/rpy_nextgen/doc/source/rinterface.rst branches/rpy_nextgen/doc/source/rlike.rst branches/rpy_nextgen/rpy/rinterface/rinterface.c branches/rpy_nextgen/rpy/rinterface/tests/__init__.py branches/rpy_nextgen/rpy/rinterface/tests/test_EmbeddedR.py branches/rpy_nextgen/rpy/rinterface/tests/test_SexpVector.py branches/rpy_nextgen/rpy/rlike/container.py branches/rpy_nextgen/rpy/rlike/tests/__init__.py branches/rpy_nextgen/rpy/rlike/tests/test_container.py Added Paths: ----------- branches/rpy_nextgen/rpy/rlike/functional.py branches/rpy_nextgen/rpy/rlike/indexing.py branches/rpy_nextgen/rpy/rlike/tests/test_functional.py branches/rpy_nextgen/rpy/rlike/tests/test_indexing.py Modified: branches/rpy_nextgen/NEWS =================================================================== --- branches/rpy_nextgen/NEWS 2008-08-23 10:15:04 UTC (rev 639) +++ branches/rpy_nextgen/NEWS 2008-08-24 13:47:05 UTC (rev 640) @@ -13,12 +13,20 @@ - 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 +:mod:`rpy2.rlike`: +- module :mod:`functional` with the functions :func:`tapply`, :func:`listify`, :func:`iterify`. + +- module :mod:`indexing` with the function :func:`order` + +- method :meth:`TaggedList.sort` now implemented + + Changes ------- @@ -26,8 +34,14 @@ - :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`. - +- the method :meth:`Sexp.typeof` was replaced by a Python `getter` :attr:`typeof`. + +- the method :meth:`Sexp.named` was replaced by a Python `getter` :attr:`named`. + +- R objects of type LANGSXP are now one kind of vector (... but this may change again) + +- R objects of type EXPRSXP are now handled as vectors (... but this may change again) + :mod:`rpy2.robjects`: - :class:`R` remains a singleton, but does not throw an exception when multiple instances are requested @@ -36,13 +50,13 @@ Bugs fixed ---------- -- Unable to compile on Python2.4 (definition of aliases to Python2.5-specific were not where they should be). +- unable to compile on Python2.4 (definition of aliases to Python2.5-specific were not where they should be). -- Overflow issues on Python 2.4/64 bits when indexing R vector with very large integers. +- overflow issues on Python 2.4/64 bits when indexing R vector with very large integers. -- Handling of negative indexes for :class:`SexpVector`'s :meth:`__getitem__` and :meth:`__setitem__` was missing +- handling of negative indexes for :class:`SexpVector`'s :meth:`__getitem__` and :meth:`__setitem__` was missing -- Trying to create an instance of :class:`SexpVector` before initializing R raises a RuntimeException (used to segfault) +- trying to create an instance of :class:`SexpVector` before initializing R raises a RuntimeException (used to segfault) - experimental method :meth:`enclos` was not properly exported @@ -83,9 +97,9 @@ - R stack checking is disabled (no longer crashes when multithreading) -- Fixed missing R_PreserveObject for vectors (causing R part of the object to sometimes vanish during garbage collection) +- fixed missing R_PreserveObject for vectors (causing R part of the object to sometimes vanish during garbage collection) -- Prevents calling an R function when R has been ended (raise :class:`RuntimeException`). +- prevents calling an R function when R has been ended (raise :class:`RuntimeException`). Release 2.0.0a1 @@ -133,7 +147,7 @@ :mod:`rpy2.robjects`: -- Fixed string representation of R object on Microsoft Windows (using fifo, not available on win32) +- fixed string representation of R object on Microsoft Windows (using fifo, not available on win32) - :meth:`__getattr__` for :class:`RS4` is now using :meth:`ri2py` @@ -144,4 +158,4 @@ Release 1.0a0 ============= -- First public release \ No newline at end of file +- first public release \ No newline at end of file Modified: branches/rpy_nextgen/doc/source/overview.rst =================================================================== --- branches/rpy_nextgen/doc/source/overview.rst 2008-08-23 10:15:04 UTC (rev 639) +++ branches/rpy_nextgen/doc/source/overview.rst 2008-08-24 13:47:05 UTC (rev 640) @@ -42,8 +42,11 @@ Python version 2.4 or higher, and R-2.7.0 or higher are required. This is developped with R-2.7.1 and Python-2.5.2. -R-2.8.0-dev is sometimes tested, and it does seem to work well. +R-2.8.0-dev is sometimes tested, and it does seem to play well with `rpy2`. +Python-2.6.0-dev is sometimes tested as well, and it seems to pass the same +unit tests Python-2.5 is passing. + Download ^^^^^^^^ Modified: branches/rpy_nextgen/doc/source/rinterface.rst =================================================================== --- branches/rpy_nextgen/doc/source/rinterface.rst 2008-08-23 10:15:04 UTC (rev 639) +++ branches/rpy_nextgen/doc/source/rinterface.rst 2008-08-24 13:47:05 UTC (rev 640) @@ -200,6 +200,12 @@ Opaque C pointer to the underlying R object + .. attribute:: named + + `R` does not count references for its object. This method + returns the `NAMED` value (an integer). + See the R-extensions manual for further details. + .. attribute:: typeof Internal R type for the underlying R object @@ -211,9 +217,9 @@ .. method:: do_slot(name) - R objects can be given attributes. In R the function - *attr* lets one access attribute, while called :meth:`do_slot` - in the C interface to R. + R objects can be given attributes. In R, the function + *attr* lets one access an object's attribute; it is + called :meth:`do_slot` in the C interface to R. :param name: string :rtype: Sexp (or Sexp-inheriting) object @@ -226,13 +232,6 @@ [13, 2] >>> - .. method:: named() - - `R` does not count references for its object. This method - returns the `NAMED` value (see the R-extensions manual). - - :rtype: integer - .. method:: rsame(sexp_obj) Tell whether the underlying R object for sexp_obj is the same or not. @@ -508,8 +507,9 @@ 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, +this can make an exact correspondance between `R` and `Python` names +rather difficult. +:mod:`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 @@ -699,21 +699,46 @@ R types ------- +Vector types +^^^^^^^^^^^^ + +:const:`CPLXSXP` + Complex + :const:`INTSXP` - Integer + Integer. +:const:`LGLSXP` + Boolean (logical in the R terminology) + :const:`REALSXP` Numerical value (float / double) -:const:`LGLSXP` - Boolean (logical in the R terminology) - :const:`STRSXP` String +:const:`VECSXP` + List + +:const:`LANGSXP` + Language object. + +Other types +^^^^^^^^^^^ + +:const:`CLOSXP` + Function with an enclosure. Represented by :class:`rpy2.rinterface.SexpClosure`. + :const:`ENVSXP` - Environment + Environment. Represented by :class:`rpy2.rinterface.SexpEnvironment`. -:const:`CPLXSXP` - Complex +:const:`S4SXP` + Instance of class S4. Represented by :class:`rpy2.rinterface.SexpS4`. + +Types you should not meet +^^^^^^^^^^^^^^^^^^^^^^^^^ + +:const:`PROMSXP` + Promise. + Modified: branches/rpy_nextgen/doc/source/rlike.rst =================================================================== --- branches/rpy_nextgen/doc/source/rlike.rst 2008-08-23 10:15:04 UTC (rev 639) +++ branches/rpy_nextgen/doc/source/rlike.rst 2008-08-24 13:47:05 UTC (rev 640) @@ -94,4 +94,23 @@ The Python docstring for the class is: .. autoclass:: rpy2.rlike.container.TaggedList - :members: \ No newline at end of file + :members: + +Tools for working with sequences +================================ + +.. autofunction:: rpy2.rlike.functional.tapply + +>>> import rpy2.rlike.functional as rlf +>>> rlf.tapply((1,2,3), ('a', 'b', 'a'), sum) +[('a', 4), ('b', 2)] + + +Indexing +======== + +.. function:: rpy2.rlike.indexing.order + +>>> import rpy2.rlike.indexing as rli +>>> rli.order(('a', 'c', 'b')) +[0, 2, 1] Modified: branches/rpy_nextgen/rpy/rinterface/rinterface.c =================================================================== --- branches/rpy_nextgen/rpy/rinterface/rinterface.c 2008-08-23 10:15:04 UTC (rev 639) +++ branches/rpy_nextgen/rpy/rinterface/rinterface.c 2008-08-24 13:47:05 UTC (rev 640) @@ -547,7 +547,7 @@ ":rtype: instance of type or subtype :class:`rpy2.rinterface.Sexp`"); static PyObject* -Sexp_named(PyObject *self) +Sexp_named_get(PyObject *self) { SEXP sexp = RPY_SEXP(((PySexpObject*)self)); if (! sexp) { @@ -558,7 +558,7 @@ return PyInt_FromLong((long)res); } PyDoc_STRVAR(Sexp_named_doc, -"Return the integer code for the R object reference-pseudo counting.\n\ +"Integer code for the R object reference-pseudo counting.\n\ This method corresponds to the macro NAMED.\n\ See the R-extensions manual for further details."); @@ -613,13 +613,15 @@ 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 */ }; static PyGetSetDef Sexp_getsets[] = { + {"named", + (getter)Sexp_named_get, + (setter)0, + Sexp_named_doc}, {"typeof", (getter)Sexp_typeof_get, (setter)0, @@ -1332,6 +1334,7 @@ int vi; Rcomplex vc; const char *vs; + SEXP tmp, sexp_item; /* needed by LANGSXP */ i_R = (R_len_t)i; switch (TYPEOF(*sexp)) { case REALSXP: @@ -1359,8 +1362,16 @@ /* vs = (CHAR(*sexp)[i_R]); */ /* res = PyString_FromStringAndSize(vs, 1); */ case VECSXP: - res = (PyObject *)newPySexpObject(VECTOR_ELT(*sexp, i_R)); + case EXPRSXP: + sexp_item = VECTOR_ELT(*sexp, i_R); + res = (PyObject *)newPySexpObject(sexp_item); break; + case LANGSXP: + tmp = nthcdr(*sexp, i_R); + SETCAR(sexp_item, CAR(tmp)); + SET_TAG(sexp_item, TAG(tmp)); + res = (PyObject *)newPySexpObject(sexp_item); + break; default: PyErr_Format(PyExc_ValueError, "Cannot handle type %d", TYPEOF(*sexp)); @@ -2041,6 +2052,8 @@ case LGLSXP: case CPLXSXP: case VECSXP: + case LANGSXP: + case EXPRSXP: case STRSXP: object = (PySexpObject *)Sexp_new(&VectorSexp_Type, Py_None, Py_None); break; @@ -2050,9 +2063,6 @@ case S4SXP: object = (PySexpObject *)Sexp_new(&S4Sexp_Type, Py_None, Py_None); break; - case LANGSXP: - object = (PySexpObject *)Sexp_new(&LangSexp_Type, Py_None, Py_None); - break; default: object = (PySexpObject *)Sexp_new(&Sexp_Type, Py_None, Py_None); break; Modified: branches/rpy_nextgen/rpy/rinterface/tests/__init__.py =================================================================== --- branches/rpy_nextgen/rpy/rinterface/tests/__init__.py 2008-08-23 10:15:04 UTC (rev 639) +++ branches/rpy_nextgen/rpy/rinterface/tests/__init__.py 2008-08-24 13:47:05 UTC (rev 640) @@ -5,6 +5,7 @@ import test_Sexp import test_SexpClosure import test_SexpVectorNumeric + import test_EmbeddedR #import test_EmbeddedR_multithreaded Modified: branches/rpy_nextgen/rpy/rinterface/tests/test_EmbeddedR.py =================================================================== --- branches/rpy_nextgen/rpy/rinterface/tests/test_EmbeddedR.py 2008-08-23 10:15:04 UTC (rev 639) +++ branches/rpy_nextgen/rpy/rinterface/tests/test_EmbeddedR.py 2008-08-24 13:47:05 UTC (rev 640) @@ -24,7 +24,7 @@ self.assertEquals(yes.strip(), res[0]) rinterface.setReadConsole(rinterface.consoleRead) -#FIXME: end and initializing again causes currently a lot a trouble... +#FIXME: end and initialize again causes currently a lot a trouble... def testCallErrorWhenEndedR(self): self.assertTrue(False) # worked when tested, but calling endEmbeddedR causes trouble t = rinterface.baseNameSpaceEnv['date'] @@ -37,7 +37,8 @@ def testObjectDispatchLang(self): formula = rinterface.globalEnv.get('formula') obj = formula(rinterface.StrSexpVector(['y ~ x', ])) - self.assertTrue(isinstance(obj, rinterface.SexpLang)) + self.assertTrue(isinstance(obj, rinterface.SexpVector)) + self.assertEquals(rinterface.LANGSXP, obj.typeof) def testObjectDispatchVector(self): letters = rinterface.globalEnv.get('letters') Modified: branches/rpy_nextgen/rpy/rinterface/tests/test_SexpVector.py =================================================================== --- branches/rpy_nextgen/rpy/rinterface/tests/test_SexpVector.py 2008-08-23 10:15:04 UTC (rev 639) +++ branches/rpy_nextgen/rpy/rinterface/tests/test_SexpVector.py 2008-08-24 13:47:05 UTC (rev 640) @@ -147,6 +147,21 @@ letters_R = ri.globalEnv.get("letters") self.assertEquals('z', letters_R[-1]) + def testGetItemLang(self): + formula = ri.baseNameSpaceEnv.get('formula') + f = formula(ri.StrSexpVector(['y ~ x', ])) + y = f[0] + self.assertEquals(ri.LANGSXP, y.typeof) + self.assertEquals(1, len(y)) + + def testGetItemExpression(self): + expression = ri.baseNameSpaceEnv.get('expression') + e = expression(ri.StrSexpVector(['a', ]), + ri.StrSexpVector(['b', ])) + y = e[0] + self.assertEquals(ri.STRSXP, y.typeof) + + def testGetItemNegativeOutOfBound(self): letters_R = ri.globalEnv.get("letters") self.assertRaises(IndexError, letters_R.__getitem__, Modified: branches/rpy_nextgen/rpy/rlike/container.py =================================================================== --- branches/rpy_nextgen/rpy/rlike/container.py 2008-08-23 10:15:04 UTC (rev 639) +++ branches/rpy_nextgen/rpy/rlike/container.py 2008-08-24 13:47:05 UTC (rev 640) @@ -1,4 +1,5 @@ import itertools +import rpy2.rlike.indexing as rli class ArgsDict(dict): """ Implements the Ordered Dict API defined in PEP 372. @@ -264,11 +265,15 @@ super(TaggedList, self).reverse() self.__tags.reverse() - def sort(self): - #FIXME: implement - raise Exception("Not yet implemented.") + def sort(self, reverse = False): + """ + Sort in place + """ + o = rli.order(self, reverse = reverse) + super(TaggedList, self).sort(reverse = reverse) + self.__tags = [self.__tags[i] for i in o] - + def tags(self): """ Return a tuple of all tags @@ -289,3 +294,4 @@ """ self.__tags[i] = t + Added: branches/rpy_nextgen/rpy/rlike/functional.py =================================================================== --- branches/rpy_nextgen/rpy/rlike/functional.py (rev 0) +++ branches/rpy_nextgen/rpy/rlike/functional.py 2008-08-24 13:47:05 UTC (rev 640) @@ -0,0 +1,44 @@ +import itertools + + +def tapply(seq, tag, fun): + """ Apply the function `fun` to the items in `seq`, + grouped by the tags defined in `tag`. + + :param seq: sequence + :param tag: any sequence of tags + :param fun: function + :rtype: list + """ + + if len(seq) != len(tag): + raise ValueError("seq and tag should have the same length.") + + tag_grp = {} + for i, t in enumerate(tag): + try: + tag_grp[t].append(i) + except LookupError, le: + tag_grp[t] = [i, ] + + res = [(tag, fun([seq[i] for i in ti])) for tag, ti in tag_grp.items()] + return res + + +def listify(fun): + """ Decorator to make a function apply + to each item in a sequence, and return a list. """ + def f(seq): + res = [fun(x) for x in seq] + return res + return f + +def iterify(fun): + """ Decorator to make a function apply + to each item in a sequence, and return an iterator. """ + def f(seq): + for x in seq: + yield fun(x) + return f + + Property changes on: branches/rpy_nextgen/rpy/rlike/functional.py ___________________________________________________________________ Added: svn:eol-style + native Added: branches/rpy_nextgen/rpy/rlike/indexing.py =================================================================== --- branches/rpy_nextgen/rpy/rlike/indexing.py (rev 0) +++ branches/rpy_nextgen/rpy/rlike/indexing.py 2008-08-24 13:47:05 UTC (rev 640) @@ -0,0 +1,18 @@ + +def order(sortable, reverse = False): + o = range(len(sortable)) + def cmp(x, y): + x = sortable[x] + y = sortable[y] + if x < y: + return -1 + elif x > y: + return +1 + else: + return 0 + + o.sort(cmp = cmp, reverse = reverse) + + return o + + Property changes on: branches/rpy_nextgen/rpy/rlike/indexing.py ___________________________________________________________________ Added: svn:eol-style + native Modified: branches/rpy_nextgen/rpy/rlike/tests/__init__.py =================================================================== --- branches/rpy_nextgen/rpy/rlike/tests/__init__.py 2008-08-23 10:15:04 UTC (rev 639) +++ branches/rpy_nextgen/rpy/rlike/tests/__init__.py 2008-08-24 13:47:05 UTC (rev 640) @@ -1,11 +1,16 @@ import unittest import test_container +import test_functional +import test_indexing def suite(): suite_container = test_container.suite() + suite_functional = test_functional.suite() + suite_indexing = test_indexing.suite() alltests = unittest.TestSuite([suite_container, - ]) + suite_functional, + suite_indexing]) return alltests def main(): Modified: branches/rpy_nextgen/rpy/rlike/tests/test_container.py =================================================================== --- branches/rpy_nextgen/rpy/rlike/tests/test_container.py 2008-08-23 10:15:04 UTC (rev 639) +++ branches/rpy_nextgen/rpy/rlike/tests/test_container.py 2008-08-24 13:47:05 UTC (rev 640) @@ -215,8 +215,14 @@ self.assertEquals(tuple(tl), (3, 2, 1)) def testsort(self): - self.assertTrue(False) # not implemented (yet) - + tn = ['a', 'c', 'b'] + tv = [1,3,2] + tl = rlc.TaggedList(tv, tags = tn) + tl.sort() + + self.assertEquals(tl.tags(), ('a', 'b', 'c')) + self.assertEquals(tuple(tl), (1, 2, 3)) + def testtags(self): tn = ['a', 'b', 'c'] tv = [1,2,3] Added: branches/rpy_nextgen/rpy/rlike/tests/test_functional.py =================================================================== --- branches/rpy_nextgen/rpy/rlike/tests/test_functional.py (rev 0) +++ branches/rpy_nextgen/rpy/rlike/tests/test_functional.py 2008-08-24 13:47:05 UTC (rev 640) @@ -0,0 +1,44 @@ +import unittest +import itertools +import rpy2.rlike.functional as rlf + +class TapplyTestCase(unittest.TestCase): + + def testSumByString(self): + seq = ( 1, 2, 3, 4, 5, 6) + tags = ('a', 'b', 'a', 'c', 'b', 'a') + expected = {'a': 1+3+6, + 'b': 2+5, + 'c': 4} + res = rlf.tapply(seq, tags, sum) + for k, v in res: + self.assertEquals(expected[k], v) + +class VectorizeTestCase(unittest.TestCase): + + def simpleFunction(self, subject_fun): + def f(x): + return x ** 2 + f_iter = subject_fun(f) + + seq = (1, 2, 3) + res = f_iter(seq) + + for va, vb in itertools.izip(seq, res): + self.assertEquals(va ** 2, vb) + + def testIterify(self): + self.simpleFunction(rlf.iterify) + + def testListify(self): + self.simpleFunction(rlf.listify) + + + +def suite(): + suite = unittest.TestLoader().loadTestsFromTestCase(TapplyTestCase) + suite.addTest(unittest.TestLoader().loadTestsFromTestCase(VectorizeTestCase)) + return suite + +if __name__ == '__main__': + unittest.main() Property changes on: branches/rpy_nextgen/rpy/rlike/tests/test_functional.py ___________________________________________________________________ Added: svn:eol-style + native Added: branches/rpy_nextgen/rpy/rlike/tests/test_indexing.py =================================================================== --- branches/rpy_nextgen/rpy/rlike/tests/test_indexing.py (rev 0) +++ branches/rpy_nextgen/rpy/rlike/tests/test_indexing.py 2008-08-24 13:47:05 UTC (rev 640) @@ -0,0 +1,21 @@ +import unittest +import itertools +import rpy2.rlike.indexing as rfi + +class OrderTestCase(unittest.TestCase): + + def testOrder(self): + seq = ( 2, 1, 5, 3, 4) + expected = (1, 2, 3, 4, 5) + res = rfi.order(seq) + for va, vb in itertools.izip(expected, res): + self.assertEquals(va, seq[vb]) + + +def suite(): + suite = unittest.TestLoader().loadTestsFromTestCase(OrderTestCase) + #suite.addTest(unittest.TestLoader().loadTestsFromTestCase(VectorizeTestCase)) + return suite + +if __name__ == '__main__': + unittest.main() Property changes on: branches/rpy_nextgen/rpy/rlike/tests/test_indexing.py ___________________________________________________________________ Added: svn:eol-style + native 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