Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix error when converting empty numpy string arrays #1672

Merged
merged 3 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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).

# reticulate 1.39.0
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()))
}
})

Loading