Skip to content

Commit 0ce0b74

Browse files
authored
Merge pull request #1877 from rstudio/fix/pandas-3-compatibility
Add support for pandas 3.0 class names
2 parents b33bfbf + fa8ed1f commit 0ce0b74

File tree

6 files changed

+59
-8
lines changed

6 files changed

+59
-8
lines changed

NAMESPACE

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ S3method(as.matrix,numpy.ndarray)
4444
S3method(as.raw,python.builtin.bytes)
4545
S3method(as.vector,numpy.ndarray)
4646
S3method(dim,numpy.ndarray)
47+
S3method(dim,pandas.DataFrame)
48+
S3method(dim,pandas.Series)
4749
S3method(dim,pandas.core.frame.DataFrame)
4850
S3method(dim,pandas.core.series.Series)
4951
S3method(dim,scipy.sparse._base._spbase)
@@ -54,6 +56,8 @@ S3method(format,python.builtin.module)
5456
S3method(format,python.builtin.object)
5557
S3method(format,python.builtin.traceback)
5658
S3method(length,numpy.ndarray)
59+
S3method(length,pandas.DataFrame)
60+
S3method(length,pandas.Series)
5761
S3method(length,pandas.core.frame.DataFrame)
5862
S3method(length,pandas.core.series.Series)
5963
S3method(length,python.builtin.dict)
@@ -88,8 +92,11 @@ S3method(py_to_r,datatable.Frame)
8892
S3method(py_to_r,datetime.date)
8993
S3method(py_to_r,datetime.datetime)
9094
S3method(py_to_r,default)
95+
S3method(py_to_r,pandas.DataFrame)
96+
S3method(py_to_r,pandas.Series)
9197
S3method(py_to_r,pandas._libs.missing.C_NAType)
9298
S3method(py_to_r,pandas._libs.missing.NAType)
99+
S3method(py_to_r,pandas.arrays.NumpyExtensionArray)
93100
S3method(py_to_r,pandas.core.arrays.categorical.Categorical)
94101
S3method(py_to_r,pandas.core.categorical.Categorical)
95102
S3method(py_to_r,pandas.core.frame.DataFrame)
@@ -117,6 +124,8 @@ S3method(r_to_py,sparseMatrix)
117124
S3method(str,py_config)
118125
S3method(str,python.builtin.module)
119126
S3method(str,python.builtin.object)
127+
S3method(summary,pandas.DataFrame)
128+
S3method(summary,pandas.Series)
120129
S3method(summary,pandas.core.frame.DataFrame)
121130
S3method(summary,pandas.core.series.Series)
122131
S3method(summary,python.builtin.object)

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# reticulate (development version)
22

