From d2c6ffc39ff62feb7dc4f0f7aec0dba5e1ac1702 Mon Sep 17 00:00:00 2001 From: Tomasz Kalinowski Date: Wed, 18 Sep 2024 13:28:30 -0400 Subject: [PATCH 1/3] fix `py_to_r()` conversion of size-0 string numpy arrays. closes #1662 --- src/python.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/python.cpp b/src/python.cpp index 8768073fd..31bd3f6b9 100644 --- a/src/python.cpp +++ b/src/python.cpp @@ -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, @@ -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); @@ -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 Date: Wed, 18 Sep 2024 13:28:51 -0400 Subject: [PATCH 2/3] add tests. --- tests/testthat/test-python-numpy.R | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/testthat/test-python-numpy.R b/tests/testthat/test-python-numpy.R index 977a7325c..8a9857225 100644 --- a/tests/testthat/test-python-numpy.R +++ b/tests/testthat/test-python-numpy.R @@ -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())) + } +}) + From 641761fb7ada738fc8c58a35d3a50e637c67d956 Mon Sep 17 00:00:00 2001 From: Tomasz Kalinowski Date: Wed, 18 Sep 2024 13:32:11 -0400 Subject: [PATCH 3/3] add NEWS --- NEWS.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 7d7ba883e..daa856881 100644 --- a/NEWS.md +++ b/NEWS.md @@ -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