Revision: 700
          http://rpy.svn.sourceforge.net/rpy/?rev=700&view=rev
Author:   lgautier
Date:     2008-11-22 21:06:58 +0000 (Sat, 22 Nov 2008)

Log Message:
-----------
Merging recent addition to the 2.0.x branch into the trunk

Bit of editing of the documentation

Modified Paths:
--------------
    rpy2/trunk/NEWS
    rpy2/trunk/doc/source/overview.rst
    rpy2/trunk/doc/source/robjects.rst
    rpy2/trunk/doc/source/rpy_classic.rst
    rpy2/trunk/rpy/__init__.py
    rpy2/trunk/rpy/rinterface/__init__.py
    rpy2/trunk/rpy/robjects/__init__.py
    rpy2/trunk/rpy/robjects/tests/__init__.py
    rpy2/trunk/rpy/robjects/tests/testRobjects.py
    rpy2/trunk/rpy/rpy_classic.py
    rpy2/trunk/rpy/tests_rpy_classic.py
    rpy2/trunk/setup.py

Added Paths:
-----------
    rpy2/trunk/rpy/robjects/conversion.py
    rpy2/trunk/rpy/robjects/numpy2ri.py
    rpy2/trunk/rpy/robjects/tests/testNumpyConversions.py

Property Changed:
----------------
    rpy2/trunk/


Property changes on: rpy2/trunk
___________________________________________________________________
Added: svn:mergeinfo
   + /rpy2/branches/version_2.0.x:679-699

Modified: rpy2/trunk/NEWS
===================================================================
--- rpy2/trunk/NEWS     2008-11-22 19:50:46 UTC (rev 699)
+++ rpy2/trunk/NEWS     2008-11-22 21:06:58 UTC (rev 700)
@@ -2,14 +2,19 @@
 ===
 
 
-
-
 Release 2.0.0
 =============
 
-Bugs fixed
-----------
+New features
+------------
 
+- New module :mod:`rpy2.robjects.conversion`.
+
+- New module :mod:`rpy2.robjects.numpy2ri` to convert :mod:`numpy` objects
+  into :mod:`rpy2` objects. 
+  # adapted from a patch contributed by Nathaniel Smith
+
+
 Changes
 -------
 
@@ -28,6 +33,32 @@
 Release 2.0.0rc1
 ================
 
+:mod:`rpy2.rpy_classic`:
+
+- :meth:`rpy_classic.RObj.getSexp` moved to a 
+  property :attr:`rpy_classic.Robj.sexp`.
+
+:mod:`rpy2.robjects`:
+
+- :meth:`RObject.__repr__` moved to :meth:`RObject.r_repr`
+
+- :meth:`ri2py`, :meth:`ro2py`, and :meth:`py2ri` moved to the new module
+  :mod:`conversion`. Adding the prefix `conversion.` to calls
+  to those functions will be enough to update existing code
+
+
+Bugs fixed
+----------
+
+- Informative message returned as RuntimeError when failing to find R's HOME
+
+- Use the registry to find the R's HOME on win32
+  # snatched from Peter's earlier contribution to rpy-1.x
+
+
+Release 2.0.0rc1
+================
+
 New features
 ------------
 

Modified: rpy2/trunk/doc/source/overview.rst
===================================================================
--- rpy2/trunk/doc/source/overview.rst  2008-11-22 19:50:46 UTC (rev 699)
+++ rpy2/trunk/doc/source/overview.rst  2008-11-22 21:06:58 UTC (rev 700)
@@ -124,7 +124,7 @@
 .. note::
 
    At the time of writing, 2 unit tests will fail. Their failure
-   is forced, because the terminating then starting again an
+   is forced, because terminating then starting again an
    embbeded R is causing problems.
 
 .. warning::
@@ -200,6 +200,12 @@
     For the original RPy and its maintainance through the years.
  
 Alexander Belopolsky. 
-    His code contribution to RPy is acknowledged. I have found great
-    inspiration in reading that code.
+    His code contribution of an alternative RPy is acknowledged.
+    I have found great inspiration in reading that code.
 
+JRI
+    The Java-R Interface, and its authors, as answers to some
+    of the implementation questions were found there.
+ 
+Contributors
+    Their names are in Section Changes.

