#pragma once #include #include // Note: forward declare basic object class for Python struct _object; // NOLINT(bugprone-reserved-identifier, cert-dcl37-c, cert-dcl51-cpp) namespace cxxpython { //! PyObject wrapper /*! Uses Python ref counting */ class Object { _object* object; public: ~Object() noexcept; Object(const Object& obj2) noexcept; Object& operator=(const Object& obj2) noexcept; Object(Object&& obj2) noexcept; Object& operator=(Object&& obj2) noexcept; private: explicit Object(_object* objectIn) noexcept : object{ objectIn } {} public: explicit(false) Object(nullptr_t) noexcept // NOLINT(google-explicit-constructor, hicpp-explicit-conversions) : object{ nullptr } {} [[nodiscard]] static Object FromNew(_object* objectIn) noexcept; [[nodiscard]] static Object FromBorrowed(_object* objectIn) noexcept; public: [[nodiscard]] Object at(int index) const noexcept; [[nodiscard]] constexpr bool operator!=(nullptr_t) const noexcept { return object != nullptr; } [[nodiscard]] constexpr bool operator==(nullptr_t) const noexcept { return object == nullptr; } // Note: use with Python/C API only! [[nodiscard]] constexpr _object* get() noexcept { return object; } [[nodiscard]] constexpr _object* get() const noexcept { return object; } private: void DecreaseRefCount() noexcept; }; //! Convert object to string std::string ToString(const Object& object); //! Convert object to long long ToLong(const Object& object) noexcept; //! Convert object to bool bool ToBool(const Object& object) noexcept; //! Python callable wrapper class Callable { Object func; public: explicit(false) Callable(nullptr_t) noexcept // NOLINT(google-explicit-constructor, hicpp-explicit-conversions) : func{ nullptr } {} explicit Callable(_object* object) noexcept; public: constexpr bool operator!=(nullptr_t) const noexcept { return func != nullptr; } constexpr bool operator==(nullptr_t) const noexcept { return func == nullptr; } Object operator()() const noexcept; Object operator()(const char* format, ...) const noexcept; }; //! Python interpreter wrapper class PyCore { struct Module { Object pyModule{ nullptr }; Object pyDictionary{ nullptr }; }; bool isRunning{ false }; std::map modules{}; public: PyCore(const PyCore&) = delete; PyCore& operator=(const PyCore&) = delete; private: ~PyCore(); PyCore() = default; public: static PyCore& Instance(); public: //! Start Python interpreter from local path. /*! Requires: The argument should point to a zero-terminated character string in static storage whose contents will not change for the duration of the program’s execution see https://docs.python.org/3/c-api/init.html#c.Py_SetPythonHome */ bool Start(const wchar_t* pyPath = nullptr) noexcept; //! Stop Python interpreter. /*! Requires: Every Object should be destroyed before calling PyCore.Stop() */ void Stop() noexcept; [[nodiscard]] bool IsRunning() const noexcept; bool LoadModule(const std::string& moduleName, const std::string& pyFileName); [[nodiscard]] Callable PyFunction(const std::string& moduleName, const std::string& funcName) const; }; } // namespace cxxpython