extensions/python/types/Types.h (306 lines of code) (raw):

/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <string> #include <optional> #include <utility> #include "../PyException.h" #include "utils/gsl.h" namespace org::apache::nifi::minifi::extensions::python { template<ReferenceType reference_type> class Object : public ReferenceHolder<reference_type> { public: using Reference = ObjectReference<reference_type>; Object() = default; explicit Object(Reference ref) : ReferenceHolder<reference_type>(std::move(ref)) { } explicit Object(PyObject* object) : ReferenceHolder<reference_type>(object) { } OwnedReference getAttribute(const char* attribute_name) { return OwnedReference(PyObject_GetAttrString(this->ref_.get(), attribute_name)); } }; namespace object { template<typename T> struct Converter {}; template<typename T> concept convertible = requires(T type) { { Converter<T>().from(std::forward<T>(type)) } -> std::same_as<OwnedObject>; }; // NOLINT(readability/braces) template<> struct Converter<bool> { OwnedObject from(bool value) { if (value) { return OwnedObject(Py_True); } return OwnedObject(Py_False); } }; template<> struct Converter<std::nullptr_t> { OwnedObject from(std::nullptr_t) { return OwnedObject(Py_None); } }; template<> struct Converter<std::string_view> { OwnedObject from(std::string_view value) { return OwnedObject(PyUnicode_FromStringAndSize(value.data(), value.length())); } }; template<> struct Converter<std::string> : public Converter<std::string_view> {}; template<typename T> requires std::signed_integral<T> && (sizeof(T) <= sizeof(long)) // NOLINT(runtime/int) struct Converter<T> { OwnedObject from(T value) { return OwnedObject(PyLong_FromLong(static_cast<long>(value))); // NOLINT(runtime/int) } }; template<typename T> requires std::unsigned_integral<T> && (sizeof(T) <= sizeof(unsigned long)) // NOLINT(runtime/int) struct Converter<T> { OwnedObject from(T value) { return OwnedObject(PyLong_FromUnsignedLong(static_cast<unsigned long>(value))); // NOLINT(runtime/int) } }; template<typename T> requires std::signed_integral<T> && (sizeof(T) > sizeof(long)) // NOLINT(runtime/int) struct Converter<T> { OwnedObject from(T value) { return OwnedObject(PyLong_FromLongLong(static_cast<long long>(value))); // NOLINT(runtime/int) } }; template<typename T> requires std::unsigned_integral<T> && (sizeof(T) > sizeof(unsigned long)) // NOLINT(runtime/int) struct Converter<T> { OwnedObject from(T value) { return OwnedObject(PyLong_FromUnsignedLongLong(static_cast<unsigned long>(value))); // NOLINT(runtime/int) } }; template<std::derived_from<OwnedReferenceHolder> T> struct Converter<T> { OwnedObject from(T&& ownedObject) { return OwnedObject(ownedObject.releaseReference()); } }; template<holder_type T> struct HolderTypeConverter { OwnedObject from(typename T::HeldType&& value) { auto typeObject = T::typeObject(); return OwnedObject(PyObject_CallFunction(reinterpret_cast<PyObject*>(typeObject), "O&", &HolderTypeConverter::convertToCapsule, reinterpret_cast<void*>(&value))); } static inline PyObject* convertToCapsule(void* ptr) { return PyCapsule_New(ptr, T::HeldTypeName, nullptr); } }; template<convertible T> OwnedObject from(T value) { return Converter<T>().from(std::forward<T>(value)); } template<convertible T> PyObject* returnReference(T value) { return from(std::forward<T>(value)).releaseReference(); } } // namespace object template<ReferenceType reference_type> class Long : public ReferenceHolder<reference_type> { public: using Reference = ObjectReference<reference_type>; Long() = default; explicit Long(Reference ref) : ReferenceHolder<reference_type>(std::move(ref)) { } explicit Long(PyObject* object) : ReferenceHolder<reference_type>(object) { } int64_t asInt64() { auto long_value = PyLong_AsLongLong(this->ref_.get()); if (long_value == -1 && PyErr_Occurred()) { throw PyException(); } return gsl::narrow<int64_t>(long_value); } static BorrowedLong fromTuple(PyObject* tuple, Py_ssize_t location) requires(reference_type == ReferenceType::BORROWED) { BorrowedLong long_from_tuple{PyTuple_GetItem(tuple, location)}; if (long_from_tuple.get() == nullptr) throw PyException(); return long_from_tuple; } }; template<ReferenceType reference_type> class Bytes : public ReferenceHolder<reference_type> { public: using Reference = ObjectReference<reference_type>; Bytes() = default; explicit Bytes(Reference ref) : ReferenceHolder<reference_type>(std::move(ref)) { } explicit Bytes(PyObject* object) : ReferenceHolder<reference_type>(object) { } static OwnedBytes fromStringAndSize(std::string_view string) requires(reference_type == ReferenceType::OWNED) { return OwnedBytes(PyBytes_FromStringAndSize(string.data(), string.length())); } }; template<ReferenceType reference_type> class Str : public ReferenceHolder<reference_type> { public: using Reference = ObjectReference<reference_type>; Str() = default; explicit Str(Reference ref) : ReferenceHolder<reference_type>(std::move(ref)) { } explicit Str(PyObject* object) : ReferenceHolder<reference_type>(object) { } std::string toUtf8String() { auto utf8coded_bytes = OwnedBytes(PyUnicode_AsUTF8String(this->ref_.get())); return std::string(PyBytes_AsString(utf8coded_bytes.get())); } static OwnedStr from(convertible_to_object auto object) requires(reference_type == ReferenceType::OWNED) { return OwnedStr(PyObject_Str(static_cast<PyObject*>(object))); } static BorrowedStr fromTuple(PyObject* tuple, Py_ssize_t location) requires(reference_type == ReferenceType::BORROWED) { BorrowedStr string_from_tuple{PyTuple_GetItem(tuple, location)}; if (string_from_tuple.get() == nullptr) throw PyException(); return string_from_tuple; } }; template<ReferenceType reference_type> class List : public ReferenceHolder<reference_type> { public: using Reference = ObjectReference<reference_type>; List() = default; explicit List(Reference ref) : ReferenceHolder<reference_type>(std::move(ref)) { } explicit List(PyObject* object) : ReferenceHolder<reference_type>(object) { } static OwnedList create() requires(reference_type == ReferenceType::OWNED) { return OwnedList(PyList_New(0)); } template<object::convertible T> void append(T value) { PyList_Append(this->ref_.get(), object::from(std::move(value)).releaseReference()); } size_t length() { return PyList_Size(this->ref_.get()); } BorrowedReference operator[](size_t index) { auto item = PyList_GetItem(this->ref_.get(), index); if (!item) { throw PyException(); } return BorrowedReference(item); } static BorrowedList fromTuple(PyObject* tuple, Py_ssize_t location) requires(reference_type == ReferenceType::BORROWED) { BorrowedList list_from_tuple{PyTuple_GetItem(tuple, location)}; if (list_from_tuple.get() == nullptr) throw PyException(); return list_from_tuple; } }; template<ReferenceType reference_type> class Dict : public ReferenceHolder<reference_type> { public: using Reference = ObjectReference<reference_type>; Dict() = default; explicit Dict(Reference ref) : ReferenceHolder<reference_type>(std::move(ref)) { } explicit Dict(PyObject* object) : ReferenceHolder<reference_type>(object) { } static OwnedDict create() requires(reference_type == ReferenceType::OWNED) { return OwnedDict(PyDict_New()); } template<object::convertible T> bool contains(T key) const { auto key_object = object::from(key); return PyDict_Contains(this->ref_.get(), key_object.get()) != 0; } template<object::convertible T> void put(const char* key, T value) { PyDict_SetItemString(this->ref_.get(), key, object::from(std::move(value)).releaseReference()); } template<object::convertible T> void put(const std::string& key, T value) { put(key.c_str(), std::move(value)); } std::optional<BorrowedReference> operator[](const char* key) { auto item = BorrowedReference(PyDict_GetItemString(this->ref_.get(), key)); return item ? std::optional{item} : std::nullopt; } std::optional<BorrowedReference> operator[](const std::string& key) { return operator[](key.c_str()); } static BorrowedDict fromTuple(PyObject* tuple, Py_ssize_t location) requires(reference_type == ReferenceType::BORROWED) { BorrowedDict dict_from_tuple{PyTuple_GetItem(tuple, location)}; if (dict_from_tuple.get() == nullptr) throw PyException(); return dict_from_tuple; } }; namespace callable { template<ReferenceType reference_type> ObjectReference<reference_type> argument(ObjectReference<reference_type> reference) { return reference; } static inline BorrowedReference argument(std::nullptr_t) { return BorrowedReference(Py_None); } static inline BorrowedReference argument(bool value) { return BorrowedReference(value ? Py_True : Py_False); } template<typename T> OwnedReference argument(T value) { return OwnedReference(object::from(std::forward<T>(value)).releaseReference()); } } // namespace callable template<ReferenceType reference_type> class Callable : public ReferenceHolder<reference_type> { public: using Reference = ObjectReference<reference_type>; Callable() = default; explicit Callable(Reference ref) : ReferenceHolder<reference_type>(std::move(ref)) { } explicit Callable(PyObject* object) : ReferenceHolder<reference_type>(object) { } template<typename... Args> OwnedReference operator()(Args&& ...args) { return OwnedReference(PyObject_CallFunctionObjArgs(this->ref_.get(), callable::argument(std::forward<Args>(args)).get()..., nullptr)); } }; template<ReferenceType reference_type> class Module : public ReferenceHolder<reference_type> { public: using Reference = ObjectReference<reference_type>; Module() = default; explicit Module(Reference ref) : ReferenceHolder<reference_type>(std::move(ref)) { } explicit Module(PyObject* object) : ReferenceHolder<reference_type>(object) { } static OwnedModule import(const char* module_name) requires(reference_type == ReferenceType::OWNED) { return OwnedModule(PyImport_ImportModule(module_name)); } OwnedCallable getFunction(const char* function_name) { return OwnedCallable(PyObject_GetAttrString(this->ref_.get(), function_name)); } }; template<class T> PyObject* newPythonAllocatedInstance(PyTypeObject* type, PyObject*, PyObject*) { auto self = PyType_GenericAlloc(type, 0); if (self == nullptr) { return nullptr; } new (self) T(); return self; } template<class T> void pythonAllocatedInstanceDealloc(T* self) { self->~T(); } } // namespace org::apache::nifi::minifi::extensions::python