Modified: rpy2/trunk/doc/source/robjects.rst
===================================================================
--- rpy2/trunk/doc/source/robjects.rst  2008-11-22 19:50:46 UTC (rev 699)
+++ rpy2/trunk/doc/source/robjects.rst  2008-11-22 21:06:58 UTC (rev 700)
@@ -70,7 +70,7 @@
 * '.' (dot) is syntactically valid in names for R objects, but not for
     python objects.
 
-That last limitation can partly be removed by using :mod:`rpy.rpy_classic` if
+That last limitation can partly be removed by using :mod:`rpy2.rpy_classic` if
 this feature matters most to you.
 
 >>> robjects.r.as_null
@@ -80,11 +80,12 @@
 >>> rpy.r.as_null
 # R function as.null() returned
 
-.. warning::
-   In the case there are R objects which name only differ by '.' and '_'
-   (e.g., 'my_variable' and 'my.variable'), setting :attr:`_dotter` to True
-   can result in confusing results at runtime.
+.. note::
 
+   The section :ref:`rpy_classic-mix` outlines how to integrate
+   :mod:`rpy2.rpy_classic` code.
+
+
 Behind the scene, the steps for getting an attribute of `r` are
 rather straightforward:
  
@@ -93,13 +94,33 @@
 
   2. Check if the attribute is can be accessed in R, starting from `globalEnv`
 
-When safety matters most, or when getting extraordinary funds for a bailout
-is unlikely, we recommed using :meth:`__getitem__` to get
-a given R object (and store it in a python variable if wanted):
+When safety matters most, we recommend using :meth:`__getitem__` to get
+a given R object.
 
 >>> as_null = robjects.r['as.null']
 
+Storing the object in a python variable will protect it from garbage
+collection, even if deleted from the objects visible to an R user.
 
+>>> robjects.globalEnv['foo'] = 1.2
+>>> foo = robjects.r['foo']
+>>> foo[0]
+1.2
+
+Here we `remove` the symbol `foo` from the R Global Environment.
+
+>>> robjects.r['rm']('foo')
+>>> robjects.r['foo']
+LookupError: 'foo' not found
+
+The object itself remains available, and protected from R's
+garbage collection until `foo` is deleted from Python
+
+>>> foo[0]
+1.2
+
+
+
 Strings as R code
 -----------------
 
@@ -295,6 +316,17 @@
 Numpy
 -----
 
+A popular solution for scientific computing with Python is :mod:`numpy` 
+(previous instances were :mod:`Numpy` and :mod:`numarray`).
+
+:mod:`rpy2` has features for facilitating the integration with code using
+:mod:`numpy` in both directions: from `rpy2` to `numpy`, and from `numpy`
+to `rpy2`.
+
+
+From `rpy2` to `numpy`:
+^^^^^^^^^^^^^^^^^^^^^^^
+
 Vectors can be converted to :mod:`numpy` arrays using
 :meth:`array` or :meth:`asarray`::
 
@@ -305,6 +337,31 @@
 Refer to the documentation for :class:`rinterface.SexpVector`
 for further details.
 
+From `numpy` to `rpy2`:
+^^^^^^^^^^^^^^^^^^^^^^^
+
+The conversion of `numpy` objects to `rpy2` objects can be 
+activated by importing the module :mod:`numpy2ri`::
+
+  import rpy2.robjects.numpy2ri
+
+That import alone is sufficient to switch an automatic conversion
+of `numpy` objects into `rpy2` objects.
+
+
+.. note::
+
+   Why make this an optional import, while it could have been included
+   in the function :func:`py2ri` (as done in the original patch 
+   submitted for that function) ?
+
+   Although both are valid and reasonable options, the design decision
+   was taken in order to decouple `rpy2` from `numpy` the most, and
+   do not assume that having `numpy` installed automatically
+   meant that a programmer wanted to use it.
+
+
+
 .. index::
    pair: robjects;REnvironment
    pair: robjects;globalEnv
@@ -525,21 +582,25 @@
 while an higher-level mapping is done between low-level objects and
 higher-level objects using the functions:
 
-:meth:`ri2py`
+:meth:`conversion.ri2py`
    :mod:`rpy2.rinterface` to Python. By default, this function
    is just an alias for the function :meth:`default_ri2py`.
 
