MeshLib C++ Docs
Loading...
Searching...
No Matches
MRPython.h
Go to the documentation of this file.
1#pragma once
2
11#include "exports.h"
12#include "MRPybind11.h"
13
14#include "MRMesh/MRExpected.h"
15#include "MRMesh/MRMacros.h"
16#include <functional>
17#include <filesystem>
18#include <unordered_map>
19
20#define MR_INIT_PYTHON_MODULE( moduleName ) MR_INIT_PYTHON_MODULE_PRECALL( moduleName, [](){} )
21
22#define MR_INIT_PYTHON_MODULE_PRECALL( moduleName, precall )\
23PYBIND11_MODULE( moduleName, m )\
24{\
25 precall();\
26 auto& adders = MR::PythonExport::instance().functions( #moduleName );\
27 for ( auto& fs : adders )\
28 for ( auto& f : fs )\
29 f( m );\
30}\
31static MR::PythonFunctionAdder moduleName##_init_( #moduleName, &PyInit_##moduleName );
32
33#define MR_ADD_PYTHON_FUNCTION( moduleName , name , func , description ) \
34 static MR::PythonFunctionAdder MR_CONCAT3(name, _adder_, __LINE__)( #moduleName, [](pybind11::module_& m){ m.def(#name, func, description);} );
35
36#define MR_ADD_PYTHON_CUSTOM_DEF( moduleName , name , ... ) \
37_Pragma("warning(push)") \
38_Pragma("warning(disable:4459)") \
39 static MR::PythonFunctionAdder name##_adder_( #moduleName, __VA_ARGS__ ); \
40_Pragma("warning(pop)")
41
43#define _MR_PYTHON_CUSTOM_CLASS_HOLDER_NAME( name ) name##_class_
44
47#define MR_PYTHON_CUSTOM_CLASS( name ) ( *_MR_PYTHON_CUSTOM_CLASS_HOLDER_NAME( name ) )
48
51#define MR_ADD_PYTHON_CUSTOM_CLASS_DECL( moduleName, name, ... ) \
52static std::optional<pybind11::class_<__VA_ARGS__>> _MR_PYTHON_CUSTOM_CLASS_HOLDER_NAME( name );
53
56#define MR_ADD_PYTHON_CUSTOM_CLASS_INST( moduleName, name ) \
57MR_ADD_PYTHON_CUSTOM_DEF( moduleName, name##_inst_, [] ( pybind11::module_& module ) \
58{ \
59 _MR_PYTHON_CUSTOM_CLASS_HOLDER_NAME( name ).emplace( module, #name ); \
60}, MR::PythonExport::Priority::Declaration )
61
67#define MR_ADD_PYTHON_CUSTOM_CLASS_INST_FUNC( moduleName, name, ... ) \
68MR_ADD_PYTHON_CUSTOM_DEF( moduleName, name##_inst_, [] ( pybind11::module_& module ) \
69{ \
70 _MR_PYTHON_CUSTOM_CLASS_HOLDER_NAME( name ) = __VA_ARGS__ ( module ); \
71}, MR::PythonExport::Priority::Declaration )
72
93#define MR_ADD_PYTHON_CUSTOM_CLASS( moduleName, name, ... ) \
94MR_ADD_PYTHON_CUSTOM_CLASS_DECL( moduleName, name, __VA_ARGS__ ) \
95MR_ADD_PYTHON_CUSTOM_CLASS_INST( moduleName, name )
96
97#define MR_ADD_PYTHON_VEC( moduleName, name, type) \
98PYBIND11_MAKE_OPAQUE( std::vector<type> ) \
99MR_ADD_PYTHON_CUSTOM_CLASS_DECL( moduleName, name, std::vector<type>, std::unique_ptr<std::vector<type>> ) \
100MR_ADD_PYTHON_CUSTOM_CLASS_INST_FUNC( moduleName, name, [] ( pybind11::module_& module ) { return pybind11::bind_vector<std::vector<type>>( module, #name, pybind11::module_local(false) ); } ) \
101MR_ADD_PYTHON_CUSTOM_DEF( moduleName, name, [] ( pybind11::module_& ) \
102{\
103 using vecType = std::vector<type>;\
104 MR_PYTHON_CUSTOM_CLASS( name ).\
105 def( pybind11::init<>() ).\
106 def( pybind11::init<size_t>(), pybind11::arg( "size" ) ).\
107 def( "empty", &vecType::empty ).\
108 def( "size", &vecType::size ).\
109 def( "resize", ( void ( vecType::* )( const vecType::size_type ) )& vecType::resize ).\
110 def( "clear", &vecType::clear ); \
111} )
112
113#define MR_ADD_PYTHON_MAP( moduleName, name, mapType ) \
114PYBIND11_MAKE_OPAQUE( mapType ) \
115MR_ADD_PYTHON_CUSTOM_CLASS_DECL( moduleName, name, mapType, std::unique_ptr<mapType> ) \
116MR_ADD_PYTHON_CUSTOM_CLASS_INST_FUNC( moduleName, name, [] ( pybind11::module_& module ) { return pybind11::bind_map<mapType>( module, #name, pybind11::module_local(false) ); } ) \
117MR_ADD_PYTHON_CUSTOM_DEF( moduleName, name, [] ( pybind11::module_& ) \
118{\
119 MR_PYTHON_CUSTOM_CLASS( name ).\
120 def( pybind11::init<>() ).\
121 def( "size", &mapType::size );\
122} )
123
124#define MR_ADD_PYTHON_EXPECTED( moduleName, name, type, errorType ) \
125using name##_expected_type_ = MR::Expected<type, errorType>; \
126MR_ADD_PYTHON_CUSTOM_CLASS( moduleName, name, name##_expected_type_ ) \
127MR_ADD_PYTHON_CUSTOM_DEF( moduleName, name, [] ( pybind11::module_& ) \
128{\
129 using expectedType = Expected<type,errorType>;\
130 MR_PYTHON_CUSTOM_CLASS( name ).\
131 def( "has_value", []() \
132 { PyErr_WarnEx(PyExc_DeprecationWarning, ".has_value is deprecated. Please use 'try - except ValueError'", 1); \
133 return &expectedType::has_value; \
134 }).\
135 def( "value", []() \
136 { \
137 PyErr_WarnEx(PyExc_DeprecationWarning, ".value is deprecated. Please use 'try - except ValueError'", 1); \
138 return ( type& ( expectedType::* )( )& )& expectedType::value; \
139 }, pybind11::return_value_policy::reference_internal ).\
140 def( "error", []() \
141 { \
142 PyErr_WarnEx(PyExc_DeprecationWarning, ".error is deprecated. Please use 'try - except ValueError'", 1); \
143 return ( const errorType& ( expectedType::* )( )const& )& expectedType::error; \
144 } );\
145} )
146
147
153
154template<StreamType T>
156{
157public:
158 MRPYTHON_API void write( const std::string& text );
159 MRPYTHON_API void flush();
160 MRPYTHON_API static int getNumWritten();
161};
162
165
166namespace MR
167{
170
171
173{
174public:
175 MRPYTHON_API static PythonExport& instance();
176
177 using PythonRegisterFuncton = std::function<void( pybind11::module_& m )>;
178
179 enum class Priority
180 {
183 Count,
184 };
185
187 {
188 PyObject* ( *initFncPointer )( void );
189 std::array<std::vector<PythonRegisterFuncton>, size_t( Priority::Count )> functions;
190 };
191
192 void addFunc( const std::string& moduleName, PythonRegisterFuncton func, Priority priority )
193 {
194 auto& mod = moduleData_[moduleName];
195 mod.functions[size_t( priority )].push_back( func );
196 }
197 void setInitFuncPtr( const std::string& moduleName, PyObject* ( *initFncPointer )( void ) )
198 {
199 auto& mod = moduleData_[moduleName];
200 mod.initFncPointer = initFncPointer;
201 }
202 const std::array<std::vector<PythonRegisterFuncton>, size_t( Priority::Count )>& functions( const std::string& moduleName ) const
203 {
204 auto it = moduleData_.find( moduleName );
205 const static std::array<std::vector<PythonRegisterFuncton>, size_t( Priority::Count )> empty;
206 if ( it == moduleData_.end() )
207 return empty;
208 return it->second.functions;
209 }
210
211 const std::unordered_map<std::string, ModuleData>& modules() const
212 {
213 return moduleData_;
214 }
215private:
216 PythonExport() = default;
217 ~PythonExport() = default;
218
219 std::unordered_map<std::string, ModuleData> moduleData_;
220};
221
223{
224 MRPYTHON_API PythonFunctionAdder( const std::string& moduleName, std::function<void( pybind11::module_& m )> func, PythonExport::Priority priority = PythonExport::Priority::Implementation );
225 MRPYTHON_API PythonFunctionAdder( const std::string& moduleName, PyObject* ( *initFncPointer )( void ) );
226};
227
229template<typename E>
230[[noreturn]] void throwExceptionFromExpected(const E& err)
231{
232 if constexpr (std::is_nothrow_convertible<E, std::string>::value)
233 throw std::runtime_error(err);
234 else
235 throw std::runtime_error(toString(err));
236}
237
239template <typename T>
240[[nodiscard]] decltype(auto) expectedValueOrThrow( T&& e )
241{
242 if ( e )
243 {
244 if constexpr ( std::is_void_v<typename std::remove_cvref_t<T>::value_type> )
245 return;
246 else
247 return *std::forward<T>( e );
248 }
249 else
250 {
251 throwExceptionFromExpected( e.error() );
252 }
253}
254
255template<typename R, typename E, typename... Args>
256auto decorateExpected( std::function<Expected<R, E>( Args... )>&& f ) -> std::function<R( Args... )>
257{
258 return[fLocal = std::move( f )]( Args&&... args ) mutable -> R
259 {
260 auto res = fLocal(std::forward<Args>( args )...);
261 if (!res.has_value())
262 throwExceptionFromExpected(res.error());
263
264 if constexpr (std::is_void<R>::value)
265 return;
266 else
267 return res.value();
268 };
269}
270
271template<typename F>
272auto decorateExpected( F&& f )
273{
274 return decorateExpected( std::function( std::forward<F>( f ) ) );
275}
276
277template<typename R, typename T, typename... Args>
278auto decorateExpected( R( T::* memFunction )( Args... ) )
279{
280 return decorateExpected( std::function<R( T*, Args... )>( std::mem_fn( memFunction ) ) );
281}
282
283}
StreamType
Definition MRPython.h:149
@ Stderr
Definition MRPython.h:151
@ Stdout
Definition MRPython.h:150
Definition MRPython.h:173
Definition MRPython.h:156
static MRPYTHON_API int getNumWritten()
MRPYTHON_API void flush()
MRPYTHON_API void write(const std::string &text)
std::function< void(pybind11::module_ &m)> PythonRegisterFuncton
Definition MRPython.h:177
std::array< std::vector< PythonRegisterFuncton >, size_t(Priority::Count)> functions
Definition MRPython.h:189
void setInitFuncPtr(const std::string &moduleName, PyObject *(*initFncPointer)(void))
Definition MRPython.h:197
const std::array< std::vector< PythonRegisterFuncton >, size_t(Priority::Count)> & functions(const std::string &moduleName) const
Definition MRPython.h:202
Priority
Definition MRPython.h:180
MRPYTHON_API PythonFunctionAdder(const std::string &moduleName, PyObject *(*initFncPointer)(void))
void throwExceptionFromExpected(const E &err)
overload toString functoion to throw exception from custom Expected::error type
Definition MRPython.h:230
MRPYTHON_API PythonFunctionAdder(const std::string &moduleName, std::function< void(pybind11::module_ &m)> func, PythonExport::Priority priority=PythonExport::Priority::Implementation)
void addFunc(const std::string &moduleName, PythonRegisterFuncton func, Priority priority)
Definition MRPython.h:192
const std::unordered_map< std::string, ModuleData > & modules() const
Definition MRPython.h:211
tl::expected< T, E > Expected
Definition MRExpected.h:31
auto decorateExpected(std::function< Expected< R, E >(Args...)> &&f) -> std::function< R(Args...)>
Definition MRPython.h:256
static MRPYTHON_API PythonExport & instance()
decltype(auto) expectedValueOrThrow(T &&e)
Like e.value(), but throws using throwExceptionFromExpected (which is better, because it allows Pytho...
Definition MRPython.h:240
MRMESH_API std::string_view toString(DimensionsVisualizePropertyType value)
only for bindings generation
Definition MRCameraOrientationPlugin.h:8
Definition MRPython.h:187
Definition MRPython.h:223