MeshLib Documentation
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 <functional>
16#include <filesystem>
17#include <unordered_map>
18
19#define MR_INIT_PYTHON_MODULE( moduleName ) MR_INIT_PYTHON_MODULE_PRECALL( moduleName, [](){} )
20
21#define MR_INIT_PYTHON_MODULE_PRECALL( moduleName, precall )\
22PYBIND11_MODULE( moduleName, m )\
23{\
24 precall();\
25 auto& adders = MR::PythonExport::instance().functions( #moduleName );\
26 for ( auto& fs : adders )\
27 for ( auto& f : fs )\
28 f( m );\
29}\
30static MR::PythonFunctionAdder moduleName##_init_( #moduleName, &PyInit_##moduleName );
31
32#define MR_ADD_PYTHON_FUNCTION( moduleName , name , func , description ) \
33 static MR::PythonFunctionAdder name##_adder_( #moduleName, [](pybind11::module_& m){ m.def(#name, func, description);} );
34
35#define MR_ADD_PYTHON_CUSTOM_DEF( moduleName , name , ... ) \
36_Pragma("warning(push)") \
37_Pragma("warning(disable:4459)") \
38 static MR::PythonFunctionAdder name##_adder_( #moduleName, __VA_ARGS__ ); \
39_Pragma("warning(pop)")
40
42#define _MR_PYTHON_CUSTOM_CLASS_HOLDER_NAME( name ) name##_class_
43
46#define MR_PYTHON_CUSTOM_CLASS( name ) ( *_MR_PYTHON_CUSTOM_CLASS_HOLDER_NAME( name ) )
47
50#define MR_ADD_PYTHON_CUSTOM_CLASS_DECL( moduleName, name, ... ) \
51static std::optional<pybind11::class_<__VA_ARGS__>> _MR_PYTHON_CUSTOM_CLASS_HOLDER_NAME( name );
52
55#define MR_ADD_PYTHON_CUSTOM_CLASS_INST( moduleName, name ) \
56MR_ADD_PYTHON_CUSTOM_DEF( moduleName, name##_inst_, [] ( pybind11::module_& module ) \
57{ \
58 _MR_PYTHON_CUSTOM_CLASS_HOLDER_NAME( name ).emplace( module, #name ); \
59}, MR::PythonExport::Priority::Declaration )
60
66#define MR_ADD_PYTHON_CUSTOM_CLASS_INST_FUNC( moduleName, name, ... ) \
67MR_ADD_PYTHON_CUSTOM_DEF( moduleName, name##_inst_, [] ( pybind11::module_& module ) \
68{ \
69 _MR_PYTHON_CUSTOM_CLASS_HOLDER_NAME( name ) = __VA_ARGS__ ( module ); \
70}, MR::PythonExport::Priority::Declaration )
71
92#define MR_ADD_PYTHON_CUSTOM_CLASS( moduleName, name, ... ) \
93MR_ADD_PYTHON_CUSTOM_CLASS_DECL( moduleName, name, __VA_ARGS__ ) \
94MR_ADD_PYTHON_CUSTOM_CLASS_INST( moduleName, name )
95
96#define MR_ADD_PYTHON_VEC( moduleName, name, type) \
97PYBIND11_MAKE_OPAQUE( std::vector<type> ) \
98MR_ADD_PYTHON_CUSTOM_CLASS_DECL( moduleName, name, std::vector<type>, std::unique_ptr<std::vector<type>> ) \
99MR_ADD_PYTHON_CUSTOM_CLASS_INST_FUNC( moduleName, name, [] ( pybind11::module_& module ) { return pybind11::bind_vector<std::vector<type>>( module, #name, pybind11::module_local(false) ); } ) \
100MR_ADD_PYTHON_CUSTOM_DEF( moduleName, name, [] ( pybind11::module_& ) \
101{\
102 using vecType = std::vector<type>;\
103 MR_PYTHON_CUSTOM_CLASS( name ).\
104 def( pybind11::init<>() ).\
105 def( pybind11::init<size_t>(), pybind11::arg( "size" ) ).\
106 def( "empty", &vecType::empty ).\
107 def( "size", &vecType::size ).\
108 def( "resize", ( void ( vecType::* )( const vecType::size_type ) )& vecType::resize ).\
109 def( "clear", &vecType::clear ); \
110} )
111
112#define MR_ADD_PYTHON_MAP( moduleName, name, mapType ) \
113PYBIND11_MAKE_OPAQUE( mapType ) \
114MR_ADD_PYTHON_CUSTOM_CLASS_DECL( moduleName, name, mapType, std::unique_ptr<mapType> ) \
115MR_ADD_PYTHON_CUSTOM_CLASS_INST_FUNC( moduleName, name, [] ( pybind11::module_& module ) { return pybind11::bind_map<mapType>( module, #name, pybind11::module_local(false) ); } ) \
116MR_ADD_PYTHON_CUSTOM_DEF( moduleName, name, [] ( pybind11::module_& ) \
117{\
118 MR_PYTHON_CUSTOM_CLASS( name ).\
119 def( pybind11::init<>() ).\
120 def( "size", &mapType::size );\
121} )
122
123#define MR_ADD_PYTHON_EXPECTED( moduleName, name, type, errorType ) \
124using name##_expected_type_ = MR::Expected<type, errorType>; \
125MR_ADD_PYTHON_CUSTOM_CLASS( moduleName, name, name##_expected_type_ ) \
126MR_ADD_PYTHON_CUSTOM_DEF( moduleName, name, [] ( pybind11::module_& ) \
127{\
128 using expectedType = Expected<type,errorType>;\
129 MR_PYTHON_CUSTOM_CLASS( name ).\
130 def( "has_value", []() \
131 { PyErr_WarnEx(PyExc_DeprecationWarning, ".has_value is deprecated. Please use 'try - except ValueError'", 1); \
132 return &expectedType::has_value; \
133 }).\
134 def( "value", []() \
135 { \
136 PyErr_WarnEx(PyExc_DeprecationWarning, ".value is deprecated. Please use 'try - except ValueError'", 1); \
137 return ( type& ( expectedType::* )( )& )& expectedType::value; \
138 }, pybind11::return_value_policy::reference_internal ).\
139 def( "error", []() \
140 { \
141 PyErr_WarnEx(PyExc_DeprecationWarning, ".error is deprecated. Please use 'try - except ValueError'", 1); \
142 return ( const errorType& ( expectedType::* )( )const& )& expectedType::error; \
143 } );\
144} )
145
146
152
153template<StreamType T>
155{
156public:
157 MRPYTHON_API void write( const std::string& text );
158 MRPYTHON_API void flush();
159 MRPYTHON_API static int getNumWritten();
160};
161
164
165namespace MR
166{
167
169{
170public:
171 MRPYTHON_API static PythonExport& instance();
172
173 using PythonRegisterFuncton = std::function<void( pybind11::module_& m )>;
174
175 enum class Priority
176 {
179 Count,
180 };
181
183 {
184 PyObject* ( *initFncPointer )( void );
185 std::array<std::vector<PythonRegisterFuncton>, size_t( Priority::Count )> functions;
186 };
187
188 void addFunc( const std::string& moduleName, PythonRegisterFuncton func, Priority priority )
189 {
190 auto& mod = moduleData_[moduleName];
191 mod.functions[size_t( priority )].push_back( func );
192 }
193 void setInitFuncPtr( const std::string& moduleName, PyObject* ( *initFncPointer )( void ) )
194 {
195 auto& mod = moduleData_[moduleName];
196 mod.initFncPointer = initFncPointer;
197 }
198 const std::array<std::vector<PythonRegisterFuncton>, size_t( Priority::Count )>& functions( const std::string& moduleName ) const
199 {
200 auto it = moduleData_.find( moduleName );
201 const static std::array<std::vector<PythonRegisterFuncton>, size_t( Priority::Count )> empty;
202 if ( it == moduleData_.end() )
203 return empty;
204 return it->second.functions;
205 }
206
207 const std::unordered_map<std::string, ModuleData>& modules() const
208 {
209 return moduleData_;
210 }
211private:
212 PythonExport() = default;
213 ~PythonExport() = default;
214
215 std::unordered_map<std::string, ModuleData> moduleData_;
216};
217
219{
220 MRPYTHON_API PythonFunctionAdder( const std::string& moduleName, std::function<void( pybind11::module_& m )> func, PythonExport::Priority priority = PythonExport::Priority::Implementation );
221 MRPYTHON_API PythonFunctionAdder( const std::string& moduleName, PyObject* ( *initFncPointer )( void ) );
222};
223
224// overload `toString` functoion to throw exception from custom `Expected::error` type
225template<typename E>
227{
228 if constexpr (std::is_nothrow_convertible<E, std::string>::value)
229 throw std::runtime_error(err);
230 else
231 throw std::runtime_error(toString(err));
232}
233
234template<typename R, typename E, typename... Args>
235auto decorateExpected( std::function<Expected<R, E>( Args... )>&& f ) -> std::function<R( Args... )>
236{
237 return[fLocal = std::move( f )]( Args&&... args ) mutable -> R
238 {
239 auto res = fLocal(std::forward<Args>( args )...);
240 if (!res.has_value())
241 throwExceptionFromExpected(res.error());
242
243 if constexpr (std::is_void<R>::value)
244 return;
245 else
246 return res.value();
247 };
248}
249
250template<typename F>
251auto decorateExpected( F&& f )
252{
253 return decorateExpected( std::function( std::forward<F>( f ) ) );
254}
255
256template<typename R, typename T, typename... Args>
257auto decorateExpected( R( T::* memFunction )( Args... ) )
258{
259 return decorateExpected( std::function<R( T*, Args... )>( std::mem_fn( memFunction ) ) );
260}
261
262}
StreamType
Definition MRPython.h:148
@ Stderr
Definition MRPython.h:150
@ Stdout
Definition MRPython.h:149
Definition MRPython.h:169
std::function< void(pybind11::module_ &m)> PythonRegisterFuncton
Definition MRPython.h:173
void setInitFuncPtr(const std::string &moduleName, PyObject *(*initFncPointer)(void))
Definition MRPython.h:193
const std::array< std::vector< PythonRegisterFuncton >, size_t(Priority::Count)> & functions(const std::string &moduleName) const
Definition MRPython.h:198
Priority
Definition MRPython.h:176
void addFunc(const std::string &moduleName, PythonRegisterFuncton func, Priority priority)
Definition MRPython.h:188
const std::unordered_map< std::string, ModuleData > & modules() const
Definition MRPython.h:207
static MRPYTHON_API PythonExport & instance()
Definition MRPython.h:155
static MRPYTHON_API int getNumWritten()
MRPYTHON_API void flush()
MRPYTHON_API void write(const std::string &text)
Definition MRCameraOrientationPlugin.h:8
void throwExceptionFromExpected(const E &err)
Definition MRPython.h:226
tl::expected< T, E > Expected
Definition MRExpected.h:58
auto decorateExpected(std::function< Expected< R, E >(Args...)> &&f) -> std::function< R(Args...)>
Definition MRPython.h:235
MRMESH_API std::string_view toString(DimensionsVisualizePropertyType value)
Definition MRPython.h:183
std::array< std::vector< PythonRegisterFuncton >, size_t(Priority::Count)> functions
Definition MRPython.h:185
Definition MRPython.h:219
MRPYTHON_API PythonFunctionAdder(const std::string &moduleName, PyObject *(*initFncPointer)(void))
MRPYTHON_API PythonFunctionAdder(const std::string &moduleName, std::function< void(pybind11::module_ &m)> func, PythonExport::Priority priority=PythonExport::Priority::Implementation)