-:meth:`py2ri`
+:meth:`conversion.py2ri`
    Python to :mod:`rpy2.rinterface`. By default, this function
    is just an alias for the function :meth:`default_py2ri`.
 
-:meth:`py2ro`
-   Python to :mod:`rpy2.robjects`. That one function
-   is merely a call to :meth:`py2ri` followed by a call to :meth:`ri2py`.
+:meth:`conversion.py2ro`
+   Python to :mod:`rpy2.robjects`. By default, that one function
+   is merely a call to :meth:`conversion.py2ri` 
+   followed by a call to :meth:`conversion.ri2py`.
 
-Those functions can be modifyied to satisfy all requirements, with
+Those functions can be re-routed to satisfy all requirements, with
 the easiest option being to write a custom function calling itself
-the default function.
+the default functions.
+
+Switching to `numpy`-to-`rpy2` is using this mechanism.
+
 As an example, let's assume that one want to return atomic values
 whenever an R numerical vector is of length one. This is only a matter
 of writing a new function `ri2py` that handles this, as shown below:
@@ -554,7 +615,7 @@
            res = res[0]
        return res
 
-   robjects.ri2py = my_ri2py
+   robjects.conversion.ri2py = my_ri2py
 
 Once this is done, we can verify immediately that this is working with:
 
@@ -563,9 +624,9 @@
 <type 'float'>
 >>> 
 
-The default behavoir can be restored with:
+The default behavior can be restored with:
 
->>> robjects.ri2py = default_ri2py
+>>> robjects.conversion.ri2py = default_ri2py
 
 The docstrings for :meth:`default_ri2py`, :meth:`default_py2ri`, and 
:meth:`py2ro` are:
 

Modified: rpy2/trunk/doc/source/rpy_classic.rst
===================================================================
--- rpy2/trunk/doc/source/rpy_classic.rst       2008-11-22 19:50:46 UTC (rev 
699)
+++ rpy2/trunk/doc/source/rpy_classic.rst       2008-11-22 21:06:58 UTC (rev 
700)
@@ -93,3 +93,56 @@
 >>> pca = rpy.r.princomp(m)
 >>> rpy.r.plot(pca, main = "PCA")
 >>>
+
+.. _rpy_classic-mix:
+
+Partial use of :mod:`rpy_classic`
+==================================
+
+The use of rpy_classic does not need to be
+exclusive of the other interface(s) proposed
+in rpy2.
+
+Chaining code designed for either of the interfaces
+is rather easy and, among other possible use-cases,
+should make the inclusion of legacy rpy code into newly
+written rpy2 code a simple take.
+
+The link between :mod:`rpy_classic` and the rest
+of :mod:`rpy2` is the property :attr:`RObj.sexp`,
+that give the representation of the underlying R object
+in the low-level :mod:`rpy2.rinterface` definition.
+This representation can then be used in function calls
+with :mod:`rpy2.rinterface` and :mod:`rpy2.robjects`.
+With :mod:`rpy2.robjects`, a conversion using 
+:func:`rpy2.robjects.default_ri2py` can be considered.
+
+.. note::
+
+   Obviously, that property `sexp` is not part of the original
+   `Robj` in rpy.
+
+
+An example:
+
+.. code-block:: python
+
+   import rpy2.robjects as ro
+   import rpy2.rpy_classic as rpy
+   rpy.set_default_mode(rpy.NO_CONVERSION)
+
+
+   def legacy_paste(v):
+       # legacy rpy code
+       res = rpy.r.paste(v, collapse = '-')
+       return res
+
+
+   rletters = ro.r['letters']
+
+   # the legaxy code is called using an rpy2.robjects object
+   alphabet_rpy = legacy_paste(rletters)
+
+   # convert the resulting rpy2.rpy_classic object to
+   # an rpy2.robjects object
+   alphabet = ro.default_ri2py(alphabet_rpy.sexp)

Modified: rpy2/trunk/rpy/__init__.py
===================================================================
--- rpy2/trunk/rpy/__init__.py  2008-11-22 19:50:46 UTC (rev 699)
+++ rpy2/trunk/rpy/__init__.py  2008-11-22 21:06:58 UTC (rev 700)
@@ -1 +1,2 @@
 __version__ = '2.1.0dev'
