Skip to content

Commit

Permalink
Merge pull request #1698 from rstudio/more-py3-13-hasattr-fixes
Browse files Browse the repository at this point in the history
More updates for Python 3.13
  • Loading branch information
t-kalinowski authored Nov 13, 2024
2 parents faba77f + e5a75e4 commit 141c1cb
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 20 deletions.
2 changes: 1 addition & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
- Added support for Python 3.13. Note that Python 3.13 removed support
for `classmethod` descriptors, which may affect the S3 class of
some Python objects that use metaclass properties to resolve a class’s
`__module__` or `__name__` attribute. (#1686)
`__module__` or `__name__` attribute. (#1686, #1698)

- `py_is_null_xptr()` and `[[` now load delayed modules (#1688).

Expand Down
4 changes: 2 additions & 2 deletions R/RcppExports.R
Original file line number Diff line number Diff line change
Expand Up @@ -295,8 +295,8 @@ py_eval_impl <- function(code, convert = TRUE) {
.Call(`_reticulate_py_eval_impl`, code, convert)
}

py_convert_pandas_series <- function(series) {
.Call(`_reticulate_py_convert_pandas_series`, series)
py_convert_pandas_series <- function(series_) {
.Call(`_reticulate_py_convert_pandas_series`, series_)
}

py_convert_pandas_df <- function(df) {
Expand Down
8 changes: 4 additions & 4 deletions src/RcppExports.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -650,13 +650,13 @@ BEGIN_RCPP
END_RCPP
}
// py_convert_pandas_series
SEXP py_convert_pandas_series(PyObjectRef series);
RcppExport SEXP _reticulate_py_convert_pandas_series(SEXP seriesSEXP) {
SEXP py_convert_pandas_series(PyObjectRef series_);
RcppExport SEXP _reticulate_py_convert_pandas_series(SEXP series_SEXP) {
BEGIN_RCPP
Rcpp::RObject rcpp_result_gen;
Rcpp::RNGScope rcpp_rngScope_gen;
Rcpp::traits::input_parameter< PyObjectRef >::type series(seriesSEXP);
rcpp_result_gen = Rcpp::wrap(py_convert_pandas_series(series));
Rcpp::traits::input_parameter< PyObjectRef >::type series_(series_SEXP);
rcpp_result_gen = Rcpp::wrap(py_convert_pandas_series(series_));
return rcpp_result_gen;
END_RCPP
}
Expand Down
2 changes: 1 addition & 1 deletion src/libpython.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ bool loadLibrary(const std::string& libPath, void** ppLib, std::string* pError)
*ppLib = (void*)::LoadLibraryEx(libPath.c_str(), NULL, 0);
#else
if (libPath == "NA") {
*ppLib = ::dlopen(NULL, RTLD_NOW|RTLD_GLOBAL);
*ppLib = ::dlopen(NULL, RTLD_NOW|RTLD_GLOBAL); // on linux, should we also do: | RTLD_DEEPBIND ??
} else {
*ppLib = ::dlopen(libPath.c_str(), RTLD_NOW|RTLD_GLOBAL);
}
Expand Down
31 changes: 19 additions & 12 deletions src/python.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1312,8 +1312,21 @@ void set_string_element(SEXP rArray, int i, PyObject* pyStr) {
SET_STRING_ELT(rArray, i, strSEXP);
}

static inline
bool py_has_attr(PyObject* x_, const char* name) {
switch (PyObject_HasAttrStringWithError(x_, name)) {
case 1: return true;
case 0: return false;
case -1:
default:
PyErr_Clear();
return false;
}
}


bool py_is_callable(PyObject* x) {
return PyCallable_Check(x) == 1 || PyObject_HasAttrString(x, "__call__");
return PyCallable_Check(x) == 1 || py_has_attr(x, "__call__");
}

// [[Rcpp::export]]
Expand Down Expand Up @@ -1546,7 +1559,7 @@ SEXP py_to_r_cpp(PyObject* x, bool convert, bool simple) {
}

// tuple (but don't convert namedtuple as it's often a custom class)
if (PyTuple_CheckExact(x) && !PyObject_HasAttrString(x, "_fields")) {
if (PyTuple_CheckExact(x) && !py_has_attr(x, "_fields")) {
Py_ssize_t len = PyTuple_Size(x);
Rcpp::List list(len);
for (Py_ssize_t i = 0; i<len; i++)
Expand Down Expand Up @@ -3361,14 +3374,7 @@ PyObjectRef py_new_ref(PyObjectRef x, SEXP convert) {
bool py_has_attr(PyObjectRef x, const std::string& name) {
GILScope _gil;
PyObject* x_ = x.get(); // ensure python initialized, module proxy resolved
switch (PyObject_HasAttrStringWithError(x_, name.c_str())) {
case 1: return true;
case 0: return false;
case -1:
default:
PyErr_Clear();
return false;
}
return py_has_attr(x_, name.c_str());
}

//' Get an attribute of a Python object
Expand Down Expand Up @@ -4013,8 +4019,9 @@ SEXPTYPE nullable_typename_to_sexptype (const std::string& name) {
}

// [[Rcpp::export]]
SEXP py_convert_pandas_series(PyObjectRef series) {
SEXP py_convert_pandas_series(PyObjectRef series_) {
GILScope _gil;
PyObject* series = series_.get();

// extract dtype
PyObjectPtr dtype(PyObject_GetAttrString(series, "dtype"));
Expand Down Expand Up @@ -4078,7 +4085,7 @@ SEXP py_convert_pandas_series(PyObjectRef series) {
} else if (name == "datetime64[ns]" ||

// if a time zone is present, dtype is "object"
PyObject_HasAttrString(series, "dt")) {
py_has_attr(series, "dt")) {

// pd.Series.items() returns an iterator over (index, value) pairs
PyObjectPtr items(PyObject_CallMethod(series, "items", NULL));
Expand Down

0 comments on commit 141c1cb

Please sign in to comment.