aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/pybind/attr.h
diff options
context:
space:
mode:
authorthegeorg <thegeorg@yandex-team.com>2023-10-03 11:19:48 +0300
committerthegeorg <thegeorg@yandex-team.com>2023-10-03 11:43:28 +0300
commitcda0c13f23f6b169fb0a49dc504b40a0aaecea09 (patch)
tree26476e92e5af2c856e017afb1df8f8dff42495bf /library/cpp/pybind/attr.h
parent4854116da9c5e3c95bb8440f2ea997c54b6e1a61 (diff)
downloadydb-cda0c13f23f6b169fb0a49dc504b40a0aaecea09.tar.gz
Move contrib/tools/jdk to build/platform/java/jdk/testing
Diffstat (limited to 'library/cpp/pybind/attr.h')
-rw-r--r--library/cpp/pybind/attr.h412
1 files changed, 412 insertions, 0 deletions
diff --git a/library/cpp/pybind/attr.h b/library/cpp/pybind/attr.h
new file mode 100644
index 00000000000..5f25a6d73d1
--- /dev/null
+++ b/library/cpp/pybind/attr.h
@@ -0,0 +1,412 @@
+#pragma once
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+#include <util/generic/string.h>
+#include <util/generic/map.h>
+#include <util/generic/set.h>
+#include <util/generic/vector.h>
+#include <util/generic/ptr.h>
+
+#include "cast.h"
+#include "exceptions.h"
+
+namespace NPyBind {
+ // TBaseAttrGetter
+ template <typename TObjType>
+ class TBaseAttrGetter {
+ public:
+ virtual ~TBaseAttrGetter() {
+ }
+ virtual bool GetAttr(PyObject* owner, const TObjType& self, const TString& attr, PyObject*& res) const = 0;
+
+ virtual bool HasAttr(PyObject* owner, const TObjType& self, const TString& attr, const TSet<TString>& hiddenNames) const {
+ if (hiddenNames.find(attr) != hiddenNames.end())
+ return false;
+ PyObject* res = nullptr;
+ if (!GetAttr(owner, self, attr, res))
+ return false;
+ Py_XDECREF(res);
+ return true;
+ }
+ };
+
+ template <typename TObjType>
+ class TBaseAttrSetter {
+ public:
+ virtual ~TBaseAttrSetter() {
+ }
+
+ virtual bool SetAttr(PyObject* owner, TObjType& self, const TString& attr, PyObject* val) = 0;
+ };
+
+ template <typename TObjType>
+ class TAttrGetters {
+ public:
+ typedef TSimpleSharedPtr<TBaseAttrGetter<TObjType>> TGetterPtr;
+
+ private:
+ typedef TVector<TGetterPtr> TGetterList;
+ typedef TMap<TString, TGetterList> TGetterMap;
+
+ const TSet<TString>& HiddenAttrNames;
+ TGetterMap Getters;
+
+ public:
+ TAttrGetters(const TSet<TString>& hiddenNames)
+ : HiddenAttrNames(hiddenNames)
+ {
+ }
+
+ void AddGetter(const TString& attr, TGetterPtr getter) {
+ Getters[attr].push_back(getter);
+ }
+
+ PyObject* GetAttr(PyObject* owner, const TObjType& self, const TString& attr) const {
+ typename TGetterMap::const_iterator it1 = Getters.find(attr);
+ if (it1 == Getters.end())
+ it1 = Getters.find("");
+ if (it1 == Getters.end())
+ return nullptr;
+ const TGetterList& lst = it1->second;
+ for (typename TGetterList::const_iterator it2 = lst.begin(), end = lst.end(); it2 != end; ++it2) {
+ PyObject* res = nullptr;
+ if ((*it2)->GetAttr(owner, self, attr, res))
+ return res;
+ // IMPORTANT!
+ // we have to fail GetAttr right there because we've failed because of internal python error/exception and can't continue iterating because
+ // it cause subsequent exceptions during call to Py_BuildValue
+ // moreover we have to preserve original exception right there
+ if (PyErr_Occurred()) {
+ break;
+ }
+ }
+ return nullptr;
+ }
+
+ bool HasAttr(PyObject* owner, const TObjType& self, const TString& attr) const {
+ typename TGetterMap::const_iterator it1 = Getters.find(attr);
+ if (it1 == Getters.end())
+ return false;
+ const TGetterList& lst = it1->second;
+ for (typename TGetterList::const_iterator it2 = lst.begin(), end = lst.end(); it2 != end; ++it2) {
+ if ((*it2)->HasAttr(owner, self, attr, HiddenAttrNames))
+ return true;
+ }
+ return false;
+ }
+
+ void GetAttrsDictionary(PyObject* owner, const TObjType& self, TMap<TString, PyObject*>& res) const {
+ for (typename TGetterMap::const_iterator it = Getters.begin(), end = Getters.end(); it != end; ++it) {
+ try {
+ if (HasAttr(owner, self, it->first)) {
+ auto attrPtr = GetAttr(owner, self, it->first);
+ if (attrPtr) {
+ res[it->first] = attrPtr;
+ }
+ if (PyErr_Occurred()) {
+ PyErr_Clear(); // Skip python errors as well
+ }
+ }
+ } catch (const std::exception&) {
+ // ignore this field
+ }
+ }
+ }
+
+ void GetAttrsNames(PyObject* owner, const TObjType& self, TVector<TString>& resultNames) const {
+ for (typename TGetterMap::const_iterator it = Getters.begin(), end = Getters.end(); it != end; ++it) {
+ if (HasAttr(owner, self, it->first))
+ resultNames.push_back(it->first);
+ }
+ }
+ };
+
+ template <typename TObjType>
+ class TGenericAttrGetter: public TBaseAttrGetter<TObjType> {
+ private:
+ TString AttrName;
+
+ public:
+ TGenericAttrGetter(const TString& attrName)
+ : AttrName(attrName)
+ {
+ }
+
+ bool GetAttr(PyObject* obj, const TObjType&, const TString&, PyObject*& res) const override {
+ auto str = NameFromString(AttrName);
+ res = PyObject_GenericGetAttr(obj, str.Get());
+ if (!res && !PyErr_Occurred())
+ ythrow TPyErr(PyExc_AttributeError) << "Can't get generic attribute '" << AttrName << "'";
+ return res;
+ }
+ };
+
+ template <typename TObjType>
+ class TAttrSetters {
+ private:
+ typedef TSimpleSharedPtr<TBaseAttrSetter<TObjType>> TSetterPtr;
+ typedef TVector<TSetterPtr> TSetterList;
+ typedef TMap<TString, TSetterList> TSetterMap;
+
+ TSetterMap Setters;
+
+ public:
+ void AddSetter(const TString& attr, TSetterPtr setter) {
+ Setters[attr].push_back(setter);
+ }
+
+ bool SetAttr(PyObject* owner, TObjType& self, const TString& attr, PyObject* val) {
+ typename TSetterMap::const_iterator it1 = Setters.find(attr);
+ if (it1 == Setters.end())
+ it1 = Setters.find("");
+ if (it1 == Setters.end())
+ return false;
+ const TSetterList& lst = it1->second;
+ for (typename TSetterList::const_iterator it2 = lst.begin(), end = lst.end(); it2 != end; ++it2) {
+ if ((*it2)->SetAttr(owner, self, attr, val))
+ return true;
+ }
+ return false;
+ }
+
+ bool SetAttrDictionary(PyObject* owner, TObjType& self, TMap<TString, PyObject*>& dict) {
+ for (TMap<TString, PyObject*>::const_iterator it = dict.begin(), end = dict.end(); it != end; ++it) {
+ try {
+ SetAttr(owner, self, it->first, it->second);
+ } catch (std::exception&) {
+ // ignore this field
+ }
+ }
+
+ return true;
+ }
+ };
+
+ /**
+ * TMethodAttrGetter - this class maps Python attribute read to C++ method call
+ */
+ template <typename TObjType, typename TResult, typename TSubObject>
+ class TMethodAttrGetter: public TBaseAttrGetter<TObjType> {
+ private:
+ typedef TResult (TSubObject::*TMethod)() const;
+ TMethod Method;
+
+ public:
+ TMethodAttrGetter(TMethod method)
+ : Method(method)
+ {
+ }
+
+ bool GetAttr(PyObject*, const TObjType& self, const TString&, PyObject*& res) const override {
+ const TSubObject* sub = dynamic_cast<const TSubObject*>(&self);
+ if (sub == nullptr)
+ return false;
+ res = BuildPyObject((sub->*Method)());
+ return (res != nullptr);
+ }
+ };
+
+ template <typename TObjType, typename TFunctor>
+ class TFunctorAttrGetter: public TBaseAttrGetter<TObjType> {
+ TFunctor Functor;
+ public:
+ explicit TFunctorAttrGetter(TFunctor functor)
+ : Functor(functor)
+ {
+ }
+
+ bool GetAttr(PyObject*, const TObjType& self, const TString&, PyObject*& res) const override {
+ res = BuildPyObject(Functor(self));
+ return (res != nullptr);
+ }
+ };
+
+
+ /**
+ * TMethodAttrGetterWithCheck - this class maps Python attribute read to C++ HasAttr/GetAttr call
+ * If HasAttr returns false, None is returned.
+ * Otherwise GetAttr is called.
+ */
+ template <typename TObjType, typename TResult, typename TSubObject>
+ class TMethodAttrGetterWithCheck: public TBaseAttrGetter<TObjType> {
+ private:
+ typedef TResult (TSubObject::*TMethod)() const;
+ typedef bool (TSubObject::*TCheckerMethod)() const;
+ TMethod Method;
+ TCheckerMethod CheckerMethod;
+
+ public:
+ TMethodAttrGetterWithCheck(TMethod method, TCheckerMethod checkerMethod)
+ : Method(method)
+ , CheckerMethod(checkerMethod)
+ {
+ }
+
+ bool GetAttr(PyObject*, const TObjType& self, const TString&, PyObject*& res) const override {
+ const TSubObject* sub = dynamic_cast<const TSubObject*>(&self);
+ if (sub == nullptr)
+ return false;
+ if ((sub->*CheckerMethod)())
+ res = BuildPyObject((sub->*Method)());
+ else {
+ Py_INCREF(Py_None);
+ res = Py_None;
+ }
+ return (res != nullptr);
+ }
+ };
+
+ template <typename TObjType, typename TResult, typename TSubObject, typename TMapper>
+ class TMethodAttrMappingGetter: public TBaseAttrGetter<TObjType> {
+ private:
+ typedef TResult (TSubObject::*TMethod)() const;
+
+ TMethod Method;
+ TMapper Mapper;
+
+ public:
+ TMethodAttrMappingGetter(TMethod method, TMapper mapper)
+ : Method(method)
+ , Mapper(mapper)
+ {
+ }
+
+ bool GetAttr(PyObject*, const TObjType& self, const TString&, PyObject*& res) const override {
+ const TSubObject* sub = dynamic_cast<const TSubObject*>(&self);
+ if (sub == nullptr)
+ return false;
+ res = BuildPyObject(Mapper((sub->*Method)()));
+ return (res != nullptr);
+ }
+ };
+
+ template <typename TObjType, typename TResult, typename TSubObject, typename TMapper>
+ TSimpleSharedPtr<TBaseAttrGetter<TObjType>>
+ CreateMethodAttrMappingGetter(TResult (TSubObject::*method)() const,
+ TMapper mapper) {
+ return new TMethodAttrMappingGetter<TObjType, TResult, TSubObject, TMapper>(method,
+ mapper);
+ }
+
+ template <typename TObjType, typename TResult, typename TValue, typename TSubObject>
+ class TMethodAttrSetter: public TBaseAttrSetter<TObjType> {
+ private:
+ typedef TResult (TSubObject::*TMethod)(TValue&);
+ TMethod Method;
+
+ public:
+ TMethodAttrSetter(TMethod method)
+ : Method(method)
+ {
+ }
+
+ virtual bool SetAttr(PyObject*, TObjType& self, const TString&, PyObject* val) {
+ TSubObject* sub = dynamic_cast<TSubObject*>(&self);
+ if (sub == nullptr)
+ return false;
+ TValue value;
+ if (!FromPyObject(val, value))
+ return false;
+ (sub->*Method)(value);
+ return true;
+ }
+ };
+
+ template <typename TObjType, typename TValue, typename TFunctor>
+ class TFunctorAttrSetter: public TBaseAttrSetter<TObjType> {
+ TFunctor Functor;
+ public:
+ explicit TFunctorAttrSetter(TFunctor functor)
+ : Functor(functor)
+ {
+ }
+
+ bool SetAttr(PyObject*, TObjType& self, const TString&, PyObject* val) const override {
+ TValue value;
+ if (!FromPyObject(val, value))
+ return false;
+ auto res = BuildPyObject(Functor(self, value));
+ return (res != nullptr);
+ }
+ };
+ template <typename TObjType, typename TResult, typename TSubObject>
+ TSimpleSharedPtr<TBaseAttrGetter<TObjType>> CreateMethodAttrGetter(TResult (TSubObject::*method)() const) {
+ return new TMethodAttrGetter<TObjType, TResult, TSubObject>(method);
+ }
+
+ template <typename TObjType, typename TFunctor>
+ TSimpleSharedPtr<TFunctorAttrGetter<TObjType, TFunctor>> CreateFunctorAttrGetter(TFunctor functor) {
+ return MakeSimpleShared<TFunctorAttrGetter<TObjType, TFunctor>>(functor);
+ }
+
+ template <typename TObjType, typename TResult, typename TSubObject>
+ TSimpleSharedPtr<TBaseAttrGetter<TObjType>> CreateMethodAttrGetterWithCheck(
+ TResult (TSubObject::*method)() const,
+ bool (TSubObject::*checkerMethod)() const) {
+ return new TMethodAttrGetterWithCheck<TObjType, TResult, TSubObject>(method, checkerMethod);
+ }
+
+ template <typename TObjType, typename TResult, typename TValue, typename TSubObject>
+ TSimpleSharedPtr<TBaseAttrSetter<TObjType>> CreateMethodAttrSetter(TResult (TSubObject::*method)(TValue&)) {
+ return new TMethodAttrSetter<TObjType, TResult, TValue, TSubObject>(method);
+ }
+
+ template <typename TObjType, typename TFunctor, typename TValue>
+ TSimpleSharedPtr<TFunctorAttrSetter<TObjType, TValue, TFunctor>> CreateFunctorAttrSetter(TFunctor functor) {
+ return MakeSimpleShared<TFunctorAttrSetter<TObjType, TValue, TFunctor>>(functor);
+ }
+
+ template <typename TObjType, typename TValue, typename TSubObject>
+ class TDirectAttrSetter: public TBaseAttrSetter<TObjType> {
+ private:
+ typedef TValue TSubObject::*TValueType;
+ TValueType Value;
+
+ public:
+ TDirectAttrSetter(TValueType value)
+ : Value(value)
+ {
+ }
+
+ bool SetAttr(PyObject*, TObjType& self, const TString&, PyObject* val) override {
+ TSubObject* sub = dynamic_cast<TSubObject*>(&self);
+ if (sub == NULL)
+ return false;
+ if (!FromPyObject(val, sub->*Value))
+ return false;
+ return true;
+ }
+ };
+
+ template <typename TObjType, typename TValue, typename TSubObject>
+ TSimpleSharedPtr<TBaseAttrSetter<TObjType>> CreateAttrSetter(TValue TSubObject::*value) {
+ return new TDirectAttrSetter<TObjType, TValue, TSubObject>(value);
+ }
+
+ template <typename TObjType, typename TValue, typename TSubObject>
+ class TDirectAttrGetter: public TBaseAttrGetter<TObjType> {
+ private:
+ typedef TValue TSubObject::*TValueType;
+ TValueType Value;
+
+ public:
+ TDirectAttrGetter(TValueType value)
+ : Value(value)
+ {
+ }
+
+ bool GetAttr(PyObject*, const TObjType& self, const TString&, PyObject*& res) const override {
+ const TSubObject* sub = dynamic_cast<const TSubObject*>(&self);
+ if (sub == nullptr)
+ return false;
+ res = BuildPyObject(sub->*Value);
+ return (res != nullptr);
+ }
+ };
+
+ template <typename TObjType, typename TValue, typename TSubObject>
+ TSimpleSharedPtr<TBaseAttrGetter<TObjType>> CreateAttrGetter(TValue TSubObject::*value) {
+ return new TDirectAttrGetter<TObjType, TValue, TSubObject>(value);
+ }
+}