+

Modified: rpy2/trunk/rpy/rinterface/__init__.py
===================================================================
--- rpy2/trunk/rpy/rinterface/__init__.py       2008-11-22 19:50:46 UTC (rev 
699)
+++ rpy2/trunk/rpy/rinterface/__init__.py       2008-11-22 21:06:58 UTC (rev 
700)
@@ -22,7 +22,7 @@
                     "This might be because R.exe is nowhere in your Path.")
     else:
         raise RuntimeError(
-            "R_HOME define, and no R command in the PATH."
+            "R_HOME not defined, and no R command in the PATH."
             )
 else:
 #Twist if 'R RHOME' spits out a warning

Modified: rpy2/trunk/rpy/robjects/__init__.py
===================================================================
--- rpy2/trunk/rpy/robjects/__init__.py 2008-11-22 19:50:46 UTC (rev 699)
+++ rpy2/trunk/rpy/robjects/__init__.py 2008-11-22 21:06:58 UTC (rev 700)
@@ -11,9 +11,11 @@
 import itertools
 import rpy2.rinterface as rinterface
 import rpy2.rlike.container as rlc
+import rpy2.robjects.conversion
 
 #FIXME: close everything when leaving (check RPy for that).
 
+
 def default_ri2py(o):
     """ Convert :class:`rpy2.rinterface.Sexp` to higher-level objects,
     without copying the R objects.
@@ -50,7 +52,7 @@
         res = RObject(o)
     return res
 
-ri2py = default_ri2py
+conversion.ri2py = default_ri2py
 
 
 def default_py2ri(o):
@@ -84,14 +86,14 @@
     elif isinstance(o, unicode):
         res = rinterface.SexpVector([o, ], rinterface.STRSXP)
     elif isinstance(o, list):
-        res = r.list(*[ri2py(py2ri(x)) for x in o])
+        res = r.list(*[conversion.ri2py(conversion.py2ri(x)) for x in o])
     elif isinstance(o, complex):
         res = rinterface.SexpVector([o, ], rinterface.CPLXSXP)
     else:
         raise(ValueError("Nothing can be done for the type %s at the moment." 
%(type(o))))
     return res
 
-py2ri = default_py2ri
+conversion.py2ri = default_py2ri
 
 
 def default_py2ro(o):
@@ -102,7 +104,7 @@
     res = default_py2ri(o)
     return default_ri2py(res)
 
-py2ro = default_py2ro
+conversion.py2ro = default_py2ro
 
 
 def repr_robject(o, linesep=os.linesep):
@@ -211,7 +213,7 @@
 
     def __init__(self, o):
         if not isinstance(o, rinterface.SexpVector):
-            o = py2ri(o)
+            o = conversion.py2ri(o)
         super(RVector, self).__init__(o)
         self.r = RVectorDelegator(self)
             
@@ -231,9 +233,9 @@
            - an index is itself a vector of elements to select
         """
         
-        args = [py2ro(x) for x in args]
+        args = [conversion.py2ro(x) for x in args]
         for k, v in kwargs.itervalues():
-            args[k] = py2ro(v)
+            args[k] = conversion.py2ro(v)
         
         res = r["["](*([self, ] + [x for x in args]), **kwargs)
         return res
@@ -241,15 +243,15 @@
     def assign(self, index, value):
         if not (isinstance(index, rlc.TaggedList) | \
                     isinstance(index, rlc.ArgsDict)):
-            args = rlc.TaggedList([py2ro(index), ])
+            args = rlc.TaggedList([conversion.py2ro(index), ])
         else:
             for i in xrange(len(index)):
-                index[i] = py2ro(index[i])
+                index[i] = conversion.py2ro(index[i])
             args = index
-        args.append(py2ro(value))
+        args.append(conversion.py2ro(value))
         args.insert(0, self)
         res = r["[<-"].rcall(args.items())
-        res = ri2py(res)
+        res = conversion.ri2py(res)
         return res
 
     def __add__(self, x):
@@ -259,11 +261,11 @@
     def __getitem__(self, i):
         res = super(RVector, self).__getitem__(i)
         if isinstance(res, rinterface.Sexp):
