Skip to content

Commit

Permalink
Merge pull request #1672 from rstudio/bugfix/conversion-empty-string-…
Browse files Browse the repository at this point in the history
…arrays

Fix error when converting empty numpy string arrays
  • Loading branch information
t-kalinowski committed Sep 18, 2024
2 parents b85a15c + 641761f commit 5dcad1f
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 6 deletions.
4 changes: 3 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
# reticulate (development version)

- Fixed error when converting an empty NumPy char array to R (#1662).

- Fixed error when using reticulate with radian (#1668, #1670).

- Fixed segfault encountered when running Python finalizer (#1663, #1664)

- Fixed segfault encountered in RStudio when rapidly switching
- Fixed segfault encountered in RStudio when rapidly switching
between R and Python chunks in a Quarto document (#1665).

- Improved behavior when the conda binary used to create an environment
Expand Down
14 changes: 9 additions & 5 deletions src/python.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1550,6 +1550,14 @@ SEXP py_to_r_cpp(PyObject* x, bool convert, bool simple) {
case NPY_VSTRING:
case NPY_UNICODE: {

rArray = Rf_allocArray(STRSXP, dimsVector);
RObject protectArray(rArray);

// special case 0-size vectors, because np.nditer() throws:
// ValueError: Iteration of zero-sized operands is not enabled
if (Rf_length(rArray) == 0)
break;

static PyObject* nditerArgs = []() {
PyObject* flags = PyTuple_New(1);
// iterating over a StringDType requires us to pass 'refs_ok' flag,
Expand All @@ -1559,7 +1567,7 @@ SEXP py_to_r_cpp(PyObject* x, bool convert, bool simple) {
PyTuple_SetItem(args, 1, flags); // steals ref
return args;
}();
// PyTuple_SetItem steals reference the array, but it's already wraped
// PyTuple_SetItem steals reference the array, but it's already wrapped
// into PyObjectPtr earlier (so it gets deleted after the scope of this function)
// To avoid trying to delete it twice, we need to increase its ref count here.
PyTuple_SetItem(nditerArgs, 0, (PyObject*)array);
Expand All @@ -1572,10 +1580,6 @@ SEXP py_to_r_cpp(PyObject* x, bool convert, bool simple) {
throw PythonException(py_fetch_error());
}

rArray = Rf_allocArray(STRSXP, dimsVector);
RObject protectArray(rArray);


for (int i=0; i<len; i++) {
PyObjectPtr el(PyIter_Next(iter)); // returns an scalar array.
PyObjectPtr pyStr(PyObject_CallMethod(el, "item", NULL));
Expand Down
12 changes: 12 additions & 0 deletions tests/testthat/test-python-numpy.R
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,15 @@ test_that("numpy non-simple arrays work", {
c(3, 4)))

})

test_that("0-length character arrays are handled correctly", {
# https://github.com/rstudio/reticulate/issues/1662
skip_if_no_numpy()
np <- import("numpy")

for (dtype in c("U", "U1", "U10", "O", "S", "S1", "S10")) {
expect_equal(np$array(character(), dtype = dtype),
array(character()))
}
})

0 comments on commit 5dcad1f

Please sign in to comment.