This is an automated email from the ASF dual-hosted git repository. bmahler pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mesos.git
commit 254e5c2dd888bd08309dc59254a1cf2d9a745625 Author: Andrei Sekretenko <[email protected]> AuthorDate: Wed Jul 24 11:01:39 2019 -0400 Added a helper to create vector from iterable into python bindings. Review: https://reviews.apache.org/r/71082/ --- src/python/native_common/common.hpp | 104 ++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/src/python/native_common/common.hpp b/src/python/native_common/common.hpp index ed743aa..fadec27 100644 --- a/src/python/native_common/common.hpp +++ b/src/python/native_common/common.hpp @@ -22,8 +22,12 @@ #include <Python.h> #include <iostream> +#include <memory> +#include <string> +#include <vector> #include <google/protobuf/io/zero_copy_stream_impl.h> +#include <google/protobuf/message.h> namespace mesos { namespace python { @@ -130,6 +134,106 @@ PyObject* createPythonProtobuf(const T& t, const char* typeName) str.size()); } + +// construct<T>() should take PyObject* as an argument, try to convert that +// PyObject into an object of type T and return an object of type equivalent +// to std::unique_ptr<T> that should hold +// - the conversion result on success +// - nullptr on failure +// Also, the Python exception should be set on conversion failure. +// +// TODO(asekretenko): use std::optional or stout Try instead of +// std::unique_ptr when they become available in this code. +// +// Declaration of 'construct<T>()' for protobufs. +template <typename T> +typename std::enable_if< + std::is_base_of<google::protobuf::Message, T>::value, + std::unique_ptr<T>>::type +construct(PyObject* obj) +{ + std::unique_ptr<T> result(new T()); + if (!readPythonProtobuf(obj, result.get())) { + PyErr_Format( + PyExc_TypeError, + "Failed to construct %s from a Python object", + result->GetDescriptor()->full_name().c_str()); + + return nullptr; + } + + return result; +} + + +// Declaration of 'construct<T>()' for non-protobufs. +template <typename T> +typename std::enable_if< + !std::is_base_of<google::protobuf::Message, T>::value, + std::unique_ptr<T>>::type +construct(PyObject* obj); + + +// TODO(asekretenko): move this specialization into .cpp file. That file will +// likely have to be put into a library (there is no simple way to use one +// source file in two python extensions that can be built concurrently). +template <> +inline std::unique_ptr<std::string> construct<std::string>(PyObject* obj) +{ + char* chars; + Py_ssize_t len; + if (PyString_AsStringAndSize(obj, &chars, &len) < 0) { + PyErr_Print(); + PyErr_Format( + PyExc_TypeError, + "Cannot construct std::string from a non-string object"); + + return nullptr; + } + + return std::unique_ptr<std::string>(new std::string(chars, len)); +} + + +template <typename T> +std::unique_ptr<std::vector<T>> constructFromIterable(PyObject* iterable) +{ + PyObject* pyIterator = PyObject_GetIter(iterable); + if (pyIterator == nullptr) { + PyErr_Format( + PyExc_TypeError, + "Cannot construct std::vector from a non-iterable object"); + return nullptr; + } + + std::unique_ptr<std::vector<T>> result(new std::vector<T>()); + + PyObject* pyItem; + + while ((pyItem = PyIter_Next(pyIterator)) != nullptr) { + std::unique_ptr<T> item = construct<T>(pyItem); + if (!item) { + // An exception has already been set by construct<>(). + Py_DECREF(pyItem); + Py_DECREF(pyIterator); + return nullptr; + } + + result->emplace_back(std::move(*item)); + Py_DECREF(pyItem); + } + + Py_DECREF(pyIterator); + + if (PyErr_Occurred() != nullptr) { + return nullptr; + } + + return result; +} + + + } // namespace python { } // namespace mesos {
