about summary refs log tree commit diff
path: root/pkgs/applications
diff options
context:
space:
mode:
authorTimo Kaufmann <timokau@zoho.com>2018-11-05 11:05:33 +0100
committerTimo Kaufmann <timokau@zoho.com>2018-11-25 19:36:21 +0100
commit8e7da1b8a44e39f45f46585e9497b1abb7a41fc4 (patch)
tree365706d22239ed809856303c2292465e27f52e99 /pkgs/applications
parent6138f5d5eb286f7f4e252da27ef681b6f6d0a9cd (diff)
downloadnixlib-8e7da1b8a44e39f45f46585e9497b1abb7a41fc4.tar
nixlib-8e7da1b8a44e39f45f46585e9497b1abb7a41fc4.tar.gz
nixlib-8e7da1b8a44e39f45f46585e9497b1abb7a41fc4.tar.bz2
nixlib-8e7da1b8a44e39f45f46585e9497b1abb7a41fc4.tar.lz
nixlib-8e7da1b8a44e39f45f46585e9497b1abb7a41fc4.tar.xz
nixlib-8e7da1b8a44e39f45f46585e9497b1abb7a41fc4.tar.zst
nixlib-8e7da1b8a44e39f45f46585e9497b1abb7a41fc4.zip
sage: 8.5.beta0 -> 8.5.beta1
Diffstat (limited to 'pkgs/applications')
-rw-r--r--pkgs/applications/science/math/sage/patches/r-rpy.patch763
-rw-r--r--pkgs/applications/science/math/sage/sage-src.nix4
2 files changed, 765 insertions, 2 deletions
diff --git a/pkgs/applications/science/math/sage/patches/r-rpy.patch b/pkgs/applications/science/math/sage/patches/r-rpy.patch
new file mode 100644
index 000000000000..ab407c8fd744
--- /dev/null
+++ b/pkgs/applications/science/math/sage/patches/r-rpy.patch
@@ -0,0 +1,763 @@
+diff --git a/src/sage/doctest/test.py b/src/sage/doctest/test.py
+index 2f4f74cfc2..c6c1bf9194 100644
+--- a/src/sage/doctest/test.py
++++ b/src/sage/doctest/test.py
+@@ -500,12 +500,13 @@ Test ``atexit`` support in the doctesting framework::
+     ....:     pass
+ 
+ Test the ``--memlimit`` option and ``# optional - memlimit``
+-(but only on Linux)::
++(but only on Linux). If this test fails, the memory needed to
++run it may have increased. Try increasing the limit. ::
+ 
+     sage: from platform import system
+     sage: ok = True
+     sage: if system() == "Linux":
+-    ....:     P = subprocess.Popen(["sage", "-t", "--warn-long", "0", "--memlimit=2000", "memlimit.rst"], stdout=subprocess.PIPE, **kwds)
++    ....:     P = subprocess.Popen(["sage", "-t", "--warn-long", "0", "--memlimit=2100", "memlimit.rst"], stdout=subprocess.PIPE, **kwds)
+     ....:     out, err = P.communicate()
+     ....:     ok = ("MemoryError: failed to allocate" in out)
+     sage: ok or out
+diff --git a/src/sage/interfaces/expect.py b/src/sage/interfaces/expect.py
+index 51a37496c2..ba982f25f7 100644
+--- a/src/sage/interfaces/expect.py
++++ b/src/sage/interfaces/expect.py
+@@ -1122,10 +1122,15 @@ If this all works, you can then make calls like:
+ 
+         EXAMPLES:
+ 
+-        We test all of this using the R interface. First we put
++        We test all of this using the Singular interface. First we put
+         10 + 15 in the input stream::
+ 
+-            sage: r._sendstr('abc <- 10 +15;\n')
++            sage: singular._sendstr('def abc = 10 + 15;\n')
++
++        Then we tell singular to print 10, which is an arbitrary number
++        different from the expected result 35.
++
++            sage: singular._sendstr('10;\n')
+ 
+         Here an exception is raised because 25 hasn't appeared yet in the
+         output stream. The key thing is that this doesn't lock, but instead
+@@ -1135,7 +1140,7 @@ If this all works, you can then make calls like:
+ 
+             sage: t = walltime()
+             sage: try:
+-            ....:    r._expect_expr('25', timeout=0.5)
++            ....:    singular._expect_expr('25', timeout=0.5)
+             ....: except Exception:
+             ....:    print('Did not get expression')
+             Did not get expression
+@@ -1145,24 +1150,24 @@ If this all works, you can then make calls like:
+             sage: w = walltime(t); w > 0.4 and w < 10
+             True
+ 
+-        We tell R to print abc, which equals 25.
++        We tell Singular to print abc, which equals 25.
+ 
+         ::
+ 
+-            sage: r._sendstr('abc;\n')
++            sage: singular._sendstr('abc;\n')
+ 
+         Now 25 is in the output stream, so we can wait for it.
+ 
+         ::
+ 
+-            sage: r._expect_expr('25')
++            sage: singular._expect_expr('25')
+ 
+-        This gives us everything before the 25.
++        This gives us everything before the 25, including the 10 we printed earlier.
+ 
+         ::
+ 
+-            sage: r._expect.before.decode('ascii')
+-            u'...abc;\r\n[1] '
++            sage: singular._expect.before.decode('ascii')
++            u'...10\r\n> '
+ 
+         We test interrupting ``_expect_expr`` using the GP interface,
+         see :trac:`6661`.  Unfortunately, this test doesn't work reliably using
+@@ -1203,14 +1208,7 @@ If this all works, you can then make calls like:
+ 
+         -  ``string`` -- a string
+ 
+-        EXAMPLES: We illustrate this function using the R interface::
+-
+-            sage: r._synchronize()
+-            sage: r._sendstr('a <- 10;\n')
+-            sage: r.eval('a')
+-            '[1] 10'
+-
+-        We illustrate using the singular interface::
++        EXAMPLES: We illustrate this function using the Singular interface::
+ 
+             sage: singular._synchronize()
+             sage: singular._sendstr('int i = 5;')
+@@ -1260,7 +1258,7 @@ If this all works, you can then make calls like:
+ 
+         EXAMPLES: We observe nothing, just as it should be::
+ 
+-            sage: r._synchronize()
++            sage: singular._synchronize()
+ 
+         TESTS:
+ 
+diff --git a/src/sage/interfaces/gp.py b/src/sage/interfaces/gp.py
+index 86f401571a..f3c6120ddc 100644
+--- a/src/sage/interfaces/gp.py
++++ b/src/sage/interfaces/gp.py
+@@ -254,6 +254,7 @@ class Gp(ExtraTabCompletion, Expect):
+         self._eval_line('default(help, "gphelp -detex");')
+         # logfile disabled since Expect already logs
+         self._eval_line('default(log,0);')
++        self._eval_line("default(nbthreads,1);")
+         # set random seed
+         self.set_seed(self._seed)
+ 
+diff --git a/src/sage/interfaces/r.py b/src/sage/interfaces/r.py
+index 5c75459903..06974a2324 100644
+--- a/src/sage/interfaces/r.py
++++ b/src/sage/interfaces/r.py
+@@ -268,17 +268,17 @@ from __future__ import print_function, absolute_import
+ from six.moves import range
+ import six
+ 
+-from .expect import Expect, ExpectElement, ExpectFunction, FunctionElement
++from .interface import Interface, InterfaceElement, InterfaceFunction, InterfaceFunctionElement
+ from sage.env import DOT_SAGE
+ import re
+-import sage.rings.integer
+ from sage.structure.element import parent
+ from sage.interfaces.tab_completion import ExtraTabCompletion
+ from sage.docs.instancedoc import instancedoc
++from rpy2 import robjects
++from rpy2.robjects import packages
++from rpy2.robjects.conversion import localconverter
+ 
+ COMMANDS_CACHE = '%s/r_commandlist.sobj'%DOT_SAGE
+-PROMPT = '__SAGE__R__PROMPT__> '
+-prompt_re = re.compile("^>", re.M)
+ 
+ #there is a mirror network, but lets take #1 for now
+ RRepositoryURL = "http://cran.r-project.org/"
+@@ -288,12 +288,156 @@ RFilteredPackages = ['.GlobalEnv']
+ # but package:base should cover this. i think.
+ RBaseCommands = ['c', "NULL", "NA", "True", "False", "Inf", "NaN"]
+ 
+-class R(ExtraTabCompletion, Expect):
++def _setup_r_to_sage_converter():
++    """
++    Set up a the converter used to convert from rpy2's
++    representation of R objects to the one sage expects.
++
++    EXAMPLES::
++
++    Test
++
++    Simple numeric values are represented as vectors in R. So `1` would actually
++    be an array of length 1. We convert all vectors of length 1 to simple values,
++    whether or not they "originally" were simple values or not:
++
++        sage: r([42]).sage()
++        42
++
++        sage: r(42).sage()
++        42
++
++        sage: r('c("foo")').sage()
++        'foo'
++
++    Arrays of length greater than one are treated normally:
++
++        sage: r([42, 43]).sage()
++        [42, 43]
++
++    We also convert all numeric values to integers if that is possible without
++    loss of precision:
++
++        sage: type(r([1.0]).sage()) == int
++        True
++
++        sage: r([1.0, 42.5]).sage()
++        [1, 42.5]
++
++    Matrices are converted to sage matrices:
++
++        sage: r('matrix(c(2,4,3,1,5,7), nrow=2, ncol=3)').sage()
++        [2 3 5]
++        [4 1 7]
++
++    More complex r structures are represented by dictionaries:
++
++        sage: r.summary(1).sage()
++        {'DATA': [1, 1, 1, 1, 1, 1],
++         '_Names': ['Min.', '1st Qu.', 'Median', 'Mean', '3rd Qu.', 'Max.'],
++         '_r_class': ['summaryDefault', 'table']}
++
++        sage: r.options(width="60").sage()
++        {'DATA': {'width': 60}, '_Names': 'width'}
++
++    The conversion can handle "not a number", infintiy, imaginary values and
++    missing values:
++
++        sage: r(-17).sqrt().sage()
++        nan
++        sage: r('-17+0i').sqrt().sage()
++        4.123105625617661j
++        sage: r('NA').sage()
++        NA
++        sage: inf = r('Inf'); inf.sage()
++        inf
++
++
++    Character Vectors are represented by regular python arrays:
++
++        sage: labs = r.paste('c("X","Y")', '1:10', sep='""'); labs.sage()
++        ['X1', 'Y2', 'X3', 'Y4', 'X5', 'Y6', 'X7', 'Y8', 'X9', 'Y10']
++    """
++    from rpy2.rinterface import SexpVector, ListSexpVector, FloatSexpVector
++    from rpy2.robjects.conversion import Converter
++
++    # convert rpy2's representation of r objects to the one sage expects (as defined by the old
++    # expect interface)
++    cv = Converter('r to sage converter')
++
++    # fallback
++    cv.ri2py.register(object, lambda obj: obj)
++
++    def float_to_int_if_possible(f):
++        # preserve the behaviour of the old r parser, e.g. return 1 instead of 1.0
++        return int(f) if isinstance(f, int) or f.is_integer() else round(f, 16) # TODO investigate the rounding
++    cv.ri2py.register(float, float_to_int_if_possible)
++
++    def list_to_singleton_if_possible(l):
++        if len(l) == 1:
++            return l[0]
++        else:
++            return l
++
++    def _vector(vec):
++        attrs = vec.list_attrs()
++        # Recursive calls have to be made explicitly
++        # https://bitbucket.org/rpy2/rpy2/issues/363/custom-converters-are-not-applied
++        data = list_to_singleton_if_possible([ cv.ri2py(val) for val in vec ])
++        rclass = list(vec.do_slot('class')) if 'class' in attrs else vec.rclass
++
++        if 'names' in attrs:
++            # seperate names and values, call ri2py recursively to convert elements
++            names = list_to_singleton_if_possible(list(vec.do_slot('names')))
++            return {
++                'DATA': data,
++                '_Names': names,
++                '_r_class': rclass,
++            }
++        else:
++            # if no names are present, convert to a normal list or a single value
++            return data
++    cv.ri2py.register(SexpVector, _vector)
++
++    def _matrix(mat):
++        if 'dim' in mat.list_attrs():
++            try:
++                from sage.matrix.constructor import matrix
++                dimensions = mat.do_slot("dim")
++                # TODO: higher dimensions? happens often in statistics
++                if len(dimensions) != 2:
++                    raise TypeError
++                (nrow, ncol) = dimensions
++                #since R does it the other way round, we assign
++                #transposed and then transpose the matrix :)
++                m = matrix(ncol, nrow, [cv.ri2py(i) for i in mat])
++                return m.transpose()
++            except TypeError:
++                pass
++        else:
++            return _vector(mat)
++    cv.ri2py.register(FloatSexpVector, _matrix)
++
++    def _list_vector(vec):
++        # we have a R list (vector of arbitrary elements)
++        attrs = vec.list_attrs()
++        names = vec.do_slot('names')
++        values = [ cv.ri2py(val) for val in vec ]
++        rclass = list(vec.do_slot('class')) if 'class' in attrs else vec.rclass
++        data = zip(names, values)
++        return {
++            'DATA': dict(data),
++            '_Names': cv.ri2py(names),
++            # '_r_class': rclass, # FIXME why not?
++        };
++    cv.ri2py.register(ListSexpVector, _list_vector)
++
++    return cv
++
++class R(ExtraTabCompletion, Interface):
+     def __init__(self,
+-                 maxread=None, script_subdirectory=None,
+-                 server_tmpdir = None,
++                 maxread=None,
+                  logfile=None,
+-                 server=None,
+                  init_list_length=1024,
+                  seed=None):
+         """
+@@ -319,46 +463,19 @@ class R(ExtraTabCompletion, Expect):
+             sage: r == loads(dumps(r))
+             True
+         """
+-        Expect.__init__(self,
+ 
+-                  # The capitalized version of this is used for printing.
+-                  name = 'r',
++        Interface.__init__(
++                self,
++                name = 'r', # The capitalized version of this is used for printing.
++        )
+ 
+-                  # This is regexp of the input prompt.  If you can change
+-                  # it to be very obfuscated that would be better.   Even
+-                  # better is to use sequence numbers.
+-                  # options(prompt=\"<prompt> \")
+-                  prompt = '> ', #default, later comes the change
++        # It would be better to make this an attribute of `R`, but that leads to problems since
++        # we override `__getattr__`.
++        global _r_to_sage_converter
++        _r_to_sage_converter = _setup_r_to_sage_converter()
+ 
+-                  # This is the command that starts up your program
+-                  # See #25806 for the --no-readline switch which fixes hangs for some
+-                  command = "R --no-readline --vanilla --quiet",
+-
+-                  server=server,
+-                  server_tmpdir=server_tmpdir,
+-
+-                  script_subdirectory = script_subdirectory,
+-
+-                  # If this is true, then whenever the user presses Control-C to
+-                  # interrupt a calculation, the whole interface is restarted.
+-                  restart_on_ctrlc = False,
+-
+-                  # If true, print out a message when starting
+-                  # up the command when you first send a command
+-                  # to this interface.
+-                  verbose_start = False,
+-
+-                  logfile=logfile,
+-
+-                  # If an input is longer than this number of characters, then
+-                  # try to switch to outputting to a file.
+-                  eval_using_file_cutoff=1024)
+-
+-        self.__seq = 0
+-        self.__var_store_len = 0
+-        self.__init_list_length = init_list_length
+-        self._prompt_wait = [self._prompt]
+         self._seed = seed
++        self._start()
+ 
+     def set_seed(self, seed=None):
+         """
+@@ -391,14 +508,10 @@ class R(ExtraTabCompletion, Expect):
+             sage: r = R()
+             sage: r._start()
+         """
+-        Expect._start(self)
+-
+         # width is line width, what's a good value? maximum is 10000!
+         # pager needed to replace help view from less to printout
+         # option device= is for plotting, is set to x11, NULL would be better?
+-        self._change_prompt(PROMPT)
+-        self.eval('options(prompt=\"%s\",continue=\"%s\", width=100,pager="cat",device="png")'%(PROMPT, PROMPT))
+-        self.expect().expect(PROMPT)
++        self.eval('options(width=100,pager="cat",device="png")')
+         self.eval('options(repos="%s")'%RRepositoryURL)
+         self.eval('options(CRAN="%s")'%RRepositoryURL)
+ 
+@@ -669,22 +782,17 @@ class R(ExtraTabCompletion, Expect):
+             ...
+             ImportError: ...
+         """
+-        ret = self.eval('require("%s")' % library_name)
+-        if six.PY2:
+-            try:
+-                ret = ret.decode('utf-8')
+-            except UnicodeDecodeError:
+-                ret = ret.decode('latin-1')
+-        # try hard to parse the message string in a locale-independent way
+-        if ' library(' in ret:       # locale-independent key-word
+-            raise ImportError("%s"%ret)
++        if robjects.packages.isinstalled(library_name):
++            robjects.packages.importr(library_name)
+         else:
+-            try:
+-                # We need to rebuild keywords!
+-                del self.__tab_completion
+-            except AttributeError:
+-                pass
+-            self._tab_completion(verbose=False, use_disk_cache=False)
++            raise ImportError("R library {} not installed".format(library_name))
++
++        try:
++            # We need to rebuild keywords!
++            del self.__tab_completion
++        except AttributeError:
++            pass
++        self._tab_completion(verbose=False, use_disk_cache=False)
+ 
+     require = library #overwrites require
+ 
+@@ -789,17 +897,24 @@ class R(ExtraTabCompletion, Expect):
+         EXAMPLES::
+ 
+             sage: r.help('c')
+-            c                     package:base                     R Documentation
++            title
++            -----
++            <BLANKLINE>
++            Combine Values into a Vector or List 
++            <BLANKLINE>
++            name
++            ----
++            <BLANKLINE>
++            c
+             ...
+-
+-            .. note::
+-
+-                This is similar to typing r.command?.
+         """
+-        s = self.eval('help("%s")'%command).strip()     # ?cmd is only an unsafe shortcut
++        s = robjects.help.pages(command)[0].to_docstring()
++
++        # TODO what is this for?
+         import sage.plot.plot
+         if sage.plot.plot.EMBEDDED_MODE:
+             s = s.replace('_\x08','')
++
+         return HelpExpression(s)
+ 
+     def _assign_symbol(self):
+@@ -914,9 +1029,19 @@ class R(ExtraTabCompletion, Expect):
+             '[1] 5'
+         """
+         cmd = '%s <- %s'%(var,value)
+-        out = self.eval(cmd)
+-        if out.find("error") != -1:
+-            raise TypeError("Error executing code in R\nCODE:\n\t%s\nR ERROR:\n\t%s"%(cmd, out))
++        # FIXME this is how it behaved before since the output was only compared to 'error'
++        # while the actual error message started with an upper-case 'Error'.
++        # The doctests rely on this when doing `loads(dumps(r('"abc"')))` which will load
++        # simply `"abc"` which will then again be set as `sage0 <- abc` (notice the missing
++        # quotes). The test will pass anyway because the identifier is reused for some reason.
++        # That means `sage0` will already be "abc" from the first `r('"abc"')` call.
++        from rpy2.rinterface import RRuntimeWarning, RRuntimeError
++        import warnings
++        warnings.filterwarnings("ignore", category = RRuntimeWarning)
++        try:
++            out = self.eval(cmd)
++        except RRuntimeError:
++            pass
+ 
+     def get(self, var):
+         """
+@@ -934,9 +1059,20 @@ class R(ExtraTabCompletion, Expect):
+             sage: r.get('a')
+             '[1] 2'
+         """
+-        s = self.eval('%s'%var)
+-        #return self._remove_indices_re.sub("", s).strip()
+-        return s
++        # FIXME again, this is how it behaved before. The doctest `L.hom(r, base_morphism=phi)`
++        # in sage/rings/function_field/function_field.py relies on this. It somehow ends up
++        # requesting a non-existant r object resulting in
++        # `RRuntimeError: Error in (function (expr, envir = parent.frame(), enclos = if (is.list(envir) ||  : 
++        #     object 'sage2' not found`
++        # I haven't figured out how or why it does that.
++        from rpy2.rinterface import RRuntimeWarning, RRuntimeError
++        import warnings
++        warnings.filterwarnings("ignore", category = RRuntimeWarning)
++        try:
++            s = self.eval('%s'%var)
++            return s
++        except RRuntimeError:
++            return ''
+ 
+     def na(self):
+         """
+@@ -966,7 +1102,12 @@ class R(ExtraTabCompletion, Expect):
+ 
+             sage: dummy = r._tab_completion(use_disk_cache=False)    #clean doctest
+             sage: r.completions('tes')
+-            ['testInheritedMethods', 'testPlatformEquivalence', 'testVirtual']
++            ['testInheritedMethods',
++             'testInstalledBasic',
++             'testInstalledPackage',
++             'testInstalledPackages',
++             'testPlatformEquivalence',
++             'testVirtual']
+         """
+         return [name for name in self._tab_completion() if name[:len(s)] == s]
+ 
+@@ -986,8 +1127,7 @@ class R(ExtraTabCompletion, Expect):
+         """
+         v = RBaseCommands
+ 
+-        ll = self.eval('dput(search())') # loaded libs
+-        ll = self.convert_r_list(ll)
++        ll = self('search()')._sage_() # loaded libs
+ 
+         for lib in ll:
+             if lib in RFilteredPackages:
+@@ -996,9 +1136,7 @@ class R(ExtraTabCompletion, Expect):
+             if lib.find("package:") != 0:
+                 continue #only packages
+ 
+-            raw = self.eval('dput(objects("%s"))'%lib)
+-            raw = self.convert_r_list(raw)
+-            raw = [x.replace(".","_") for x in raw]
++            raw = self('objects("%s")'%lib)._sage_()
+ 
+             #TODO are there others? many of them are shortcuts or
+             #should be done on another level, like selections in lists
+@@ -1123,24 +1261,6 @@ class R(ExtraTabCompletion, Expect):
+         RFunction(self, 'plot')(*args, **kwds)
+         return RFunction(self, 'dev.off')()
+ 
+-    def _strip_prompt(self, code):
+-        """
+-        Remove the standard R prompt from the beginning of lines in code.
+-
+-        INPUT:
+-
+-        - code -- a string
+-
+-        OUTPUT: a string
+-
+-        EXAMPLES::
+-
+-            sage: s = '> a <- 2\n> b <- 3'
+-            sage: r._strip_prompt(s)
+-            ' a <- 2\n b <- 3'
+-        """
+-        return prompt_re.sub("", code)
+-
+     def eval(self, code, globals=None, locals=None, synchronize=True, *args, **kwds):
+         """
+         Evaluates a command inside the R interpreter and returns the output
+@@ -1151,9 +1271,8 @@ class R(ExtraTabCompletion, Expect):
+             sage: r.eval('1+1')
+             '[1] 2'
+         """
+-        # TODO split code at ";" outside of quotes and send them as individual
+-        #      lines without ";".
+-        return Expect.eval(self, code, synchronize=synchronize, *args, **kwds)
++        return str(robjects.r(code)).rstrip()
++
+ 
+     def _r_to_sage_name(self, s):
+         """
+@@ -1255,16 +1374,8 @@ class R(ExtraTabCompletion, Expect):
+         self.execute('setwd(%r)' % dir)
+ 
+ 
+-# patterns for _sage_()
+-rel_re_param = re.compile(r'\s([\w\.]+)\s=')
+-rel_re_range = re.compile(r'([\d]+):([\d]+)')
+-rel_re_integer = re.compile(r'([^\d])([\d]+)L')
+-rel_re_terms = re.compile(r'terms\s*=\s*(.*?),')
+-rel_re_call = re.compile(r'call\s*=\s*(.*?)\),')
+-
+-
+ @instancedoc
+-class RElement(ExtraTabCompletion, ExpectElement):
++class RElement(ExtraTabCompletion, InterfaceElement):
+ 
+     def _tab_completion(self):
+         """
+@@ -1315,7 +1426,7 @@ class RElement(ExtraTabCompletion, ExpectElement):
+             sage: len(x)
+             5
+         """
+-        return int(self.parent().eval('dput(length(%s))'%self.name())[:-1] )
++        return self.parent()('length(%s)'%self.name())._sage_()
+ 
+     def __getattr__(self, attrname):
+         """
+@@ -1777,95 +1888,9 @@ class RElement(ExtraTabCompletion, ExpectElement):
+         self._check_valid()
+         P = self.parent()
+ 
+-        # This is the core of the trick: using dput
+-        # dput prints out the internal structure of R's data elements
+-        # options via .deparseOpts(control=...)
+-        # TODO: dput also works with a file, if things get huge!
+-        # [[However, using a file for output often isn't necessary
+-        # since pipe buffering works pretty well for output.
+-        # That said, benchmark this.  -- William Stein]]
+-        exp = P.eval('dput(%s)'%self.name())
+-
+-        # Preprocess expression
+-        # example what this could be:
+-        # structure(list(statistic = structure(0.233549683248457, .Names = "t"),
+-        # parameter = structure(5.58461538461538, .Names = "df"), p.value = 0.823657802106985,
+-        # conf.int = structure(c(-2.41722062247400, 2.91722062247400
+-        # ), conf.level = 0.95), estimate = structure(c(2.75, 2.5), .Names = c("mean of x",
+-        # "mean of y")), null.value = structure(0, .Names = "difference in means"),
+-        # alternative = "two.sided", method = "Welch Two Sample t-test",
+-        # data.name = "c(1, 2, 3, 5) and c(1, 2, 3, 4)"), .Names = c("statistic",
+-        # "parameter", "p.value", "conf.int", "estimate", "null.value",
+-        # "alternative", "method", "data.name"), class = "htest")
+-
+-        # R's structure (from help):
+-        # structure(.Data, ...)
+-        #    .Data: an object which will have various attributes attached to it.
+-        #    ...: attributes, specified in 'tag=value' form, which will be
+-        #         attached to data.
+-        #For historical reasons (these names are used when deparsing),
+-        # attributes '".Dim"', '".Dimnames"', '".Names"', '".Tsp"' and
+-        # '".Label"' are renamed to '"dim"', '"dimnames"', '"names"',
+-        # '"tsp"' and '"levels"'.
+-
+-
+-
+-        # we want this in a single line
+-        exp.replace('\n','')
+-        exp = "".join(exp.split("\n"))
+-
+-        # python compatible parameters
+-        exp = rel_re_param.sub(self._subs_dots, exp)
+-
+-        # Rename class since it is a Python keyword
+-        exp = re.sub(' class = ', ' _r_class = ',exp)
+-
+-        # Change 'structure' to '_r_structure'
+-        # TODO: check that we are outside of quotes ""
+-        exp = re.sub(r' structure\(', ' _r_structure(', exp)
+-        exp = re.sub(r'^structure\(', '_r_structure(', exp)  # special case
+-
+-        # Change 'list' to '_r_list'
+-        exp = re.sub(r' list\(', ' _r_list(', exp)
+-        exp = re.sub(r'\(list\(', '(_r_list(', exp)
+-
+-        # Change 'a:b' to 'range(a,b+1)'
+-        exp = rel_re_range.sub(self._subs_range, exp)
+-
+-        # Change 'dL' to 'Integer(d)'
+-        exp = rel_re_integer.sub(self._subs_integer, exp)
+-
+-        # Wrap the right hand side of terms = ... in quotes since it
+-        # has a ~ in it.
+-        exp = rel_re_terms.sub(r'terms = "\1",', exp)
+-
+-
+-        # Change call = ..., to call = "...",
+-        exp = rel_re_call.sub(r'call = "\1",', exp)
+-
+-        # seems to work for
+-        # rr = r.summary(r.princomp(r.matrix(r.c(1,2,3,4,3,4,1,2,2),4)))
+-        # rr._sage_()
+-        # but the call expression get's evaluated. why?!? TODO
+-
+-
+-        # translation:
+-        # c is an ordered list
+-        # list is a dictionary (where _Names give the entries names.
+-        #    map entries in names to (value, name) in each entry?
+-        # structure is .. see above .. structure(DATA,**kw)
+-        # TODO: thinking of just replacing c( with ( to get a long tuple?
+-
+-
+-        exp = self._convert_nested_r_list(exp)
+-
+-        # Set up the globals
+-        globs = {'NA':None, 'NULL':None, 'FALSE':False, 'TRUE':True,
+-                 '_r_list':self._r_list, '_r_structure':self._r_structure,
+-                 'Integer':sage.rings.integer.Integer,
+-                 'character':str}
+-
+-        return eval(exp, globs, globs)
++        with localconverter(_r_to_sage_converter) as cv:
++            parsed = robjects.r(self.name())
++            return parsed
+ 
+ 
+     def _latex_(self):
+@@ -1893,7 +1918,7 @@ class RElement(ExtraTabCompletion, ExpectElement):
+ 
+ 
+ @instancedoc
+-class RFunctionElement(FunctionElement):
++class RFunctionElement(InterfaceFunctionElement):
+     def __reduce__(self):
+         """
+         EXAMPLES::
+@@ -1917,9 +1942,16 @@ class RFunctionElement(FunctionElement):
+             sage: a = r([1,2,3])
+             sage: length = a.length
+             sage: print(length.__doc__)
+-            length                 package:base                 R Documentation
+-            ...
++            title
++            -----
++            <BLANKLINE>
++            Length of an Object 
++            <BLANKLINE>
++            name
++            ----
+             <BLANKLINE>
++            length
++            ...
+         """
+         M = self._obj.parent()
+         return M.help(self._name)
+@@ -1951,7 +1983,7 @@ class RFunctionElement(FunctionElement):
+ 
+ 
+ @instancedoc
+-class RFunction(ExpectFunction):
++class RFunction(InterfaceFunction):
+     def __init__(self, parent, name, r_name=None):
+         """
+         A Function in the R interface.
+@@ -2007,9 +2039,16 @@ class RFunction(ExpectFunction):
+ 
+             sage: length = r.length
+             sage: print(length.__doc__)
+-            length                 package:base                 R Documentation
+-            ...
++            title
++            -----
++            <BLANKLINE>
++            Length of an Object 
+             <BLANKLINE>
++            name
++            ----
++            <BLANKLINE>
++            length
++            ...
+         """
+         M = self._parent
+         return M.help(self._name)
+diff --git a/src/sage/stats/r.py b/src/sage/stats/r.py
+index cd2002559b..8a2f243901 100644
+--- a/src/sage/stats/r.py
++++ b/src/sage/stats/r.py
+@@ -39,12 +39,12 @@ def ttest(x,y,conf_level = 0.95, **kw):
+ 
+    Example::
+ 
+-      sage: a, b = ttest([1,2,3,4,5],[1,2,3,3.5,5.121]); a
+-      0.941026372027427
++      sage: a, b = ttest([1,2,3,4,5],[1,2,3,3.5,5.121]); a # abs tol 1e-12
++      0.9410263720274274
+    """
+    if len(x) != len(y):
+       raise AttributeError("vectors x and y must be of same length")
+ 
+    test = myR.t_test(x,y,conf_level = conf_level, **kw)._sage_()
+-   t = test.get('DATA').get('p_value')
++   t = test.get('DATA').get('p.value')
+    return t, test
diff --git a/pkgs/applications/science/math/sage/sage-src.nix b/pkgs/applications/science/math/sage/sage-src.nix
index c166a17fafc7..8bbbebcca03d 100644
--- a/pkgs/applications/science/math/sage/sage-src.nix
+++ b/pkgs/applications/science/math/sage/sage-src.nix
@@ -9,14 +9,14 @@
 # all get the same sources with the same patches applied.
 
 stdenv.mkDerivation rec {
-  version = "8.5.beta0";
+  version = "8.5.beta1";
   name = "sage-src-${version}";
 
   src = fetchFromGitHub {
     owner = "sagemath";
     repo = "sage";
     rev = version;
-    sha256 = "0kc8fqwz97dwyf4hxz5yr9sjwh5q0jr7a9g1yrdaz66m5805r859";
+    sha256 = "0pxalw7kw8zdnn51yp3s81c6r5m9a500f9yn14s2883jyag9yiz1";
   };
 
   # Patches needed because of particularities of nix or the way this is packaged.