Add HasAttr, GetAttr, and SetAttr to py::Object
Reviewers: ipaljak Reviewed By: ipaljak Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D2706
This commit is contained in:
parent
456267249e
commit
31a4c55e76
@ -38,7 +38,7 @@ class EnsureGIL final {
|
||||
};
|
||||
|
||||
/// Owns a `PyObject *` and supports a more C++ idiomatic API to objects.
|
||||
class Object final {
|
||||
class [[nodiscard]] Object final {
|
||||
PyObject *ptr_{nullptr};
|
||||
|
||||
public:
|
||||
@ -85,6 +85,56 @@ class Object final {
|
||||
/// @sa FetchError
|
||||
Object Str() const { return Object(PyObject_Str(ptr_)); }
|
||||
|
||||
/// Equivalent to `hasattr(this, attr_name)` in Python.
|
||||
///
|
||||
/// This function always succeeds, meaning that exceptions that occur while
|
||||
/// calling __getattr__ and __getattribute__ will get suppressed. To get error
|
||||
/// reporting, use GetAttr instead.
|
||||
bool HasAttr(const char *attr_name) const {
|
||||
return PyObject_HasAttrString(ptr_, attr_name);
|
||||
}
|
||||
|
||||
/// Equivalent to `hasattr(this, attr_name)` in Python.
|
||||
///
|
||||
/// This function always succeeds, meaning that exceptions that occur while
|
||||
/// calling __getattr__ and __getattribute__ will get suppressed. To get error
|
||||
/// reporting, use GetAttr instead.
|
||||
bool HasAttr(PyObject *attr_name) const {
|
||||
return PyObject_HasAttr(ptr_, attr_name);
|
||||
}
|
||||
|
||||
/// Equivalent to `this.attr_name` in Python.
|
||||
///
|
||||
/// Returned Object is nullptr if an error occurred.
|
||||
/// @sa FetchError
|
||||
Object GetAttr(const char *attr_name) const {
|
||||
return Object(PyObject_GetAttrString(ptr_, attr_name));
|
||||
}
|
||||
|
||||
/// Equivalent to `this.attr_name` in Python.
|
||||
///
|
||||
/// Returned Object is nullptr if an error occurred.
|
||||
/// @sa FetchError
|
||||
Object GetAttr(PyObject *attr_name) const {
|
||||
return Object(PyObject_GetAttr(ptr_, attr_name));
|
||||
}
|
||||
|
||||
/// Equivalent to `this.attr_name = v` in Python.
|
||||
///
|
||||
/// False is returned if an error occurred.
|
||||
/// @sa FetchError
|
||||
[[nodiscard]] bool SetAttr(const char *attr_name, PyObject *v) {
|
||||
return PyObject_SetAttrString(ptr_, attr_name, v) == 0;
|
||||
}
|
||||
|
||||
/// Equivalent to `this.attr_name = v` in Python.
|
||||
///
|
||||
/// False is returned if an error occurred.
|
||||
/// @sa FetchError
|
||||
[[nodiscard]] bool SetAttr(PyObject *attr_name, PyObject *v) {
|
||||
return PyObject_SetAttr(ptr_, attr_name, v) == 0;
|
||||
}
|
||||
|
||||
/// Equivalent to `callable()` in Python.
|
||||
///
|
||||
/// Returned Object is nullptr if an error occurred.
|
||||
@ -148,8 +198,7 @@ inline std::ostream &operator<<(std::ostream &os,
|
||||
if (!exc_info.type) return os;
|
||||
Object traceback_mod(PyImport_ImportModule("traceback"));
|
||||
CHECK(traceback_mod);
|
||||
Object format_exception_fn(
|
||||
PyObject_GetAttrString(traceback_mod, "format_exception"));
|
||||
Object format_exception_fn(traceback_mod.GetAttr("format_exception"));
|
||||
CHECK(format_exception_fn);
|
||||
auto list = format_exception_fn.Call(
|
||||
exc_info.type, exc_info.value ? exc_info.value : Py_None,
|
||||
|
@ -411,7 +411,7 @@ PyObject *PyQueryModuleAddReadProcedure(PyQueryModule *self, PyObject *cb) {
|
||||
}
|
||||
Py_INCREF(cb);
|
||||
py::Object py_cb(cb);
|
||||
py::Object py_name(PyObject_GetAttrString(py_cb, "__name__"));
|
||||
py::Object py_name(py_cb.GetAttr("__name__"));
|
||||
const auto *name = PyUnicode_AsUTF8(py_name);
|
||||
// TODO: Validate name
|
||||
auto *memory = self->module->procedures.get_allocator().GetMemoryResource();
|
||||
@ -1055,7 +1055,7 @@ template <class TFun>
|
||||
auto WithMgpModule(mgp_module *module_def, const TFun &fun) {
|
||||
py::Object py_mgp(PyImport_ImportModule("_mgp"));
|
||||
CHECK(py_mgp) << "Expected builtin '_mgp' to be available for import";
|
||||
py::Object py_mgp_module(PyObject_GetAttrString(py_mgp, "_MODULE"));
|
||||
py::Object py_mgp_module(py_mgp.GetAttr("_MODULE"));
|
||||
CHECK(py_mgp_module) << "Expected '_mgp' to have attribute '_MODULE'";
|
||||
// NOTE: This check is not thread safe, but this should only go through
|
||||
// ModuleRegistry::LoadModuleLibrary which ought to serialize loading.
|
||||
@ -1065,9 +1065,9 @@ auto WithMgpModule(mgp_module *module_def, const TFun &fun) {
|
||||
"modules?";
|
||||
auto *py_query_module = MakePyQueryModule(module_def);
|
||||
CHECK(py_query_module);
|
||||
CHECK(0 <= PyObject_SetAttrString(py_mgp, "_MODULE", py_query_module));
|
||||
CHECK(py_mgp.SetAttr("_MODULE", py_query_module));
|
||||
auto ret = fun();
|
||||
CHECK(0 <= PyObject_SetAttrString(py_mgp, "_MODULE", Py_None));
|
||||
CHECK(py_mgp.SetAttr("_MODULE", Py_None));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user