From deadf9728833d6a1a82fb9b3064efb5b1ff9d083 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 29 Mar 2023 16:31:51 -0700 Subject: [PATCH 01/13] src/sage/doctest/forker.py: Run clean_namespace on the globals of each test --- src/sage/doctest/forker.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/doctest/forker.py b/src/sage/doctest/forker.py index 35f473b40f9..edde96a9b65 100644 --- a/src/sage/doctest/forker.py +++ b/src/sage/doctest/forker.py @@ -889,6 +889,10 @@ def run(self, test, compileflags=0, out=None, clear_globs=True): warnings.showwarning = showwarning_with_traceback self.running_doctest_digest = hashlib.md5() self.test = test + # Because test is a copy, we need to + # relink imported lazy_import objects to point to the appropriate namespace + from sage.misc.lazy_import import clean_namespace + clean_namespace(test.globs) # We use this slightly modified version of Pdb because it # interacts better with the doctesting framework (like allowing # doctests for sys.settrace()). Since we already have output From 8f79bb6b01aea3151330c87c0fd93865c8188b5e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 29 Mar 2023 16:32:41 -0700 Subject: [PATCH 02/13] src/sage/interfaces/r.py: No comma between # optional tags --- src/sage/interfaces/r.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/interfaces/r.py b/src/sage/interfaces/r.py index 3a1e640d657..289b73b3754 100644 --- a/src/sage/interfaces/r.py +++ b/src/sage/interfaces/r.py @@ -1274,7 +1274,7 @@ def plot(self, *args, **kwds): persistent in your own code:: sage: from tempfile import TemporaryDirectory - sage: with TemporaryDirectory() as d: # optional - rpy2, rgraphics + sage: with TemporaryDirectory() as d: # optional - rpy2 rgraphics ....: _ = r.setwd(d) ....: r.plot("1:10") null device From 3c9d48a8848334287e6de280bc756001d1a827e1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 29 Mar 2023 16:34:13 -0700 Subject: [PATCH 03/13] src/sage/interfaces/r.py: Resolve lazy import of 'r' before pickling it --- src/sage/interfaces/r.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/interfaces/r.py b/src/sage/interfaces/r.py index 289b73b3754..10b54871cca 100644 --- a/src/sage/interfaces/r.py +++ b/src/sage/interfaces/r.py @@ -706,8 +706,10 @@ def __reduce__(self): EXAMPLES:: - sage: rlr, t = r.__reduce__() # optional - rpy2 - sage: rlr(*t) # optional - rpy2 + sage: r # resolve lazy import # optional - rpy2 + R Interpreter + sage: rlr, t = r.__reduce__() # optional - rpy2 + sage: rlr(*t) # optional - rpy2 R Interpreter """ return reduce_load_R, tuple([]) From a924096755785f5a2581f4d2e98cf30c98891e57 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 29 Mar 2023 17:33:18 -0700 Subject: [PATCH 04/13] src/sage/interfaces/r.py: Make imports from rpy2 to lazy_import with feature --- src/sage/interfaces/r.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/sage/interfaces/r.py b/src/sage/interfaces/r.py index 10b54871cca..6936b673f96 100644 --- a/src/sage/interfaces/r.py +++ b/src/sage/interfaces/r.py @@ -279,13 +279,20 @@ # see the _lazy_init for some reasoning behind the lazy imports from sage.misc.lazy_import import lazy_import -lazy_import("rpy2", "robjects") -lazy_import("rpy2.robjects", "packages", "rpy2_packages") -lazy_import("rpy2.robjects.conversion", "localconverter") +from sage.features import PythonModule + +rpy2_feature = PythonModule('rpy2', spkg='rpy2') + +lazy_import("rpy2", "robjects", feature=rpy2_feature) +lazy_import("rpy2.robjects", "packages", "rpy2_packages", feature=rpy2_feature) +lazy_import("rpy2.robjects.conversion", ["localconverter", "Converter"], feature=rpy2_feature) +lazy_import("rpy2.rinterface", ["SexpVector", "ListSexpVector", "FloatSexpVector"], + feature=rpy2_feature) # for help page fetching -lazy_import("rpy2.robjects.help", "Package") -lazy_import("rpy2", "rinterface") +lazy_import("rpy2.robjects.help", "Package", feature=rpy2_feature) +lazy_import("rpy2", "rinterface", feature=rpy2_feature) + COMMANDS_CACHE = '%s/r_commandlist.sobj' % DOT_SAGE @@ -367,9 +374,6 @@ def _setup_r_to_sage_converter(): sage: labs = r.paste('c("X","Y")', '1:10', sep='""'); labs.sage() # optional - rpy2 ['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') From b156781b20320fc6bdcd4167eec248f1920aab8d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 16 Apr 2024 22:38:59 -0700 Subject: [PATCH 05/13] build/pkgs/{r,rpy2}: Explain dummy / pseudo-standard package type --- build/pkgs/r/SPKG.rst | 11 +++++++++++ build/pkgs/rpy2/SPKG.rst | 14 +++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/build/pkgs/r/SPKG.rst b/build/pkgs/r/SPKG.rst index 584294e891a..393860a2064 100644 --- a/build/pkgs/r/SPKG.rst +++ b/build/pkgs/r/SPKG.rst @@ -24,3 +24,14 @@ Upstream Contact - https://www.r-project.org - R mailing list, #R in IRC + + +Special Installation Instructions +--------------------------------- + +In the Sage distribution, ``r`` is a "dummy" package: +It is here to provide information about equivalent system packages. +R cannot be installed using the Sage distribution. +Please install it manually, either using one of the system package +commands shown here or following the upstream instructions +at https://www.r-project.org diff --git a/build/pkgs/rpy2/SPKG.rst b/build/pkgs/rpy2/SPKG.rst index 3ba34445021..ba81ab6c098 100644 --- a/build/pkgs/rpy2/SPKG.rst +++ b/build/pkgs/rpy2/SPKG.rst @@ -12,12 +12,16 @@ License ------- - GPL 2+ -- Note that we have deleted references to Mozilla PL as an option, - which we are allowed to do by the full rpy2 license in order to - remain GPL-compatible - Upstream Contact ---------------- -- https://rpy2.bitbucket.io +- https://github.com/rpy2/rpy2 + +Special Installation Instructions +--------------------------------- + +In the Sage distribution, ``rpy2`` is a "semi-standard" package: It will be +automatically installed by the Sage distribution if a suitable system +installation of R is detected by ``configure``. (Note that Sage no longer +ships and installs its own copy of R.) From 6b11f2df63a25aa0a18ceae0d460e8b50b5375ef Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 16 Apr 2024 22:39:48 -0700 Subject: [PATCH 06/13] Revert "src/sage/features/standard.py: Remove rpy2 feature for now" This reverts commit 999030298cfd998fece7e613f8f3dbd24146f713. --- src/sage/features/standard.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/features/standard.py b/src/sage/features/standard.py index c2090fc53a4..0dc27d8a4e7 100644 --- a/src/sage/features/standard.py +++ b/src/sage/features/standard.py @@ -32,5 +32,6 @@ def all_features(): PythonModule('ptyprocess', spkg='ptyprocess', type='standard'), PythonModule('pyparsing', spkg='pyparsing', type='standard'), PythonModule('requests', spkg='requests', type='standard'), + PythonModule('rpy2', spkg='rpy2', type='standard'), PythonModule('scipy', spkg='scipy', type='standard'), PythonModule('sympy', spkg='sympy', type='standard')] From 0f4fbfd1436e9ff9484b6c97a0d1aa1fd4a5e562 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 16 Apr 2024 22:50:12 -0700 Subject: [PATCH 07/13] src/sage/interfaces/r.py: Use file-level # needs tag --- src/sage/interfaces/r.py | 356 ++++++++++++++++++--------------------- 1 file changed, 168 insertions(+), 188 deletions(-) diff --git a/src/sage/interfaces/r.py b/src/sage/interfaces/r.py index 6936b673f96..f49735b028a 100644 --- a/src/sage/interfaces/r.py +++ b/src/sage/interfaces/r.py @@ -1,3 +1,4 @@ +# sage.doctest: needs rpy2 r""" Interfaces to R @@ -24,21 +25,21 @@ vector named `x` using the R interface in Sage, you pass the R interpreter object a list or tuple of numbers:: - sage: x = r([10.4,5.6,3.1,6.4,21.7]); x # optional - rpy2 + sage: x = r([10.4,5.6,3.1,6.4,21.7]); x [1] 10.4 5.6 3.1 6.4 21.7 You can invert elements of a vector x in R by using the invert operator or by doing 1/x:: - sage: ~x # optional - rpy2 + sage: ~x [1] 0.09615385 0.17857143 0.32258065 0.15625000 0.04608295 - sage: 1/x # optional - rpy2 + sage: 1/x [1] 0.09615385 0.17857143 0.32258065 0.15625000 0.04608295 The following assignment creates a vector `y` with 11 entries which consists of two copies of `x` with a 0 in between:: - sage: y = r([x,0,x]); y # optional - rpy2 + sage: y = r([x,0,x]); y [1] 10.4 5.6 3.1 6.4 21.7 0.0 10.4 5.6 3.1 6.4 21.7 Vector Arithmetic @@ -47,25 +48,24 @@ by adding together (element by element) `2x` repeated 2.2 times, `y` repeated just once, and 1 repeated 11 times:: - sage: v = 2*x+y+1; v # optional - rpy2 + sage: v = 2*x+y+1; v [1] 32.2 17.8 10.3 20.2 66.1 21.8 22.6 12.8 16.9 50.8 43.5 One can compute the sum of the elements of an R vector in the following two ways:: - sage: sum(x) # optional - rpy2 + sage: sum(x) [1] 47.2 - sage: x.sum() # optional - rpy2 + sage: x.sum() [1] 47.2 One can calculate the sample variance of a list of numbers:: - sage: ((x-x.mean())^2/(x.length()-1)).sum() # optional - rpy2 + sage: ((x-x.mean())^2/(x.length()-1)).sum() [1] 53.853 - sage: x.var() # optional - rpy2 + sage: x.var() [1] 53.853 - sage: # optional - rpy2 sage: x.sort() [1] 3.1 5.6 6.4 10.4 21.7 sage: x.min() @@ -75,24 +75,23 @@ sage: x [1] 10.4 5.6 3.1 6.4 21.7 - sage: r(-17).sqrt() # optional - rpy2 + sage: r(-17).sqrt() [1] NaN - sage: r('-17+0i').sqrt() # optional - rpy2 + sage: r('-17+0i').sqrt() [1] 0+4.123106i Generating an arithmetic sequence:: - sage: r('1:10') # optional - rpy2 + sage: r('1:10') [1] 1 2 3 4 5 6 7 8 9 10 Because ``from`` is a keyword in Python, it can't be used as a keyword argument. Instead, ``from_`` can be passed, and R will recognize it as the correct thing:: - sage: r.seq(length=10, from_=-1, by=.2) # optional - rpy2 + sage: r.seq(length=10, from_=-1, by=.2) [1] -1.0 -0.8 -0.6 -0.4 -0.2 0.0 0.2 0.4 0.6 0.8 - sage: # optional - rpy2 sage: x = r([10.4,5.6,3.1,6.4,21.7]) sage: x.rep(2) [1] 10.4 5.6 3.1 6.4 21.7 10.4 5.6 3.1 6.4 21.7 @@ -103,7 +102,6 @@ Missing Values:: - sage: # optional - rpy2 sage: na = r('NA') sage: z = r([1,2,3,na]) sage: z @@ -135,19 +133,18 @@ Character Vectors:: - sage: labs = r.paste('c("X","Y")', '1:10', sep='""'); labs # optional - rpy2 + sage: labs = r.paste('c("X","Y")', '1:10', sep='""'); labs [1] "X1" "Y2" "X3" "Y4" "X5" "Y6" "X7" "Y8" "X9" "Y10" Index vectors; selecting and modifying subsets of a data set:: - sage: na = r('NA') # optional - rpy2 - sage: x = r([10.4,5.6,3.1,6.4,21.7,na]); x # optional - rpy2 + sage: na = r('NA') + sage: x = r([10.4,5.6,3.1,6.4,21.7,na]); x [1] 10.4 5.6 3.1 6.4 21.7 NA - sage: x['!is.na(self)'] # optional - rpy2 + sage: x['!is.na(self)'] [1] 10.4 5.6 3.1 6.4 21.7 - sage: # optional - rpy2 sage: x = r([10.4,5.6,3.1,6.4,21.7,na]); x [1] 10.4 5.6 3.1 6.4 21.7 NA sage: (x+1)['(!is.na(self)) & self>0'] @@ -159,12 +156,12 @@ Distributions:: - sage: r.options(width="60") # optional - rpy2 + sage: r.options(width="60") $width [1] 80 - sage: rr = r.dnorm(r.seq(-3,3,0.1)) # optional - rpy2 - sage: rr # optional - rpy2 + sage: rr = r.dnorm(r.seq(-3,3,0.1)) + sage: rr [1] 0.004431848 0.005952532 0.007915452 0.010420935 [5] 0.013582969 0.017528300 0.022394530 0.028327038 [9] 0.035474593 0.043983596 0.053990967 0.065615815 @@ -184,13 +181,12 @@ Convert R Data Structures to Python/Sage:: - sage: rr = r.dnorm(r.seq(-3,3,0.1)) # optional - rpy2 - sage: sum(rr._sage_()) # optional - rpy2 + sage: rr = r.dnorm(r.seq(-3,3,0.1)) + sage: sum(rr._sage_()) 9.9772125168981... Or you get a dictionary to be able to access all the information:: - sage: # optional - rpy2 sage: rs = r.summary(r.c(1,4,3,4,3,2,5,1)) sage: rs Min. 1st Qu. Median Mean 3rd Qu. Max. @@ -317,49 +313,48 @@ def _setup_r_to_sage_converter(): length 1 to simple values, whether or not they "originally" were simple values or not:: - sage: r([42]).sage() # optional - rpy2 + sage: r([42]).sage() 42 - sage: r(42).sage() # optional - rpy2 + sage: r(42).sage() 42 - sage: r('c("foo")').sage() # optional - rpy2 + sage: r('c("foo")').sage() 'foo' Arrays of length greater than one are treated normally:: - sage: r([42, 43]).sage() # optional - rpy2 + 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 # optional - rpy2 + sage: type(r([1.0]).sage()) == int True - sage: r([1.0, 42.5]).sage() # optional - rpy2 + 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() # optional - rpy2 + 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() # optional - rpy2 + 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() # optional - rpy2 + sage: r.options(width="60").sage() {'DATA': {'width': 60}, '_Names': 'width'} The conversion can handle "not a number", infinity, imaginary values and missing values:: - sage: # optional - rpy2 sage: r(-17).sqrt().sage() nan sage: r('-17+0i').sqrt().sage() @@ -371,7 +366,7 @@ def _setup_r_to_sage_converter(): Character Vectors are represented by regular python arrays:: - sage: labs = r.paste('c("X","Y")', '1:10', sep='""'); labs.sage() # optional - rpy2 + sage: labs = r.paste('c("X","Y")', '1:10', sep='""'); labs.sage() ['X1', 'Y2', 'X3', 'Y4', 'X5', 'Y6', 'X7', 'Y8', 'X9', 'Y10'] """ # convert rpy2's representation of r objects to the one sage expects (as defined by the old @@ -479,13 +474,13 @@ def __init__(self, EXAMPLES:: - sage: r.summary(r.c(1,2,3,111,2,3,2,3,2,5,4)) # optional - rpy2 + sage: r.summary(r.c(1,2,3,111,2,3,2,3,2,5,4)) Min. 1st Qu. Median Mean 3rd Qu. Max. 1.00 2.00 3.00 12.55 3.50 111.00 TESTS:: - sage: r == loads(dumps(r)) # optional - rpy2 + sage: r == loads(dumps(r)) True """ Interface.__init__( @@ -516,7 +511,6 @@ def _lazy_init(self): Initialization happens on eval:: - sage: # optional - rpy2 sage: my_r = R() sage: my_r._initialized False @@ -527,7 +521,6 @@ def _lazy_init(self): And on package import:: - sage: # optional - rpy2 sage: my_r = R() sage: my_r._initialized False @@ -537,7 +530,6 @@ def _lazy_init(self): And when fetching help pages:: - sage: # optional - rpy2 sage: my_r = R() sage: my_r._initialized False @@ -558,7 +550,7 @@ def _coerce_impl(self, x, use_special=True): Check conversion of Booleans (:issue:`28705`):: - sage: repr(r(True)) == r._true_symbol() # indirect doctest # optional - rpy2 + sage: repr(r(True)) == r._true_symbol() # indirect doctest True """ # We overwrite _coerce_impl here because r._true_symbol() and @@ -576,10 +568,10 @@ def set_seed(self, seed=None): EXAMPLES:: - sage: r = R() # optional - rpy2 - sage: r.set_seed(1) # optional - rpy2 + sage: r = R() + sage: r.set_seed(1) 1 - sage: r.sample("1:10", 5) # random # optional - rpy2 + sage: r.sample("1:10", 5) # random [1] 3 4 5 7 2 """ if seed is None: @@ -596,8 +588,8 @@ def _start(self): EXAMPLES:: - sage: r = R() # optional - rpy2 - sage: r._start() # optional - rpy2 + sage: r = R() + sage: r._start() """ # pager needed to replace help view from less to printout # option device= is for plotting, is set to x11, NULL would be better? @@ -626,23 +618,22 @@ def png(self, *args, **kwds): EXAMPLES:: - sage: # optional - rpy2 sage: filename = tmp_filename() + '.png' - sage: r.png(filename='"%s"'%filename) # optional - rgraphics + sage: r.png(filename='"%s"'%filename) # optional - rgraphics NULL sage: x = r([1,2,3]) sage: y = r([4,5,6]) - sage: r.plot(x,y) # optional - rgraphics + sage: r.plot(x,y) # optional - rgraphics null device 1 - sage: import os; os.unlink(filename) # optional - rgraphics + sage: import os; os.unlink(filename) # optional - rgraphics We want to make sure that we actually can view R graphics, which happens differently on different platforms:: - sage: s = r.eval('capabilities("png")') # Should be on Linux and Solaris # optional - rpy2 - sage: t = r.eval('capabilities("aqua")') # Should be on all supported Mac versions # optional - rpy2 - sage: "TRUE" in s+t # optional -- rgraphics # optional - rpy2 + sage: s = r.eval('capabilities("png")') # Should be on Linux and Solaris + sage: t = r.eval('capabilities("aqua")') # Should be on all supported Mac versions + sage: "TRUE" in s+t # optional - rgraphics True """ # Check to see if R has PNG support @@ -658,8 +649,8 @@ def convert_r_list(self, l): EXAMPLES:: - sage: s = 'c(".GlobalEnv", "package:stats", "package:graphics", "package:grDevices", \n"package:utils", "package:datasets", "package:methods", "Autoloads", \n"package:base")' # optional - rpy2 - sage: r.convert_r_list(s) # optional - rpy2 + sage: s = 'c(".GlobalEnv", "package:stats", "package:graphics", "package:grDevices", \n"package:utils", "package:datasets", "package:methods", "Autoloads", \n"package:base")' + sage: r.convert_r_list(s) ['.GlobalEnv', 'package:stats', 'package:graphics', @@ -681,7 +672,7 @@ def install_packages(self, package_name): EXAMPLES:: - sage: r.install_packages('aaMI') # not tested # optional - rpy2 + sage: r.install_packages('aaMI') # not tested ... R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. @@ -699,7 +690,7 @@ def _repr_(self): EXAMPLES:: - sage: r # indirect doctest # optional - rpy2 + sage: r # indirect doctest R Interpreter """ return 'R Interpreter' @@ -710,10 +701,10 @@ def __reduce__(self): EXAMPLES:: - sage: r # resolve lazy import # optional - rpy2 + sage: r # resolve lazy import R Interpreter - sage: rlr, t = r.__reduce__() # optional - rpy2 - sage: rlr(*t) # optional - rpy2 + sage: rlr, t = r.__reduce__() + sage: rlr(*t) R Interpreter """ return reduce_load_R, tuple([]) @@ -726,9 +717,9 @@ def __getattr__(self, attrname): EXAMPLES:: - sage: c = r.c; c # optional - rpy2 + sage: c = r.c; c c - sage: type(c) # optional - rpy2 + sage: type(c) """ try: @@ -749,7 +740,7 @@ def _read_in_file_command(self, filename): EXAMPLES:: - sage: r._read_in_file_command('file.txt') # optional - rpy2 + sage: r._read_in_file_command('file.txt') 'file=file("file.txt",open="r")\nsource(file)' """ return 'file=file("%s",open="r")\nsource(file)' % filename @@ -761,7 +752,6 @@ def read(self, filename): EXAMPLES:: - sage: # optional - rpy2 sage: filename = tmp_filename() sage: f = open(filename, 'w') sage: _ = f.write('a <- 2+2\n') @@ -776,7 +766,7 @@ def _install_hints(self): """ EXAMPLES:: - sage: print(r._install_hints()) # optional - rpy2 + sage: print(r._install_hints()) R is currently installed with Sage. """ return "R is currently installed with Sage.\n" @@ -791,7 +781,7 @@ def _source(self, s): EXAMPLES:: - sage: print(r._source("c")) # optional - rpy2 + sage: print(r._source("c")) function (...) .Primitive("c") """ if s[-2:] == "()": @@ -810,7 +800,7 @@ def source(self, s): EXAMPLES:: - sage: print(r.source("c")) # optional - rpy2 + sage: print(r.source("c")) function (...) .Primitive("c") """ return self._source(s) @@ -823,7 +813,6 @@ def version(self): EXAMPLES:: - sage: # optional - rpy2 sage: r.version() # not tested ((3, 0, 1), 'R version 3.0.1 (2013-05-16)') sage: rint, rstr = r.version() @@ -857,10 +846,10 @@ def library(self, library_name): EXAMPLES:: - sage: r.library('grid') # optional - rpy2 - sage: 'grid' in r.eval('(.packages())') # optional - rpy2 + sage: r.library('grid') + sage: 'grid' in r.eval('(.packages())') True - sage: r.library('foobar') # optional - rpy2 + sage: r.library('foobar') Traceback (most recent call last): ... ImportError: ... @@ -895,8 +884,8 @@ def available_packages(self): EXAMPLES:: - sage: ap = r.available_packages() # optional - internet # optional - rpy2 - sage: len(ap) > 20 # optional - internet # optional - rpy2 + sage: ap = r.available_packages() # optional - internet + sage: len(ap) > 20 # optional - internet True """ p = self.new('available.packages("%s/src/contrib")' % RRepositoryURL) @@ -917,7 +906,7 @@ def _object_class(self): EXAMPLES:: - sage: r._object_class() # optional - rpy2 + sage: r._object_class() """ return RElement @@ -930,7 +919,7 @@ def _true_symbol(self): EXAMPLES:: - sage: r._true_symbol() # optional - rpy2 + sage: r._true_symbol() '[1] TRUE' """ # return the string rep of truth, i.e., what the system outputs @@ -945,7 +934,7 @@ def _false_symbol(self): EXAMPLES:: - sage: r._false_symbol() # optional - rpy2 + sage: r._false_symbol() '[1] FALSE' """ # return the string rep of false, i.e., what the system outputs @@ -956,7 +945,7 @@ def _equality_symbol(self): """ EXAMPLES:: - sage: r._equality_symbol() # optional - rpy2 + sage: r._equality_symbol() '==' """ # return the symbol for checking equality, e.g., == or eq. @@ -992,7 +981,7 @@ def help(self, command): EXAMPLES:: - sage: r.help('c') # optional - rpy2 + sage: r.help('c') title ----- @@ -1021,7 +1010,7 @@ def _assign_symbol(self): EXAMPLES:: - sage: r._assign_symbol() # optional - rpy2 + sage: r._assign_symbol() ' <- ' """ return " <- " @@ -1034,7 +1023,7 @@ def _left_list_delim(self): EXAMPLES:: - sage: r._left_list_delim() # optional - rpy2 + sage: r._left_list_delim() 'c(' """ return "c(" @@ -1047,7 +1036,7 @@ def _right_list_delim(self): EXAMPLES:: - sage: r._right_list_delim() # optional - rpy2 + sage: r._right_list_delim() ')' """ return ")" @@ -1058,7 +1047,7 @@ def console(self): EXAMPLES:: - sage: r.console() # not tested # optional - rpy2 + sage: r.console() # not tested R version 2.6.1 (2007-11-26) Copyright (C) 2007 The R Foundation for Statistical Computing ISBN 3-900051-07-0 @@ -1074,7 +1063,7 @@ def function_call(self, function, args=None, kwds=None): EXAMPLES:: - sage: r.function_call('length', args=[ [1,2,3] ]) # optional - rpy2 + sage: r.function_call('length', args=[ [1,2,3] ]) [1] 3 """ args, kwds = self._convert_args_kwds(args, kwds) @@ -1088,7 +1077,7 @@ def call(self, function_name, *args, **kwds): EXAMPLES:: - sage: r.call('length', [1,2,3]) # optional - rpy2 + sage: r.call('length', [1,2,3]) [1] 3 """ return self.function_call(function_name, args=args, kwds=kwds) @@ -1102,9 +1091,9 @@ def _an_element_(self): EXAMPLES:: - sage: r._an_element_() # optional - rpy2 + sage: r._an_element_() [1] 0 - sage: type(_) # optional - rpy2 + sage: type(_) """ return self(0) @@ -1120,8 +1109,8 @@ def set(self, var, value): EXAMPLES:: - sage: r.set('a', '2 + 3') # optional - rpy2 - sage: r.get('a') # optional - rpy2 + sage: r.set('a', '2 + 3') + sage: r.get('a') '[1] 5' """ _ = self.eval(f'{var} <- {value}') @@ -1138,8 +1127,8 @@ def get(self, var): EXAMPLES:: - sage: r.set('a', 2) # optional - rpy2 - sage: r.get('a') # optional - rpy2 + sage: r.set('a', 2) + sage: r.get('a') '[1] 2' """ return self.eval('%s' % var) @@ -1152,7 +1141,7 @@ def na(self): EXAMPLES:: - sage: r.na() # optional - rpy2 + sage: r.na() [1] NA """ return self('NA') @@ -1170,8 +1159,8 @@ def completions(self, s): EXAMPLES:: - sage: dummy = r._tab_completion(use_disk_cache=False) #clean doctest # optional - rpy2 - sage: 'testInheritedMethods' in r.completions('tes') # optional - rpy2 + sage: dummy = r._tab_completion(use_disk_cache=False) #clean doctest + sage: 'testInheritedMethods' in r.completions('tes') True """ return [name for name in self._tab_completion() if name[:len(s)] == s] @@ -1184,10 +1173,10 @@ def _commands(self): EXAMPLES:: - sage: l = r._commands() # optional - rpy2 - sage: 'AIC' in l # optional - rpy2 + sage: l = r._commands() + sage: 'AIC' in l True - sage: len(l) > 200 # optional - rpy2 + sage: len(l) > 200 True """ v = RBaseCommands @@ -1234,8 +1223,8 @@ def _tab_completion(self, verbose=True, use_disk_cache=True): EXAMPLES:: - sage: t = r._tab_completion(verbose=False) # optional - rpy2 - sage: len(t) > 200 # optional - rpy2 + sage: t = r._tab_completion(verbose=False) + sage: len(t) > 200 True """ try: @@ -1280,7 +1269,7 @@ def plot(self, *args, **kwds): persistent in your own code:: sage: from tempfile import TemporaryDirectory - sage: with TemporaryDirectory() as d: # optional - rpy2 rgraphics + sage: with TemporaryDirectory() as d: # optional - rgraphics ....: _ = r.setwd(d) ....: r.plot("1:10") null device @@ -1290,16 +1279,15 @@ def plot(self, *args, **kwds): the output device to that file. If this is done in the notebook, it must be done in the same cell as the plot itself:: - sage: # optional - rpy2 sage: filename = tmp_filename() + '.png' - sage: r.png(filename='"%s"'%filename) # optional - rgraphics + sage: r.png(filename='"%s"'%filename) # optional - rgraphics NULL sage: x = r([1,2,3]) sage: y = r([4,5,6]) - sage: r.plot(x,y) # optional - rgraphics + sage: r.plot(x,y) # optional - rgraphics null device 1 - sage: import os; os.unlink(filename) # optional - rgraphics + sage: import os; os.unlink(filename) # optional - rgraphics Please note that for more extensive use of R's plotting capabilities (such as the lattices package), it is advisable @@ -1307,7 +1295,7 @@ def plot(self, *args, **kwds): notebook. The following examples are not tested, because they differ depending on operating system:: - sage: # not tested, optional - rpy2 + sage: # not tested sage: r.X11() sage: r.quartz() sage: r.hist("rnorm(100)") @@ -1319,13 +1307,12 @@ def plot(self, *args, **kwds): would need to use the following since R lattice graphics do not automatically print away from the command line:: - sage: # optional - rpy2 - sage: filename = tmp_filename() + '.png' # Not needed in notebook, used for doctesting - sage: r.png(filename='"%s"'%filename) # optional - rgraphics + sage: filename = tmp_filename() + '.png' # Not needed in notebook, used for doctesting + sage: r.png(filename='"%s"'%filename) # optional - rgraphics NULL sage: r.library("lattice") sage: r("print(histogram(~wt | cyl, data=mtcars))") # optional - rgraphics - sage: import os; os.unlink(filename) # optional - rgraphics + sage: import os; os.unlink(filename) # optional - rgraphics """ # We have to define this to override the plot function defined in the # superclass. @@ -1339,7 +1326,7 @@ def eval(self, code, *args, **kwds): EXAMPLES:: - sage: r.eval('1+1') # optional - rpy2 + sage: r.eval('1+1') '[1] 2' """ self._lazy_init() @@ -1359,7 +1346,6 @@ def _r_to_sage_name(self, s): EXAMPLES:: - sage: # optional - rpy2 sage: f = r._r_to_sage_name sage: f('t.test') 't_test' @@ -1383,7 +1369,6 @@ def _sage_to_r_name(self, s): EXAMPLES:: - sage: # optional - rpy2 sage: f = r._sage_to_r_name sage: f('t_test') 't.test' @@ -1415,9 +1400,9 @@ def __getitem__(self, s): EXAMPLES:: - sage: r['as.data.frame'] # optional - rpy2 + sage: r['as.data.frame'] as.data.frame - sage: r['print'] # optional - rpy2 + sage: r['print'] print """ return RFunction(self, s, r_name=True) @@ -1432,9 +1417,9 @@ def chdir(self, dir): EXAMPLES:: - sage: import tempfile # optional - rpy2 - sage: tmpdir = tempfile.mkdtemp() # optional - rpy2 - sage: r.chdir(tmpdir) # optional - rpy2 + sage: import tempfile + sage: tmpdir = tempfile.mkdtemp() + sage: r.chdir(tmpdir) Check that ``tmpdir`` and ``r.getwd()`` refer to the same directory. We need to use ``realpath()`` in case ``$TMPDIR`` @@ -1442,7 +1427,7 @@ def chdir(self, dir): :: - sage: os.path.realpath(tmpdir) == sageobj(r.getwd()) # known bug (trac #9970) # optional - rpy2 + sage: os.path.realpath(tmpdir) == sageobj(r.getwd()) # known bug (issue #9970) True """ self.execute('setwd(%r)' % dir) @@ -1461,9 +1446,9 @@ def _tab_completion(self): EXAMPLES:: - sage: a = r([1,2,3]) # optional - rpy2 - sage: t = a._tab_completion() # optional - rpy2 - sage: len(t) > 200 # optional - rpy2 + sage: a = r([1,2,3]) + sage: t = a._tab_completion() + sage: len(t) > 200 True """ # TODO: rewrite it, just take methods(class=class(self)) @@ -1475,7 +1460,6 @@ def tilde(self, x): EXAMPLES:: - sage: # optional - rpy2 sage: x = r([1,2,3,4,5]) sage: y = r([3,5,7,9,11]) sage: a = r.lm( y.tilde(x) ) # lm( y ~ x ) @@ -1495,9 +1479,9 @@ def is_string(self): EXAMPLES:: - sage: r('"abc"').is_string() # optional - rpy2 + sage: r('"abc"').is_string() True - sage: r([1,2,3]).is_string() # optional - rpy2 + sage: r([1,2,3]).is_string() False """ @@ -1511,8 +1495,8 @@ def __len__(self): EXAMPLES:: - sage: x = r([10.4,5.6,3.1,6.4,21.7]) # optional - rpy2 - sage: len(x) # optional - rpy2 + sage: x = r([10.4,5.6,3.1,6.4,21.7]) + sage: len(x) 5 """ return self.parent()('length(%s)' % self.name()).sage() @@ -1530,7 +1514,6 @@ def __getattr__(self, attrname): EXAMPLES:: - sage: # optional - rpy2 sage: x = r([1,2,3]) sage: length = x.length sage: type(length) @@ -1561,7 +1544,6 @@ def __getitem__(self, n): EXAMPLES:: - sage: # optional - rpy2 sage: x = r([10.4,5.6,3.1,6.4,21.7]) sage: x[0] numeric(0) @@ -1620,7 +1602,6 @@ def __bool__(self): EXAMPLES:: - sage: # optional - rpy2 sage: x = r([10.4,5.6,3.1,6.4,21.7]) sage: bool(x) True @@ -1647,8 +1628,8 @@ def _comparison(self, other, symbol): TESTS:: - sage: x = r([10.4,5.6,3.1,6.4,21.7]) # optional - rpy2 - sage: x._comparison(10.4, "==") # optional - rpy2 + sage: x = r([10.4,5.6,3.1,6.4,21.7]) + sage: x._comparison(10.4, "==") [1] TRUE FALSE FALSE FALSE FALSE """ P = self.parent() @@ -1669,8 +1650,8 @@ def __eq__(self, other): Notice that comparison is term by term and returns an R element. :: - sage: x = r([10.4,5.6,3.1,6.4,21.7]) # optional - rpy2 - sage: x == 10.4 # optional - rpy2 + sage: x = r([10.4,5.6,3.1,6.4,21.7]) + sage: x == 10.4 [1] TRUE FALSE FALSE FALSE FALSE """ return self._comparison(other, "==") @@ -1689,8 +1670,8 @@ def __lt__(self, other): Notice that comparison is term by term and returns an R element. :: - sage: x = r([10.4,5.6,3.1,6.4,21.7]) # optional - rpy2 - sage: x < 7 # optional - rpy2 + sage: x = r([10.4,5.6,3.1,6.4,21.7]) + sage: x < 7 [1] FALSE TRUE TRUE TRUE FALSE """ return self._comparison(other, "<") @@ -1709,8 +1690,8 @@ def __gt__(self, other): Notice that comparison is term by term and returns an R element. :: - sage: x = r([10.4,5.6,3.1,6.4,21.7]) # optional - rpy2 - sage: x > 8 # optional - rpy2 + sage: x = r([10.4,5.6,3.1,6.4,21.7]) + sage: x > 8 [1] TRUE FALSE FALSE FALSE TRUE """ return self._comparison(other, ">") @@ -1727,8 +1708,8 @@ def __le__(self, other): EXAMPLES:: - sage: x = r([10.4,5.6,3.1,6.4,21.7]) # optional - rpy2 - sage: x <= 10.4 # optional - rpy2 + sage: x = r([10.4,5.6,3.1,6.4,21.7]) + sage: x <= 10.4 [1] TRUE TRUE TRUE TRUE FALSE """ return self._comparison(other, "<=") @@ -1745,8 +1726,8 @@ def __ge__(self, other): EXAMPLES:: - sage: x = r([10.4,5.6,3.1,6.4,21.7]) # optional - rpy2 - sage: x >= 10.4 # optional - rpy2 + sage: x = r([10.4,5.6,3.1,6.4,21.7]) + sage: x >= 10.4 [1] TRUE FALSE FALSE FALSE TRUE """ return self._comparison(other, ">=") @@ -1763,8 +1744,8 @@ def __ne__(self, other): EXAMPLES:: - sage: x = r([10.4,5.6,3.1,6.4,21.7]) # optional - rpy2 - sage: x != 10.4 # optional - rpy2 + sage: x = r([10.4,5.6,3.1,6.4,21.7]) + sage: x != 10.4 [1] FALSE TRUE TRUE TRUE TRUE """ @@ -1782,16 +1763,16 @@ def dot_product(self, other): EXAMPLES:: - sage: c = r.c(1,2,3,4) # optional - rpy2 - sage: c.dot_product(c.t()) # optional - rpy2 + sage: c = r.c(1,2,3,4) + sage: c.dot_product(c.t()) [,1] [,2] [,3] [,4] [1,] 1 2 3 4 [2,] 2 4 6 8 [3,] 3 6 9 12 [4,] 4 8 12 16 - sage: v = r([3,-1,8]) # optional - rpy2 - sage: v.dot_product(v) # optional - rpy2 + sage: v = r([3,-1,8]) + sage: v.dot_product(v) [,1] [1,] 74 """ @@ -1814,9 +1795,9 @@ def _sage_(self): EXAMPLES:: - sage: rs = r.summary(r.c(1,4,3,4,3,2,5,1)) # optional - rpy2 - sage: d = rs._sage_() # optional - rpy2 - sage: sorted(d.items()) # optional - rpy2 + sage: rs = r.summary(r.c(1,4,3,4,3,2,5,1)) + sage: d = rs._sage_() + sage: sorted(d.items()) [('DATA', [1, 1.75, 3, 2.875, 4, 5]), ('_Names', ['Min.', '1st Qu.', 'Median', 'Mean', '3rd Qu.', 'Max.']), ('_r_class', ['summaryDefault', 'table'])] @@ -1837,7 +1818,7 @@ def _latex_(self): EXAMPLES:: - sage: latex(r(2)) # optional - Hmisc (R package) # optional - rpy2 + sage: latex(r(2)) # optional - Hmisc (R package) 2 """ from sage.misc.latex import LatexExpr @@ -1857,10 +1838,10 @@ def __reduce__(self): """ EXAMPLES:: - sage: a = r([1,2,3]) # optional - rpy2 - sage: a.mean # optional - rpy2 + sage: a = r([1,2,3]) + sage: a.mean mean - sage: dumps(a.mean) # optional - rpy2 + sage: dumps(a.mean) Traceback (most recent call last): ... NotImplementedError: pickling of R element methods is not yet supported @@ -1873,9 +1854,9 @@ def _instancedoc_(self): EXAMPLES:: - sage: a = r([1,2,3]) # optional - rpy2 - sage: length = a.length # optional - rpy2 - sage: print(length.__doc__) # optional - rpy2 + sage: a = r([1,2,3]) + sage: length = a.length + sage: print(length.__doc__) title ----- @@ -1896,9 +1877,9 @@ def _sage_src_(self): EXAMPLES:: - sage: a = r([1,2,3]) # optional - rpy2 - sage: length = a.length # optional - rpy2 - sage: print(length._sage_src_()) # optional - rpy2 + sage: a = r([1,2,3]) + sage: length = a.length + sage: print(length._sage_src_()) function (x) .Primitive("length") """ M = self._obj.parent() @@ -1908,9 +1889,9 @@ def __call__(self, *args, **kwds): """ EXAMPLES:: - sage: a = r([1,2,3]) # optional - rpy2 - sage: length = a.length # optional - rpy2 - sage: length() # optional - rpy2 + sage: a = r([1,2,3]) + sage: length = a.length + sage: length() [1] 3 """ return self._obj.parent().function_call(self._name, args=[self._obj] + list(args), kwds=kwds) @@ -1930,10 +1911,10 @@ def __init__(self, parent, name, r_name=None): EXAMPLES:: - sage: length = r.length # optional - rpy2 - sage: type(length) # optional - rpy2 + sage: length = r.length + sage: type(length) - sage: loads(dumps(length)) # optional - rpy2 + sage: loads(dumps(length)) length """ self._parent = parent @@ -1946,9 +1927,9 @@ def __eq__(self, other): """ EXAMPLES:: - sage: r.mean == loads(dumps(r.mean)) # optional - rpy2 + sage: r.mean == loads(dumps(r.mean)) True - sage: r.mean == r.lr # optional - rpy2 + sage: r.mean == r.lr False """ return (isinstance(other, RFunction) and @@ -1958,9 +1939,9 @@ def __ne__(self, other): """ EXAMPLES:: - sage: r.mean != loads(dumps(r.mean)) # optional - rpy2 + sage: r.mean != loads(dumps(r.mean)) False - sage: r.mean != r.lr # optional - rpy2 + sage: r.mean != r.lr True """ return not (self == other) @@ -1971,8 +1952,8 @@ def _instancedoc_(self): EXAMPLES:: - sage: length = r.length # optional - rpy2 - sage: print(length.__doc__) # optional - rpy2 + sage: length = r.length + sage: print(length.__doc__) title ----- @@ -1993,8 +1974,8 @@ def _sage_src_(self): EXAMPLES:: - sage: length = r.length # optional - rpy2 - sage: print(length._sage_src_()) # optional - rpy2 + sage: length = r.length + sage: print(length._sage_src_()) function (x) .Primitive("length") """ @@ -2005,8 +1986,8 @@ def __call__(self, *args, **kwds): """ EXAMPLES:: - sage: length = r.length # optional - rpy2 - sage: length([1,2,3]) # optional - rpy2 + sage: length = r.length + sage: length([1,2,3]) [1] 3 """ return self._parent.function_call(self._name, args=list(args), kwds=kwds) @@ -2024,12 +2005,12 @@ def is_RElement(x): EXAMPLES:: - sage: from sage.interfaces.r import is_RElement # optional - rpy2 - sage: is_RElement(2) # optional - rpy2 + sage: from sage.interfaces.r import is_RElement + sage: is_RElement(2) doctest:...: DeprecationWarning: the function is_RElement is deprecated; use isinstance(x, sage.interfaces.abc.RElement) instead See https://github.com/sagemath/sage/issues/34804 for details. False - sage: is_RElement(r(2)) # optional - rpy2 + sage: is_RElement(r(2)) True """ from sage.misc.superseded import deprecation @@ -2048,8 +2029,8 @@ def reduce_load_R(): EXAMPLES:: - sage: from sage.interfaces.r import reduce_load_R # optional - rpy2 - sage: reduce_load_R() # optional - rpy2 + sage: from sage.interfaces.r import reduce_load_R + sage: reduce_load_R() R Interpreter """ return r @@ -2061,7 +2042,7 @@ def r_console(): EXAMPLES:: - sage: r.console() # not tested # optional - rpy2 + sage: r.console() # not tested R version 2.6.1 (2007-11-26) Copyright (C) 2007 The R Foundation for Statistical Computing ISBN 3-900051-07-0 @@ -2080,7 +2061,6 @@ def r_version(): EXAMPLES:: - sage: # optional - rpy2 sage: r_version() # not tested ((3, 0, 1), 'R version 3.0.1 (2013-05-16)') sage: rint, rstr = r_version() @@ -2104,10 +2084,10 @@ def __repr__(self): EXAMPLES:: - sage: a = sage.interfaces.r.HelpExpression("This\nis\nR!") # optional - rpy2 - sage: type(a) # optional - rpy2 + sage: a = sage.interfaces.r.HelpExpression("This\nis\nR!") + sage: type(a) - sage: a # optional - rpy2 + sage: a This is R! From 01cef3648bc4dec11ad18781d119cbb78094441e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 7 Jun 2024 16:54:32 -0700 Subject: [PATCH 08/13] Revert "src/sage/doctest/forker.py: Run clean_namespace on the globals of each test" This reverts commit deadf9728833d6a1a82fb9b3064efb5b1ff9d083. --- src/sage/doctest/forker.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/sage/doctest/forker.py b/src/sage/doctest/forker.py index edde96a9b65..35f473b40f9 100644 --- a/src/sage/doctest/forker.py +++ b/src/sage/doctest/forker.py @@ -889,10 +889,6 @@ def run(self, test, compileflags=0, out=None, clear_globs=True): warnings.showwarning = showwarning_with_traceback self.running_doctest_digest = hashlib.md5() self.test = test - # Because test is a copy, we need to - # relink imported lazy_import objects to point to the appropriate namespace - from sage.misc.lazy_import import clean_namespace - clean_namespace(test.globs) # We use this slightly modified version of Pdb because it # interacts better with the doctesting framework (like allowing # doctests for sys.settrace()). Since we already have output From 6b101da582984a6d20bba03ca9904da71d89caac Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 7 Jun 2024 17:34:11 -0700 Subject: [PATCH 09/13] src/sage/interfaces/r.py: Replace problematic lazy imports --- src/sage/interfaces/r.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sage/interfaces/r.py b/src/sage/interfaces/r.py index f49735b028a..7b082f1a487 100644 --- a/src/sage/interfaces/r.py +++ b/src/sage/interfaces/r.py @@ -282,8 +282,6 @@ lazy_import("rpy2", "robjects", feature=rpy2_feature) lazy_import("rpy2.robjects", "packages", "rpy2_packages", feature=rpy2_feature) lazy_import("rpy2.robjects.conversion", ["localconverter", "Converter"], feature=rpy2_feature) -lazy_import("rpy2.rinterface", ["SexpVector", "ListSexpVector", "FloatSexpVector"], - feature=rpy2_feature) # for help page fetching lazy_import("rpy2.robjects.help", "Package", feature=rpy2_feature) @@ -369,6 +367,8 @@ def _setup_r_to_sage_converter(): 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 + # 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') @@ -701,8 +701,7 @@ def __reduce__(self): EXAMPLES:: - sage: r # resolve lazy import - R Interpreter + sage: from sage.interfaces.r import r sage: rlr, t = r.__reduce__() sage: rlr(*t) R Interpreter From ed62dcb928c7c014253f2d569d01e35be7304181 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 7 Jun 2024 17:36:41 -0700 Subject: [PATCH 10/13] src/sage/features/__init__.py: Fix feature type --- src/sage/interfaces/r.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/interfaces/r.py b/src/sage/interfaces/r.py index 7b082f1a487..4320700dd4b 100644 --- a/src/sage/interfaces/r.py +++ b/src/sage/interfaces/r.py @@ -277,7 +277,7 @@ from sage.misc.lazy_import import lazy_import from sage.features import PythonModule -rpy2_feature = PythonModule('rpy2', spkg='rpy2') +rpy2_feature = PythonModule('rpy2', spkg='rpy2', type='standard') lazy_import("rpy2", "robjects", feature=rpy2_feature) lazy_import("rpy2.robjects", "packages", "rpy2_packages", feature=rpy2_feature) From 0627ffbda3097533e2b882e1a2b22cffdf9d3c11 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 7 Jun 2024 19:43:10 -0700 Subject: [PATCH 11/13] src/sage/repl/ipython_tests.py: Make doctest more flexible --- src/sage/repl/ipython_tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/repl/ipython_tests.py b/src/sage/repl/ipython_tests.py index 74a76c84d68..390ef77fa7c 100644 --- a/src/sage/repl/ipython_tests.py +++ b/src/sage/repl/ipython_tests.py @@ -53,7 +53,7 @@ ... String form: lm File: .../sage/interfaces/r.py - Docstring: + Docstring:... title ***** From 538c9114edf160c778161aec83e61b62158780b1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 7 Jun 2024 19:44:59 -0700 Subject: [PATCH 12/13] build/pkgs/r/distros/conda.txt: Add r-lattice --- build/pkgs/r/distros/conda.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/build/pkgs/r/distros/conda.txt b/build/pkgs/r/distros/conda.txt index 4c235733c5f..741d5f82d93 100644 --- a/build/pkgs/r/distros/conda.txt +++ b/build/pkgs/r/distros/conda.txt @@ -1,2 +1,3 @@ r r-essentials +r-lattice From 11833d814b12d0787313f13e3362583d337d8ce8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 8 Jun 2024 17:37:16 -0700 Subject: [PATCH 13/13] src/sage/interfaces/r.py: Fix doctest comment style --- src/sage/interfaces/r.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/interfaces/r.py b/src/sage/interfaces/r.py index 4320700dd4b..33addb28afa 100644 --- a/src/sage/interfaces/r.py +++ b/src/sage/interfaces/r.py @@ -631,8 +631,8 @@ def png(self, *args, **kwds): We want to make sure that we actually can view R graphics, which happens differently on different platforms:: - sage: s = r.eval('capabilities("png")') # Should be on Linux and Solaris - sage: t = r.eval('capabilities("aqua")') # Should be on all supported Mac versions + sage: s = r.eval('capabilities("png")') # should be on Linux and Solaris + sage: t = r.eval('capabilities("aqua")') # should be on all supported Mac versions sage: "TRUE" in s+t # optional - rgraphics True """ @@ -1158,7 +1158,7 @@ def completions(self, s): EXAMPLES:: - sage: dummy = r._tab_completion(use_disk_cache=False) #clean doctest + sage: dummy = r._tab_completion(use_disk_cache=False) # clean doctest sage: 'testInheritedMethods' in r.completions('tes') True """ @@ -1306,7 +1306,7 @@ def plot(self, *args, **kwds): would need to use the following since R lattice graphics do not automatically print away from the command line:: - sage: filename = tmp_filename() + '.png' # Not needed in notebook, used for doctesting + sage: filename = tmp_filename() + '.png' # not needed in notebook, used for doctesting sage: r.png(filename='"%s"'%filename) # optional - rgraphics NULL sage: r.library("lattice")