Revision: 641 http://rpy.svn.sourceforge.net/rpy/?rev=641&view=rev Author: lgautier Date: 2008-08-25 07:08:15 +0000 (Mon, 25 Aug 2008)
Log Message: ----------- rinterface: - fixed signature for Sexp_get getter - added emptyEnv - new method Sexp_do_slot_assign rlike: - added paramater 'cmp' to order() robjects: - fixed DataFrame methods rownames() and colnames() doc: - more 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/doc/source/robjects.rst branches/rpy_nextgen/rpy/rinterface/rinterface.c branches/rpy_nextgen/rpy/rinterface/tests/test_Sexp.py branches/rpy_nextgen/rpy/rlike/indexing.py branches/rpy_nextgen/rpy/robjects/__init__.py Modified: branches/rpy_nextgen/NEWS =================================================================== --- branches/rpy_nextgen/NEWS 2008-08-24 13:47:05 UTC (rev 640) +++ branches/rpy_nextgen/NEWS 2008-08-25 07:08:15 UTC (rev 641) @@ -14,6 +14,10 @@ - method :meth:`rsame` to test if the underlying R objects for two :class:`Sexp` are the same. +- added `emptyEnv` (R's C-level `R_EmptyEnv`) + +- added method :meth:`Sexp.do_slot_assign` + :mod:`rpy2.robjects`: - R string vectors can now be built from Python unicode objects @@ -42,6 +46,7 @@ - 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 @@ -64,6 +69,7 @@ - complex vectors should now be handled properly by :mod:`rpy2.rinterface.robjects`. +- methods :meth:`rownames` and :meth:`colnames` for :class:`RDataFrame` were incorrect. Release 2.0.0a2 =============== Modified: branches/rpy_nextgen/doc/source/overview.rst =================================================================== --- branches/rpy_nextgen/doc/source/overview.rst 2008-08-24 13:47:05 UTC (rev 640) +++ branches/rpy_nextgen/doc/source/overview.rst 2008-08-25 07:08:15 UTC (rev 641) @@ -139,10 +139,11 @@ - the use of the module simple from both a Python or R user's perspective -- minimize the need for knowledge about R, and the need for tricks are workaround. -- the possibility to customize a lot only with Python (without having to go to C-level). +- minimize the need for knowledge about R, and the need for tricks and workarounds. +- the possibility to customize a lot while remaining at the Python level (without having to go down to C-level). + :mod:`rpy2.robjects` implements an extension to the interface in :mod:`rpy2.rinterface` by extending the classes for R objects defined there with child classes. Modified: branches/rpy_nextgen/doc/source/rinterface.rst =================================================================== --- branches/rpy_nextgen/doc/source/rinterface.rst 2008-08-24 13:47:05 UTC (rev 640) +++ branches/rpy_nextgen/doc/source/rinterface.rst 2008-08-25 07:08:15 UTC (rev 641) @@ -222,7 +222,7 @@ called :meth:`do_slot` in the C interface to R. :param name: string - :rtype: Sexp (or Sexp-inheriting) object + :rtype: instance of :class:`Sexp` >>> matrix = rinterface.globalEnv.get("matrix") >>> letters = rinterface.globalEnv.get("letters") @@ -232,6 +232,14 @@ [13, 2] >>> + .. method:: do_slot_assign(name, value) + + Assign value to the slot with the given name + + :param name: string + :param value: instance of :class:`Sexp` + + .. method:: rsame(sexp_obj) Tell whether the underlying R object for sexp_obj is the same or not. @@ -523,10 +531,9 @@ 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): + while not item.rsame(ri.emptyEnv): spath.append(item) item = item.enclos() spath.append(ri.baseNameSpaceEnv) @@ -541,7 +548,6 @@ 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 @@ -551,7 +557,7 @@ retry = False except LookupError, knf: env = env.enclos() - if env.rsame(emptyenv): + if env.rsame(ri.emptyEnv): retry = False else: retry = True @@ -723,6 +729,9 @@ :const:`LANGSXP` Language object. +:const:`EXPRSXP` + Unevaluated expression. + Other types ^^^^^^^^^^^ @@ -736,7 +745,7 @@ Instance of class S4. Represented by :class:`rpy2.rinterface.SexpS4`. -Types you should not meet +Types one should not meet ^^^^^^^^^^^^^^^^^^^^^^^^^ :const:`PROMSXP` Modified: branches/rpy_nextgen/doc/source/rlike.rst =================================================================== --- branches/rpy_nextgen/doc/source/rlike.rst 2008-08-24 13:47:05 UTC (rev 640) +++ branches/rpy_nextgen/doc/source/rlike.rst 2008-08-25 07:08:15 UTC (rev 641) @@ -96,21 +96,52 @@ .. autoclass:: rpy2.rlike.container.TaggedList :members: + +.. module:: rpy2.rlike.functional + Tools for working with sequences ================================ -.. autofunction:: rpy2.rlike.functional.tapply +.. autofunction:: tapply >>> import rpy2.rlike.functional as rlf >>> rlf.tapply((1,2,3), ('a', 'b', 'a'), sum) [('a', 4), ('b', 2)] +.. module:: rpy2.rlike.indexing + Indexing ======== -.. function:: rpy2.rlike.indexing.order +Much of the R-style indexing can be achieved with Python's list comprehension: +>>> x = ('a', 'b', 'c') +>>> x_i = (0, 2) +>>> [x[i] for i in x_i] +['a', 'c'] + +In `R`, negative indexes mean that values should be excluded. Again, +list comprehension can be used: + +>>> x = ('a', 'b', 'c') +>>> x_i = (0, 2) + +.. function:: order(seq, cmp = default_cmp, reverse = False) + + Give the order in which to take the items in the sequence `seq` and + have them sorted. + The optional function cmp should return +1, -1, or 0. + + :param seq: sequence + :param cmp: function + :param reverse: boolean + :rtype: list of integers + >>> import rpy2.rlike.indexing as rli ->>> rli.order(('a', 'c', 'b')) +>>> x = ('a', 'c', 'b') +>>> o = rli.order(x) +>>> o [0, 2, 1] +>>> [x[i] for i in o] +['a', 'b', 'c'] \ No newline at end of file Modified: branches/rpy_nextgen/doc/source/robjects.rst =================================================================== --- branches/rpy_nextgen/doc/source/robjects.rst 2008-08-24 13:47:05 UTC (rev 640) +++ branches/rpy_nextgen/doc/source/robjects.rst 2008-08-25 07:08:15 UTC (rev 641) @@ -257,6 +257,7 @@ :show-inheritance: :members: + Environments ============ @@ -304,7 +305,11 @@ >>> env = robjects.r.baseenv() >>> len([x for x in env]) +<a long list returned> +For further information, read the documentation for the +class :class:`rpy2.rinterface.SexpEnvironment`. + .. index:: pair: robjects; RFunction pair: robjects; function Modified: branches/rpy_nextgen/rpy/rinterface/rinterface.c =================================================================== --- branches/rpy_nextgen/rpy/rinterface/rinterface.c 2008-08-24 13:47:05 UTC (rev 640) +++ branches/rpy_nextgen/rpy/rinterface/rinterface.c 2008-08-25 07:08:15 UTC (rev 641) @@ -138,6 +138,7 @@ static PySexpObject *globalEnv; static PySexpObject *baseNameSpaceEnv; +static PySexpObject *emptyEnv; static PySexpObject *na_string; /* early definition of functions */ @@ -363,6 +364,7 @@ RPY_SEXP(globalEnv) = R_GlobalEnv; RPY_SEXP(baseNameSpaceEnv) = R_BaseNamespace; + RPY_SEXP(emptyEnv) = R_EmptyEnv; RPY_SEXP(na_string) = NA_STRING; GetErrMessage_SEXP = findVar(install("geterrmessage"), @@ -406,6 +408,7 @@ RPY_SEXP(globalEnv) = R_EmptyEnv; RPY_SEXP(baseNameSpaceEnv) = R_EmptyEnv; + RPY_SEXP(emptyEnv) = R_EmptyEnv; GetErrMessage_SEXP = R_NilValue; //FIXME: Is it possible to reinitialize R later ? @@ -547,6 +550,50 @@ ":rtype: instance of type or subtype :class:`rpy2.rinterface.Sexp`"); static PyObject* +Sexp_do_slot_assign(PyObject *self, PyObject *args) +{ + + SEXP sexp = RPY_SEXP(((PySexpObject*)self)); + if (! sexp) { + PyErr_Format(PyExc_ValueError, "NULL SEXP."); + return NULL;; + } + + char *name_str; + PyObject *value; + if (! PyArg_ParseTuple(args, "sO", + &name_str, + &value)) { + return NULL; + } + + if (! PyObject_IsInstance(value, + (PyObject*)&Sexp_Type)) { + PyErr_Format(PyExc_ValueError, "Value must be an instance of Sexp."); + return NULL; + } + + if (! R_has_slot(sexp, install(name_str))) { + PyErr_SetString(PyExc_LookupError, "The object has no such attribute."); + return NULL; + } + SEXP value_sexp = RPY_SEXP((PySexpObject *)value); + if (! value_sexp) { + PyErr_Format(PyExc_ValueError, "NULL SEXP."); + return NULL;; + } + + SET_SLOT(sexp, install(name_str), value_sexp); + Py_INCREF(Py_None); + return Py_None; +} +PyDoc_STRVAR(Sexp_do_slot_assign_doc, + "Set the attribute/slot for an R object.\n" + "\n" + ":param name: string\n" + ":param value: instance of rpy2.rinterface.Sexp"); + +static PyObject* Sexp_named_get(PyObject *self) { SEXP sexp = RPY_SEXP(((PySexpObject*)self)); @@ -563,7 +610,7 @@ See the R-extensions manual for further details."); static PyObject* -Sexp_sexp_get(PyObject *self) +Sexp_sexp_get(PyObject *self, void *closure) { SEXP sexp = RPY_SEXP(((PySexpObject*)self)); @@ -575,6 +622,23 @@ PyObject *res = PyCObject_FromVoidPtr(sexp, NULL); return res; } + +/* static PyObject* */ +/* Sexp_sexp_set(PyObject *self, PyObject *obj, void *closure) */ +/* { */ +/* if (! PyCObject_Check(obj)) { */ +/* PyErr_SetString(PyExc_TypeError, "The value must be a CObject."); */ +/* return -1; */ +/* } */ +/* SEXP sexp = (SEXP) PyCObject_AsVoidPtr(PyObject* obj); */ +/* if (! sexp) { */ +/* PyErr_Format(PyExc_ValueError, "NULL SEXP."); */ +/* return -1; */ +/* } */ +/* RPY_SEXP(((PySexpObject*)self)) = sexp; */ + +/* return 0; */ +/* } */ PyDoc_STRVAR(Sexp_sexp_doc, "Opaque C pointer to the underlying R object"); @@ -611,6 +675,8 @@ static PyMethodDef Sexp_methods[] = { {"do_slot", (PyCFunction)Sexp_do_slot, METH_O, Sexp_do_slot_doc}, + {"do_slot_assign", (PyCFunction)Sexp_do_slot_assign, METH_VARARGS, + Sexp_do_slot_assign_doc}, {"rsame", (PyCFunction)Sexp_rsame, METH_O, Sexp_rsame_doc}, {NULL, NULL} /* sentinel */ @@ -2501,6 +2567,12 @@ /* //FIXME: DECREF ? */ /* Py_DECREF(baseNameSpaceEnv); */ + emptyEnv = (PySexpObject*)Sexp_new(&EnvironmentSexp_Type, + Py_None, Py_None); + RPY_SEXP(emptyEnv) = R_EmptyEnv; + if (PyDict_SetItemString(d, "emptyEnv", + (PyObject *)emptyEnv) < 0) + return; /* Add SXP types */ validSexpType = calloc(maxValidSexpType, sizeof(char *)); Modified: branches/rpy_nextgen/rpy/rinterface/tests/test_Sexp.py =================================================================== --- branches/rpy_nextgen/rpy/rinterface/tests/test_Sexp.py 2008-08-24 13:47:05 UTC (rev 640) +++ branches/rpy_nextgen/rpy/rinterface/tests/test_Sexp.py 2008-08-25 07:08:15 UTC (rev 641) @@ -50,8 +50,17 @@ for i, n in enumerate(iris_names): self.assertEquals(iris_names[i], names[i]) - self.assertRaises(LookupError, sexp.do_slot, "foo") + self.assertRaises(LookupError, sexp.do_slot, "foo") + def testDo_slot_assign(self): + data_func = rinterface.globalEnv.get("data") + data_func(rinterface.SexpVector(["iris", ], rinterface.STRSXP)) + sexp = rinterface.globalEnv.get("iris") + iris_names = rinterface.StrSexpVector(['a', 'b', 'c', 'd', 'e']) + sexp.do_slot_assign("names", iris_names) + names = [x for x in sexp.do_slot("names")] + self.assertEquals(['a', 'b', 'c', 'd', 'e'], names) + def testSexp_rsame_true(self): sexp_a = rinterface.globalEnv.get("letters") sexp_b = rinterface.globalEnv.get("letters") Modified: branches/rpy_nextgen/rpy/rlike/indexing.py =================================================================== --- branches/rpy_nextgen/rpy/rlike/indexing.py 2008-08-24 13:47:05 UTC (rev 640) +++ branches/rpy_nextgen/rpy/rlike/indexing.py 2008-08-25 07:08:15 UTC (rev 641) @@ -1,17 +1,24 @@ -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 +def default_cmp(x, y): + """ Default comparison function """ + if x < y: + return -1 + elif x > y: + return +1 + else: + return 0 + +def order(seq, cmp = default_cmp, reverse = False): + """ Return the order in which to take the items to obtained + a sorted sequence.""" + o = range(len(seq)) + + def wrap_cmp(x, y): + x = seq[x] + y = seq[y] + return cmp(x, y) - o.sort(cmp = cmp, reverse = reverse) + o.sort(cmp = wrap_cmp, reverse = reverse) return o Modified: branches/rpy_nextgen/rpy/robjects/__init__.py =================================================================== --- branches/rpy_nextgen/rpy/robjects/__init__.py 2008-08-24 13:47:05 UTC (rev 640) +++ branches/rpy_nextgen/rpy/robjects/__init__.py 2008-08-25 07:08:15 UTC (rev 641) @@ -54,7 +54,6 @@ res = RObject(o) return res -#FIXME: better names for the functions ri2py = default_ri2py @@ -350,20 +349,23 @@ def rownames(self): """ Row names - :rype: SexpVector + + :rtype: SexpVector """ - return baseNameSpaceEnv["colnames"](self)[0] + res = baseNameSpaceEnv["rownames"](self) + return ri2py(res) def colnames(self): """ Column names - :rype: SexpVector + + :rtype: SexpVector """ - return baseNameSpaceEnv["colnames"](self)[0] + res = baseNameSpaceEnv["colnames"](self) + return ri2py(res) - class RFunction(RObjectMixin, rinterface.SexpClosure): - """ An R function (aka "closure"). + """ An R function. """ 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