3+
- Added support for pandas 3.0 (#1874, #1875).
4+
35
- Fix spurious `Error: ignoring SIGPIPE signal` on Unix when embedded Python writes to a closed pipe (#1868).
46

57
- Fixed Positron UI interactions, such as restart/create new session with reticulate (#1871, #1869).

R/conversion.R

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,9 @@ py_to_r.pandas.core.series.Series <- function(x) {
186186
values
187187
}
188188

189+
#' @export
190+
py_to_r.pandas.Series <- py_to_r.pandas.core.series.Series
191+
189192
#' @export
190193
py_to_r.pandas.core.categorical.Categorical <- function(x) {
191194
local_conversion_scope(x, FALSE)
@@ -199,6 +202,11 @@ py_to_r.pandas.core.categorical.Categorical <- function(x) {
199202
py_to_r.pandas.core.arrays.categorical.Categorical <-
200203
py_to_r.pandas.core.categorical.Categorical
201204

205+
#' @export
206+
py_to_r.pandas.arrays.NumpyExtensionArray <- function(x) {
207+
py_to_r(x$to_numpy())
208+
}
209+
202210
#' @export
203211
py_to_r.pandas._libs.missing.NAType <- function(x) {
204212
NA
@@ -221,6 +229,9 @@ summary.pandas.core.series.Series <- function(object, ...) {
221229
object$describe()
222230
}
223231

232+
#' @export
233+
summary.pandas.Series <- summary.pandas.core.series.Series
234+
224235
#' @export
225236
length.pandas.core.series.Series <- function(x) {
226237
if (py_is_null_xptr(x) || !py_available())
@@ -230,11 +241,17 @@ length.pandas.core.series.Series <- function(x) {
230241
}
231242
}
232243

244+
#' @export
245+
length.pandas.Series <- length.pandas.core.series.Series
246+
233247
#' @export
234248
dim.pandas.core.series.Series <- function(x) {
235249
NULL
236250
}
237251

252+
#' @export
253+
dim.pandas.Series <- dim.pandas.core.series.Series
254+
238255
#' @export
239256
r_to_py.data.frame <- function(x, convert = FALSE) {
240257

@@ -313,10 +330,14 @@ py_to_r.pandas.core.frame.DataFrame <- function(x) {
313330
attr(df, "pandas.index") <- index
314331

315332
if (inherits(index, c("pandas.core.indexes.base.Index",
316-
"pandas.indexes.base.Index"))) {
333+
"pandas.indexes.base.Index",
334+
"pandas.Index"
335+
))) {
317336

318337
if (inherits(index, c("pandas.core.indexes.range.RangeIndex",
319-
"pandas.indexes.range.RangeIndex")) &&
338+
"pandas.indexes.range.RangeIndex",
339+
"pandas.RangeIndex"
340+
)) &&
320341
np$issubdtype(index$dtype, np$number))
321342
{
322343
# check for a range index from 0 -> n. in such a case, we don't need
@@ -347,7 +368,9 @@ py_to_r.pandas.core.frame.DataFrame <- function(x) {
347368
}
348369

349370
else if (inherits(index, c("pandas.core.indexes.datetimes.DatetimeIndex",
350-
"pandas.tseries.index.DatetimeIndex"))) {
371+
"pandas.tseries.index.DatetimeIndex",
372+
"pandas.DatetimeIndex"
373+
))) {
351374

352375
converted <- tryCatch(py_to_r(index$values), error = identity)
353376

@@ -380,9 +403,15 @@ py_to_r.pandas.core.frame.DataFrame <- function(x) {
380403

381404
}
382405

406+
#' @export
407+
py_to_r.pandas.DataFrame <- py_to_r.pandas.core.frame.DataFrame
408+
383409
#' @export
384410
summary.pandas.core.frame.DataFrame <- summary.pandas.core.series.Series
385411

412+
#' @export
413+
summary.pandas.DataFrame <- summary.pandas.core.frame.DataFrame
414+
386415
#' @export
387416
length.pandas.core.frame.DataFrame <- function(x) {
388417
if (py_is_null_xptr(x) || !py_available())
@@ -392,6 +421,9 @@ length.pandas.core.frame.DataFrame <- function(x) {
392421
}
393422
}
394423

424+
#' @export
425+
length.pandas.DataFrame <- length.pandas.core.frame.DataFrame
426+
395427
#' @export
396428
dim.pandas.core.frame.DataFrame <- function(x) {
397429
if (py_is_null_xptr(x) || !py_available())
@@ -400,6 +432,10 @@ dim.pandas.core.frame.DataFrame <- function(x) {
400432
py_object_shape(x)
401433
}
402434

435+
#' @export
436+
dim.pandas.DataFrame <- dim.pandas.core.frame.DataFrame
437+
438+
403439
# Scipy sparse matrices
404440
#' @importFrom Matrix Matrix
405441

R/knitr-engine.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -737,7 +737,7 @@ eng_python_autoprint <- function(captured, options) {
737737
.engine_context$pending_plots$push(included_path)
738738
return("")
739739

740-
} else if (inherits(value, "pandas.core.frame.DataFrame")) {
740+
} else if (inherits(value, c("pandas.core.frame.DataFrame", "pandas.DataFrame"))) {
741741

742742
return(captured)
743743

src/python.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4382,9 +4382,8 @@ PyObject* r_to_py_pandas_nullable_series (const RObject& column, const bool conv
43824382
// strings are not built using np array + mask. Instead they take a
43834383
// np array with OBJECT type, with None's in the place of NA's
43844384
if (TYPEOF(column) == STRSXP) {
4385-
PyObjectPtr args(PyTuple_New(2));
4385+
PyObjectPtr args(PyTuple_New(1));
43864386
PyTuple_SetItem(args, 0, (PyObject*)r_to_py_numpy(column, convert));
4387-
PyTuple_SetItem(args, 1, Py_False);
43884387

43894388
PyObject* pd_col(PyObject_Call(constructor, args, NULL));
43904389

tests/testthat/test-python-pandas.R

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
context("pandas")
22

3+
pandas_version <- function() {
4+
pd <- import("pandas", convert = TRUE)
5+
numeric_version(pd$`__version__`)
6+
}
7+
38
test_that("Simple Pandas data frames can be roundtripped", {
49
skip_if_no_pandas()
510

@@ -293,12 +298,12 @@ test_that("can cast from pandas nullable types", {
293298

294299
test_that("NA in string columns don't prevent simplification", {
295300
skip_if_no_pandas()
296-
301+
297302
pd <- import("pandas", convert = FALSE)
298303
np <- import("numpy", convert = FALSE)
299304

300305
x <- pd$Series(list("a", pd$`NA`, NULL, np$nan))
301-
expect_equal(py_to_r(x$dtype$name), "object")
306+
expect_equal(py_to_r(x$dtype$name), if (pandas_version() < "3") "object" else "str")
302307

303308
r <- py_to_r(x)
304309

0 commit comments

Comments
 (0)