Skip to content

Commit

Permalink
Merge pull request #1645 from rstudio/fixes-for-cran-macos-oldrel
Browse files Browse the repository at this point in the history
Fixes for failing CRAN checks
  • Loading branch information
t-kalinowski authored Aug 12, 2024
2 parents d683b3b + abb9496 commit ddab6a6
Show file tree
Hide file tree
Showing 10 changed files with 276 additions and 120 deletions.
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

- `conda_run2()` is now exported (#1637, contributed by @dramanica)

- Fixes for CRAN check failures (#1645)

# reticulate 1.38.0

- Python Exceptions converted to R conditions are now R lists instead
Expand Down
2 changes: 1 addition & 1 deletion tests/testthat/test-python-source.R
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ test_that("Python scripts can be sourced from local file", {

test_that("Python scripts can be sourced from a URL", {
skip_if_no_python()
# skip_if_offline() ## needs {curl}
source_python('https://raw.githubusercontent.com/rstudio/reticulate/main/tests/testthat/script.py')
expect_equal(add(2, 4), 6)
})
Expand Down Expand Up @@ -38,4 +39,3 @@ test_that("source_python() overlays in the main module", {
main <- import_main()
expect_equal(main$value, 42)
})

3 changes: 0 additions & 3 deletions vignettes/arrays.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ vignette: >
%\VignetteEncoding{UTF-8}
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(eval = FALSE)
```

Dense data are stored contiguously in memory, addressed by a single index (the
memory address). Array memory ordering schemes translate that single index into
Expand Down
33 changes: 14 additions & 19 deletions vignettes/calling_python.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,11 @@ vignette: >
---


```{r setup, include=FALSE}
knitr::opts_chunk$set(eval = FALSE)
```


## Overview

The **reticulate** package provides an R interface to Python modules, classes, and functions. For example, this code imports the Python `os` module and calls some functions within it:

```{r, eval=FALSE}
```r
library(reticulate)
os <- import("os")
os$listdir(".")
Expand Down Expand Up @@ -81,7 +76,7 @@ If a Python object of a custom class is returned then an R reference to that obj

The `import()` function can be used to import any Python module. For example:

```{r}
```r
difflib <- import("difflib")
difflib$ndiff(foo, bar)

Expand All @@ -91,7 +86,7 @@ filecmp$cmp(dir1, dir2)

The `import_main()` and `import_builtins()` functions give you access to the main module where code is executed by default and the collection of built in Python functions. For example:

```{r}
```r
main <- import_main()

builtins <- import_builtins()
Expand All @@ -111,7 +106,7 @@ def add(x, y):

We source it using the `source_python()` function and then can call the `add()` function directly from R:

```{r}
```r
source_python('add.py')
add(5, 10)
```
Expand All @@ -123,7 +118,7 @@ add(5, 10)

You can execute Python code within the main module using the `py_run_file` and `py_run_string` functions. You can then access any objects created using the `py` object exported by reticulate:

```{r}
```r
library(reticulate)

py_run_file("script.py")
Expand All @@ -138,7 +133,7 @@ py$x

By default when Python objects are returned to R they are converted to their equivalent R types. However, if you'd rather make conversion from Python to R explicit and deal in native Python objects by default you can pass `convert = FALSE` to the `import` function. In this case Python to R conversion will be disabled for the module returned from `import`. For example:

```{r}
```r
# import numpy and specify no automatic Python to R conversion
np <- import("numpy", convert = FALSE)

Expand Down Expand Up @@ -326,7 +321,7 @@ We can also use `py_to_r()` to convert the CSC matrix back to `Matrix::dgCMatrix

The R `with` generic function can be used to interact with Python context manager objects (in Python you use the `with` keyword to do the same). For example:

```{r}
```r
py <- import_builtins()
with(py$open("output.txt", "w") %as% file, {
file$write("Hello, there!")
Expand All @@ -339,19 +334,19 @@ This example opens a file and ensures that it is automatically closed at the end

If a Python API returns an iterator or a generator, you can interact with it using the `iterate()` function. The `iterate()` function can be used to apply an R function to each item yielded by the iterator:

```{r}
```r
iterate(iter, print)
```

If you don't pass a function to `iterate` the results will be collected into an R vector:

```{r}
```r
results <- iterate(iter)
```

Note that the `Iterators` will be drained of their values by `iterate()`:

```{r}
```r
a <- iterate(iter) # results are not empty
b <- iterate(iter) # results are empty since items have already been drained
```
Expand All @@ -360,7 +355,7 @@ b <- iterate(iter) # results are empty since items have already been drained

You can also iterate on an element-by-element basis using the `iter_next()` function. For example:

```{r}
```r
while (TRUE) {
item <- iter_next(iter)
if (is.null(item))
Expand All @@ -370,7 +365,7 @@ while (TRUE) {

By default `iter_next()` will return `NULL` when the iteration is complete but you can provide a custom `completed` value it will be returned instead. For example:

```{r}
```r
while (TRUE) {
item <- iter_next(iter, completed = NA)
if (is.na(item))
Expand All @@ -387,7 +382,7 @@ Python [generators](https://wiki.python.org/moin/Generators) are functions that

In Python, generators produce values using the `yield` keyword. In R, values are simply returned from the function. One benefit of the `yield` keyword is that it enables successive iterations to use the state of previous iterations. In R, this can be done by returning a function that mutates its enclosing environment via the <<- operator. For example:

```{r}
```r
# define a generator function
sequence_generator <-function(start) {
value <- start
Expand All @@ -403,7 +398,7 @@ iter <- py_iterator(sequence_generator(10))

If you want to indicate the end of the iteration, return `NULL` from the function:

```{r}
```r
sequence_generator <-function(start) {
value <- start
function() {
Expand Down
17 changes: 7 additions & 10 deletions vignettes/package.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ vignette: >
%\VignetteEncoding{UTF-8}
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(eval = FALSE)
```

## Delay Loading Python Modules

Expand Down Expand Up @@ -55,7 +52,7 @@ py_install("scipy")

You can document the use of this function along with your package, or alternatively you can provide a wrapper function for `py_install()` that defaults to installing in a Python environment created specifically for your R package. For example:

```{r, eval = FALSE}
```r
install_scipy <- function(envname = "r-scipy", method = "auto", ...) {
reticulate::py_install("scipy", envname = envname,
method = method, ...)
Expand All @@ -72,7 +69,7 @@ There are two things you should do to ensure your package is well behaved on CRA

1. Use the `delay_load` option (as described above) to ensure that the module (and Python) is loaded only on its first use. For example:

```{r}
```r
# python 'scipy' module I want to use in my package
scipy <- NULL

Expand All @@ -84,7 +81,7 @@ There are two things you should do to ensure your package is well behaved on CRA

2. When writing tests, check to see if your module is available and if it isn't then skip the test. For example, if you are using the **testthat** package, you might do this:
```{r}
```r
# helper function to skip tests if we don't have the 'foo' module
skip_if_no_scipy <- function() {
have_scipy <- py_module_available("scipy")
Expand All @@ -107,7 +104,7 @@ If you do decide to implement custom S3 methods for a Python class it's importan
By default when you attempt to interact with a Python object from a previous session (a `NULL` R `externalptr`) an error is thrown. If you want to do something more customized in your S3 method you can use the `py_is_null_xptr()` function. For example:
```{r eval=FALSE}
```r
method.MyModule.MyPythonClass <- function(x, y, ...) {
if (py_is_null_xptr(x))
# whatever is appropriate
Expand All @@ -120,7 +117,7 @@ Note that this check isn't required, as by default an R error will occur. If it'
The **reticulate** package exports a `py_str` generic method which is called from the `str` method only after doing appropriate validation (if the object is NULL then `<pointer: 0x0>` is returned). You can implement the `py_str` method as follows:
```{r eval=FALSE}
```r
#' @importFrom reticulate py_str
#' @export
py_str.MyModule.MyPythonClass <- function(object, ...) {
Expand All @@ -147,7 +144,7 @@ If you see that **reticulate** is missing support for conversion of one or more

`r_to_py()` accepts a `convert` argument, which controls how objects generated from the created Python object are converted. To illustrate, consider the difference between these two cases:

```{r}
```r
library(reticulate)

# [convert = TRUE] => convert Python objects to R when appropriate
Expand All @@ -169,7 +166,7 @@ This is accomplished through the use of a `convert` flag, which is set on the Py

As an example of the second:

```{r eval=FALSE}
```r
# suppose 'make_python_object()' creates a Python object
# from R objects of class 'my_r_object'.
r_to_py.my_r_object <- function(x, convert) {
Expand Down
12 changes: 4 additions & 8 deletions vignettes/python_packages.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ vignette: >
%\VignetteEncoding{UTF-8}
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(eval = FALSE)
```

## Overview

Python packages are typically installed from one of two package repositories:
Expand Down Expand Up @@ -60,7 +56,7 @@ Virtual environments are by default located at `~/.virtualenvs`. You can change

Here's an example of using these functions to create an environment, install packages within it, then use the environment from R:

```{r}
```r
library(reticulate)

# create a new environment
Expand All @@ -75,7 +71,7 @@ scipy <- import("scipy")

Note that you may have a given Python package installed in multiple environments, in that case you may want to call the `use_virtualenv()` function to ensure that a specific virtualenv is utilized by reticulate:

```{r}
```r
library(reticulate)

# indicate that we want to use a specific virtualenv
Expand Down Expand Up @@ -108,7 +104,7 @@ The following functions are available for managing Conda environments:

Here's an example of using these functions to create an environment, install packages within it, then use the environment from R:

```{r}
```r
library(reticulate)

# create a new environment
Expand All @@ -123,7 +119,7 @@ scipy <- import("scipy")

Note that you may have a given Python package installed in multiple Conda environments, in that case you may want to call the `use_condaenv()` function to ensure that a specific Conda environment is utilized by reticulate:

```{r}
```r
library(reticulate)

# indicate that we want to use a specific condaenv
Expand Down
Loading

0 comments on commit ddab6a6

Please sign in to comment.