-            res = ri2py(res)
+            res = conversion.ri2py(res)
         return res
 
     def __setitem__(self, i, value):
-        value = py2ri(value)
+        value = conversion.py2ri(value)
         res = super(RVector, self).__setitem__(i, value)
 
     def getnames(self):
@@ -312,11 +314,11 @@
 
     def getdim(self):
         res = r.dim(self)
-        res = ri2py(res)
+        res = conversion.ri2py(res)
         return res
 
     def setdim(self, value):
-        value = py2ro(value)
+        value = conversion.py2ro(value)
         res = r["dim<-"](self, value)
             #FIXME: not properly done
         raise(Exception("Not yet implemented"))
@@ -387,7 +389,7 @@
         :rtype: SexpVector
         """
         res = baseNameSpaceEnv["rownames"](self)
-        return ri2py(res)
+        return conversion.ri2py(res)
 
     def colnames(self):
         """ Column names
@@ -395,7 +397,7 @@
         :rtype: SexpVector
         """
         res = baseNameSpaceEnv["colnames"](self)
-        return ri2py(res)
+        return conversion.ri2py(res)
 
 
 class RFunction(RObjectMixin, rinterface.SexpClosure):
@@ -404,12 +406,12 @@
     """
 
     def __call__(self, *args, **kwargs):
-        new_args = [py2ri(a) for a in args]
+        new_args = [conversion.py2ri(a) for a in args]
        new_kwargs = {}
         for k, v in kwargs.iteritems():
-            new_kwargs[k] = py2ri(v)
+            new_kwargs[k] = conversion.py2ri(v)
         res = super(RFunction, self).__call__(*new_args, **new_kwargs)
-        res = ri2py(res)
+        res = conversion.ri2py(res)
         return res
 
 
@@ -423,20 +425,20 @@
 
     def __getitem__(self, item):
         res = super(REnvironment, self).__getitem__(item)
-        res = ri2py(res)
+        res = conversion.ri2py(res)
         return res
 
     def __setitem__(self, item, value):
-        robj = py2ro(value)
+        robj = conversion.py2ro(value)
         super(REnvironment, self).__setitem__(item, robj)
 
     def get(self, item):
         """ Get a object from its R name/symol
         :param item: string (name/symbol)
-        :rtype: object (as returned by :func:`ri2py`)
+        :rtype: object (as returned by :func:`conversion.ri2py`)
         """
         res = super(REnvironment, self).get(item)
-        res = ri2py(res)
+        res = conversion.ri2py(res)
         return res
 
 
@@ -444,7 +446,7 @@
 
     def __getattr__(self, attr):
         res = self.do_slot(attr)
-        res = ri2py(res)
+        res = conversion.ri2py(res)
         return res
 
 
@@ -461,7 +463,7 @@
         
     def getenvironment(self):
         res = self.do_slot(".Environment")
-        res = ri2py(res)
+        res = conversion.ri2py(res)
         return res
 
     def setenvironment(self, val):
@@ -500,7 +502,7 @@
     def __getitem__(self, item):
         res = rinterface.globalEnv.get(item)
             
-       res = ri2py(res)
+       res = conversion.ri2py(res)
         return res
 
     #FIXME: check that this is properly working
@@ -523,6 +525,6 @@
 
 r = R()
 
-globalEnv = ri2py(rinterface.globalEnv)
-baseNameSpaceEnv = ri2py(rinterface.baseNameSpaceEnv)
-emptyEnv = ri2py(rinterface.emptyEnv)
+globalEnv = conversion.ri2py(rinterface.globalEnv)
+baseNameSpaceEnv = conversion.ri2py(rinterface.baseNameSpaceEnv)
+emptyEnv = conversion.ri2py(rinterface.emptyEnv)

Copied: rpy2/trunk/rpy/robjects/conversion.py (from rev 699, 
rpy2/branches/version_2.0.x/rpy/robjects/conversion.py)
===================================================================
--- rpy2/trunk/rpy/robjects/conversion.py                               (rev 0)
+++ rpy2/trunk/rpy/robjects/conversion.py       2008-11-22 21:06:58 UTC (rev 
700)
@@ -0,0 +1,12 @@
+
+
+def ri2py(obj):
+    raise RuntimeError("Conversion function undefined")
+
+def py2ri(obj):
+    raise RuntimeError("Conversion function undefined")
+
+def py2ro(obj):
+    raise RuntimeError("Conversion function undefined")
+
+


