123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 |
- #pragma once
- #define PY_SSIZE_T_CLEAN
- #include <Python.h>
- #include "ptr.h"
- #include "cast.h"
- #include "exceptions.h"
- #include <util/generic/function.h>
- namespace NPyBind {
- #if PY_MAJOR_VERSION >= 3
- namespace NPrivate {
- using TFinalizationCallBack = std::function<void()>;
- void AddFinalizationCallBack(TFinalizationCallBack);
- class TAtExitRegistrar: private TNonCopyable {
- TAtExitRegistrar(TPyObjectPtr module);
- public:
- static void Instantiate(TPyObjectPtr module) {
- static TAtExitRegistrar registrar(module);
- Y_UNUSED(registrar);
- }
- };
- class TPyBindModuleRegistrar: private TNonCopyable {
- TPyBindModuleRegistrar();
- TPyObjectPtr Module;
- public:
- static void Instantiate() {
- static TPyBindModuleRegistrar registrar;
- Y_UNUSED(registrar);
- }
- };
- } //NPrivate
- #endif
- class TModuleHolder {
- private:
- TModuleHolder(const TModuleHolder&);
- TModuleHolder& operator=(const TModuleHolder&);
- TModuleHolder();
- private:
- typedef PyCFunction TModuleMethod;
- #if PY_MAJOR_VERSION >= 3
- typedef PyObject* (*TModuleInitFunc)();
- #else
- typedef void (*TModuleInitFunc)();
- #endif
- struct TMethodDef {
- TString Name;
- TModuleMethod Method;
- TString Description;
- int Flags;
- TMethodDef(const TString& name, TModuleMethod method, const TString& descr, int flags)
- : Name(name)
- , Method(method)
- , Description(descr)
- , Flags(flags)
- {
- }
- operator PyMethodDef() const {
- PyMethodDef cur = {Name.c_str(), Method, Flags, Description.c_str()};
- return cur;
- }
- };
- typedef TSimpleSharedPtr<TVector<TMethodDef>> TMethodDefVecPtr;
- typedef TSimpleSharedPtr<TVector<PyMethodDef>> TPyMethodDefVecPtr;
- TVector<TMethodDefVecPtr> Methods;
- TVector<TPyMethodDefVecPtr> Defs;
- #if PY_MAJOR_VERSION >= 3
- //because the md_name will leak otherwise
- class TPyModuleDefWithName {
- PyModuleDef Def;
- TString Name;
- public:
- explicit TPyModuleDefWithName(TString name, TPyMethodDefVecPtr moduleDefs)
- : Name(std::move(name))
- {
- Def = PyModuleDef{
- PyModuleDef_HEAD_INIT,
- Name.c_str(),
- nullptr,
- -1,
- moduleDefs->data(),
- nullptr, nullptr, nullptr, nullptr
- };
- }
- PyModuleDef* GetDefPtr() {
- return &Def;
- }
- };
- TVector<TSimpleSharedPtr<TPyModuleDefWithName>> ModuleDefs;
- #endif
- template <TModuleMethod method>
- static PyObject* MethodWrapper(PyObject* obj, PyObject* args) {
- try {
- PyObject* res = method(obj, args);
- if (!res && !PyErr_Occurred())
- ythrow yexception() << "\nModule method exited with NULL, but didn't set Error.\n Options:\n -- Return correct value or None;\n -- Set python exception;\n -- Throw c++ exception.";
- return res;
- } catch (const std::exception& ex) {
- PyErr_SetString(TExceptionsHolder::Instance().ToPyException(ex).Get(), ex.what());
- } catch (...) {
- PyErr_SetString(PyExc_RuntimeError, "Unknown error occurred while trying to call module method");
- }
- return nullptr;
- }
- public:
- static TModuleHolder& Instance() {
- static TModuleHolder Holder;
- return Holder;
- }
- void ImportModule(TPyObjectPtr module, const char* const name, TModuleInitFunc initFunc) {
- PyImport_AppendInittab(const_cast<char*>(name), initFunc);
- TPyObjectPtr importedModule(PyImport_ImportModule(name), true);
- PyModule_AddObject(module.Get(), name, importedModule.Get());
- }
- template <TModuleMethod method>
- void AddModuleMethod(const TString& name, const TString& descr = "") {
- Methods.back()->push_back(TMethodDef(name, MethodWrapper<method>, descr, METH_VARARGS));
- }
- TPyObjectPtr InitModule(const TString& name) {
- Defs.push_back(new TVector<PyMethodDef>(Methods.back()->begin(), Methods.back()->end()));
- PyMethodDef blank = {nullptr, nullptr, 0, nullptr};
- Defs.back()->push_back(blank);
- #if PY_MAJOR_VERSION >= 3
- ModuleDefs.push_back(MakeSimpleShared<TPyModuleDefWithName>(name, Defs.back()));
- TPyObjectPtr res(PyModule_Create(ModuleDefs.back()->GetDefPtr()));
- NPrivate::TAtExitRegistrar::Instantiate(res);
- NPrivate::TPyBindModuleRegistrar::Instantiate();
- #else
- TPyObjectPtr res(Py_InitModule(name.c_str(), &(Defs.back()->at(0))));
- #endif
- Methods.push_back(new TVector<TMethodDef>);
- return res;
- }
- };
- template <typename TMethodSignature, TMethodSignature method>
- class TModuleMethodCaller {
- private:
- template <typename TResult, typename... Args>
- struct TCaller {
- static PyObject* Call(PyObject* args) {
- return BuildPyObject(Apply(method, GetArguments<Args...>(args)));
- }
- };
- template <typename TResult, typename... Args>
- static PyObject* InternalCall(TResult (*)(Args...), PyObject* args) {
- return BuildPyObject(Apply(method, GetArguments<Args...>(args)));
- }
- public:
- static PyObject* Call(PyObject*, PyObject* args) {
- if (args && (!PyTuple_Check(args) || PyTuple_Size(args) != TFunctionArgs<TMethodSignature>::Length)) {
- ythrow yexception() << "Method takes " << (size_t)(TFunctionArgs<TMethodSignature>::Length) << " arguments, " << PyTuple_Size(args) << " provided";
- }
- return InternalCall(method, args);
- }
- };
- }
|