24 #ifndef PXR_BASE_TF_PY_FUNCTION_H 25 #define PXR_BASE_TF_PY_FUNCTION_H 30 #include "pxr/base/tf/pyLock.h" 31 #include "pxr/base/tf/pyObjWrapper.h" 34 #include <boost/python/converter/from_python.hpp> 35 #include <boost/python/converter/registered.hpp> 36 #include <boost/python/converter/rvalue_from_python_data.hpp> 37 #include <boost/python/extract.hpp> 38 #include <boost/python/handle.hpp> 39 #include <boost/python/object.hpp> 41 #include <boost/function.hpp> 45 PXR_NAMESPACE_OPEN_SCOPE
48 struct TfPyFunctionFromPython;
50 template <
typename Ret,
typename... Args>
51 struct TfPyFunctionFromPython<Ret (Args...)>
57 Ret operator()(Args... args) {
67 Ret operator()(Args... args) {
68 using namespace boost::python;
71 object callable(handle<>(borrowed(PyWeakref_GetObject(weak.
ptr()))));
73 TF_WARN(
"Tried to call an expired python callback");
84 #if PY_MAJOR_VERSION == 2 88 Ret operator()(Args... args) {
89 using namespace boost::python;
93 PyObject *
self = PyWeakref_GetObject(weakSelf.
ptr());
94 if (
self == Py_None) {
95 TF_WARN(
"Tried to call a method on an expired python instance");
98 #if PY_MAJOR_VERSION == 2 99 object method(handle<>(PyMethod_New(func.
ptr(),
self, cls.
ptr())));
101 object method(handle<>(PyMethod_New(func.
ptr(),
self)));
107 TfPyFunctionFromPython() {
108 RegisterFunctionType<boost::function<Ret (Args...)>>();
109 RegisterFunctionType<std::function<Ret (Args...)>>();
112 template <
typename FuncType>
114 RegisterFunctionType() {
115 using namespace boost::python;
116 converter::registry::
117 insert(&convertible, &construct<FuncType>, type_id<FuncType>());
120 static void *convertible(PyObject *obj) {
121 return ((obj == Py_None) || PyCallable_Check(obj)) ? obj : 0;
124 template <
typename FuncType>
125 static void construct(PyObject *src, boost::python::converter::
126 rvalue_from_python_stage1_data *data) {
128 using namespace boost::python;
130 void *storage = ((converter::rvalue_from_python_storage<FuncType> *)
131 data)->storage.bytes;
133 if (src == Py_None) {
134 new (storage) FuncType();
156 object callable(handle<>(borrowed(src)));
157 PyObject *pyCallable = callable.ptr();
159 PyMethod_Check(pyCallable) ?
160 PyMethod_GET_SELF(pyCallable) : NULL;
165 #if PY_MAJOR_VERSION == 2 166 object cls(handle<>(borrowed(PyMethod_GET_CLASS(pyCallable))));
168 object func(handle<>(borrowed(PyMethod_GET_FUNCTION(
170 object weakSelf(handle<>(PyWeakref_NewRef(
self, NULL)));
175 #if PY_MAJOR_VERSION == 2 180 }
else if (PyObject_HasAttrString(pyCallable,
"__name__") &&
181 extract<string>(callable.attr(
"__name__"))()
187 if (PyObject *weakCallable =
188 PyWeakref_NewRef(pyCallable, NULL)) {
192 object(handle<>(weakCallable)))});
201 data->convertible = storage;
205 PXR_NAMESPACE_CLOSE_SCOPE
207 #endif // PXR_BASE_TF_PY_FUNCTION_H Utilities for calling python callables.
TF_API PyObject * ptr() const
Underlying PyObject* access.
#define TF_WARN(...)
Issue a warning, but continue execution.
Miscellaneous Utilities for dealing with script.
Convenience class for accessing the Python Global Interpreter Lock.
Provide a way to call a Python callable.
Boost Python object wrapper.
TF_API bool TfPyIsNone(boost::python::object const &obj)
Return true iff obj is None.