Property changes on: rpy2/trunk/rpy/robjects/conversion.py
___________________________________________________________________
Added: svn:mergeinfo
   + /rpy2/branches/version_2.0.x/rpy/robjects/conversion.py:679-696
Added: svn:eol-style
   + native

Copied: rpy2/trunk/rpy/robjects/numpy2ri.py (from rev 699, 
rpy2/branches/version_2.0.x/rpy/robjects/numpy2ri.py)
===================================================================
--- rpy2/trunk/rpy/robjects/numpy2ri.py                         (rev 0)
+++ rpy2/trunk/rpy/robjects/numpy2ri.py 2008-11-22 21:06:58 UTC (rev 700)
@@ -0,0 +1,53 @@
+import rpy2.robjects as ro
+import rpy2.rinterface as rinterface
+import numpy
+
+def numpy2ri(o):
+    if isinstance(o, numpy.ndarray):
+        if not o.dtype.isnative:
+            raise(ValueError("Cannot pass numpy arrays with non-native byte 
orders at the moment."))
+
+        # The possible kind codes are listed at
+        #   http://numpy.scipy.org/array_interface.shtml
+        kinds = {
+            # "t" -> not really supported by numpy
+            "b": rinterface.LGLSXP,
+            "i": rinterface.INTSXP,
+            # "u" -> special-cased below
+            "f": rinterface.REALSXP,
+            "c": rinterface.CPLXSXP,
+            # "O" -> special-cased below
+            "S": rinterface.STRSXP,
+            "U": rinterface.STRSXP,
+            # "V" -> special-cased below
+            }
+        # Most types map onto R arrays:
+        if o.dtype.kind in kinds:
+            # "F" means "use column-major order"
+            vec = rinterface.SexpVector(o.ravel("F"), kinds[o.dtype.kind])
+            dim = rinterface.SexpVector(o.shape, rinterface.INTSXP)
+            res = ro.r.array(vec, dim=dim)
+        # R does not support unsigned types:
+        elif o.dtype.kind == "u":
+            raise(ValueError("Cannot convert numpy array of unsigned values -- 
R does not have unsigned integers."))
+        # Array-of-PyObject is treated like a Python list:
+        elif o.dtype.kind == "O":
+            res = ro.conversion.py2ri(list(o))
+        # Record arrays map onto R data frames:
+        elif o.dtype.kind == "V":
+            if o.dtype.names is None:
+                raise(ValueError("Nothing can be done for this numpy array 
type %s at the moment." % (o.dtype,)))
+            df_args = []
+            for field_name in o.dtype.names:
+                df_args.append((field_name, 
+                                ro.conversion.py2ri(o[field_name])))
+            res = ro.baseNameSpaceEnv["data.frame"].rcall(tuple(df_args))
+        # It should be impossible to get here:
+        else:
+            raise(ValueError("Unknown numpy array type."))
+    else:
+        res = ro.default_py2ri(o)
+    return res
+
+
+ro.conversion.py2ri = numpy2ri


Property changes on: rpy2/trunk/rpy/robjects/numpy2ri.py
___________________________________________________________________
Added: svn:mergeinfo
   + /rpy2/branches/version_2.0.x/rpy/robjects/numpy2ri.py:679-696
Added: svn:eol-style
   + native

Modified: rpy2/trunk/rpy/robjects/tests/__init__.py
===================================================================
--- rpy2/trunk/rpy/robjects/tests/__init__.py   2008-11-22 19:50:46 UTC (rev 
699)
+++ rpy2/trunk/rpy/robjects/tests/__init__.py   2008-11-22 21:06:58 UTC (rev 
700)
@@ -9,6 +9,9 @@
 import testREnvironment
 import testRobjects
 
+# wrap this nicely so a warning is issued if no numpy present
+import testNumpyConversions
+
 def suite():
     suite_RObject = testRObject.suite()
     suite_RVector = testRVector.suite()
@@ -18,6 +21,7 @@
     suite_REnvironment = testREnvironment.suite()
     suite_RFormula = testRFormula.suite()
     suite_Robjects = testRobjects.suite()
+    suite_NumpyConversions = testNumpyConversions.suite()
     alltests = unittest.TestSuite([suite_RObject,
                                    suite_RVector,                   
                                    suite_RArray,
@@ -25,7 +29,9 @@
                                    suite_RFunction,
                                    suite_REnvironment,
                                    suite_RFormula,
-                                   suite_Robjects ])
+                                   suite_Robjects,
+                                   suite_NumpyConversions
+                                   ])
     return alltests
 
 def main():

Copied: rpy2/trunk/rpy/robjects/tests/testNumpyConversions.py (from rev 699, 
rpy2/branches/version_2.0.x/rpy/robjects/tests/testNumpyConversions.py)
===================================================================
--- rpy2/trunk/rpy/robjects/tests/testNumpyConversions.py                       
        (rev 0)
+++ rpy2/trunk/rpy/robjects/tests/testNumpyConversions.py       2008-11-22 
21:06:58 UTC (rev 700)
@@ -0,0 +1,94 @@
+import unittest
+import rpy2.robjects as robjects
+r = robjects.r
+
+import numpy
+import rpy2.robjects.numpy2ri as rpyn
+
+
+class NumpyConversionsTestCase(unittest.TestCase):
+
+    def setUp(self):
+        robjects.conversion.py2ri = rpyn.numpy2ri
+
+    def tearDown(self):
+        robjects.conversion.py2ri = robjects.default_py2ri
+
+    def checkHomogeneous(self, obj, mode, storage_mode):
+        converted = robjects.conversion.py2ri(obj)
+        self.assertEquals(r["mode"](converted)[0], mode)
+        self.assertEquals(r["storage.mode"](converted)[0], storage_mode)
+        self.assertEquals(list(obj), list(converted))
+        self.assertTrue(r["is.array"](converted)[0])
+
+    def testVector(self):
+
+        b = numpy.array([True, False, True], dtype=numpy.bool_)
+        self.checkHomogeneous(b, "logical", "logical")
+
+        i = numpy.array([1, 2, 3], dtype="i")
+        self.checkHomogeneous(i, "numeric", "integer")
+
+        f = numpy.array([1, 2, 3], dtype="f")
+        self.checkHomogeneous(f, "numeric", "double")
+
+        c = numpy.array([1j, 2j, 3j], dtype=numpy.complex_)
+        self.checkHomogeneous(c, "complex", "complex")
+
+        s = numpy.array(["a", "b", "c"], dtype="S")
+        self.checkHomogeneous(s, "character", "character")
+
+        u = numpy.array([u"a", u"b", u"c"], dtype="U")
+        self.checkHomogeneous(u, "character", "character")
+
+    def testArray(self):
+
+        i2d = numpy.array([[1, 2, 3], [4, 5, 6]], dtype="i")
+        i2d_r = robjects.conversion.py2ri(i2d)
+
+        self.assertEquals(r["storage.mode"](i2d_r)[0], "integer")
+        self.assertEquals(tuple(r["dim"](i2d_r)), (2, 3))
+
+        # Make sure we got the row/column swap right:
+        self.assertEquals(i2d_r.subset(1, 2)[0], i2d[0, 1])
+
+        f3d = numpy.arange(24, dtype="f").reshape((2, 3, 4))
+        f3d_r = robjects.conversion.py2ri(f3d)
+
+        self.assertEquals(r["storage.mode"](f3d_r)[0], "double")
+        self.assertEquals(tuple(r["dim"](f3d_r)), (2, 3, 4))
+
+        # Make sure we got the row/column swap right:
+        self.assertEquals(f3d_r.subset(1, 2, 3)[0], f3d[0, 1, 2])
+
+    def testObjectArray(self):
+        o = numpy.array([1, "a", 3.2], dtype=numpy.object_)
+        o_r = robjects.conversion.py2ri(o)
+        self.assertEquals(r["mode"](o_r)[0], "list")
+        self.assertEquals(r["[["](o_r, 1)[0], 1)
+        self.assertEquals(r["[["](o_r, 2)[0], "a")
+        self.assertEquals(r["[["](o_r, 3)[0], 3.2)
+
+    def testRecordArray(self):
+        rec = numpy.array([(1, 2.3), (2, -0.7), (3, 12.1)],
+                          dtype=[("count", "i"), ("value", numpy.double)])
+        rec_r = robjects.conversion.py2ri(rec)
+        self.assertTrue(r["is.data.frame"](rec_r)[0])
+        self.assertEquals(tuple(r["names"](rec_r)), ("count", "value"))
+        count_r = r["$"](rec_r, "count")
+        value_r = r["$"](rec_r, "value")
+        self.assertEquals(r["storage.mode"](count_r)[0], "integer")
+        self.assertEquals(r["storage.mode"](value_r)[0], "double")
+        self.assertEquals(count_r[1], 2)
+        self.assertEquals(value_r[2], 12.1)
+
+    def testBadArray(self):
+        u = numpy.array([1, 2, 3], dtype=numpy.uint32)
+        self.assertRaises(ValueError, robjects.conversion.py2ri, u)
+
+def suite():
+    return 
unittest.TestLoader().loadTestsFromTestCase(NumpyConversionsTestCase)
+
+if __name__ == '__main__':
+    unittest.main()
+

Modified: rpy2/trunk/rpy/robjects/tests/testRobjects.py
===================================================================
--- rpy2/trunk/rpy/robjects/tests/testRobjects.py       2008-11-22 19:50:46 UTC 
(rev 699)
+++ rpy2/trunk/rpy/robjects/tests/testRobjects.py       2008-11-22 21:06:58 UTC 
(rev 700)
@@ -119,7 +119,7 @@
             if inherits(pyobj, classname)[0]:
                 pyobj = Density(pyobj)
             return pyobj
-        robjects.ri2py = f
+        robjects.conversion.ri2py = f
         x = robjects.r.rnorm(100)
         d = robjects.r.density(x)
 

Modified: rpy2/trunk/rpy/rpy_classic.py
===================================================================
--- rpy2/trunk/rpy/rpy_classic.py       2008-11-22 19:50:46 UTC (rev 699)
+++ rpy2/trunk/rpy/rpy_classic.py       2008-11-22 21:06:58 UTC (rev 700)
@@ -221,8 +221,10 @@
         return res
 
     ##FIXME: not part of RPy-1.x.
-    def getSexp(self):
+    def get_sexp(self):
         return self.__sexp
+
+    sexp = property(fget = get_sexp)
     
     #def __repr__(self):
     #    res = rpy2py(self)

Modified: rpy2/trunk/rpy/tests_rpy_classic.py
===================================================================
--- rpy2/trunk/rpy/tests_rpy_classic.py 2008-11-22 19:50:46 UTC (rev 699)
+++ rpy2/trunk/rpy/tests_rpy_classic.py 2008-11-22 21:06:58 UTC (rev 700)
@@ -1,6 +1,7 @@
 import unittest
 
 import rpy2.rpy_classic as rpy
+import rpy2.rinterface
 
 
 class RpyClassicTestCase(unittest.TestCase):
@@ -27,6 +28,12 @@
         self.assertTrue(callable(rpy.r.seq))
         self.assertTrue(callable(rpy.r.pi))
 
+    def testSexp(self):
+        rpy.set_default_mode(rpy.NO_CONVERSION)
+        pi = rpy.r.pi
+        self.assertTrue(isinstance(pi.sexp, rpy2.rinterface.Sexp))
+        self.assertRaises(AttributeError, setattr, pi, 'sexp', None)
+
 def suite():
     suite = unittest.TestLoader().loadTestsFromTestCase(RpyClassicTestCase)
     return suite

Modified: rpy2/trunk/setup.py
===================================================================
--- rpy2/trunk/setup.py 2008-11-22 19:50:46 UTC (rev 699)
+++ rpy2/trunk/setup.py 2008-11-22 21:06:58 UTC (rev 700)
@@ -11,6 +11,11 @@
 if RHOMES is None:
     
     RHOMES = os.popen("R RHOME").readlines()
+    if len(RHOMES) == 0:
+        raise RuntimeError(
+            "R_HOME not defined, and no R command in the PATH."
+            )
+
     #Twist if 'R RHOME' spits out a warning
     if RHOMES[0].startswith("WARNING"):
         RHOMES = RHOMES[1]


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

Reply via email to