Skip to content

Commit

Permalink
Merge pull request #1761 from rstudio/fix-py_slice
Browse files Browse the repository at this point in the history
Fix `[` with Python objects in `:` slice args
  • Loading branch information
t-kalinowski authored Mar 10, 2025
2 parents 6143cb6 + e80ae69 commit cdfabdd
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 8 deletions.
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

- Updates for Positron to fix issues with `repl_python()` and Variables Pane (#1755).

- Fixed an issue where `[` received Python objects as slice arguments.
e.g., `x[start:end]` when `start` or `end` were Python objects (#1731).

- Reticulate-managed `uv` can now resolve system-installed Pythons,
supporting platforms where pre-built binaries are unavailable, such as
musl-based Alpine Linux (#1751, #1752).
Expand Down
28 changes: 20 additions & 8 deletions src/python.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4619,22 +4619,34 @@ PyObjectRef py_capsule(SEXP x) {
PyObjectRef py_slice(SEXP start = R_NilValue, SEXP stop = R_NilValue, SEXP step = R_NilValue) {
GILScope _gil;

PyObjectPtr start_, stop_, step_;
auto coerce_slice_arg = [](SEXP x) -> PyObject* {
if (x == R_NilValue) {
return NULL;
}
if (TYPEOF(x) == INTSXP || TYPEOF(x) == REALSXP) {
return PyLong_FromLong(Rf_asInteger(x));
}
if (is_py_object(x)) {
PyObject* pyobj = PyObjectRef(x, false).get();
Py_IncRef(pyobj);
return pyobj;
}
return r_to_py(x, false);
};

if (start != R_NilValue)
start_.assign(PyLong_FromLong(Rf_asInteger(start)));
if (stop != R_NilValue)
stop_.assign(PyLong_FromLong(Rf_asInteger(stop)));
if (step != R_NilValue)
step_.assign(PyLong_FromLong(Rf_asInteger(step)));
PyObjectPtr start_(coerce_slice_arg(start));
PyObjectPtr stop_(coerce_slice_arg(stop));
PyObjectPtr step_(coerce_slice_arg(step));

PyObject* out(PySlice_New(start_, stop_, step_));
PyObject* out = PySlice_New(start_, stop_, step_);
if (out == NULL)
throw PythonException(py_fetch_error());

return py_ref(out, false);
}



//' @rdname iterate
//' @export
// [[Rcpp::export]]
Expand Down
21 changes: 21 additions & 0 deletions tests/testthat/test-python-base-r-generics.R
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,24 @@ test_that("[ can infer slices, multiple args", {
expect_identical(py_eval("x"), py_to_r(x))

})


test_that("[ passes through python objects", {

skip_if_no_numpy()

np <- import("numpy", convert = FALSE)

x <- np$arange(10L)
ir <- 3L
ip <- np$array(3L)

expect_equal(py_to_r(x[ir]), 3L)
expect_equal(py_to_r(x[ip]), 3L)

expect_equal(py_to_r(x[ir:NA]), array(3:9))
expect_equal(py_to_r(x[ip:NA]), array(3:9))
expect_equal(py_to_r(x[NA:ir]), array(0:2))
expect_equal(py_to_r(x[NA:ip]), array(0:2))

})

0 comments on commit cdfabdd

Please sign in to comment.