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>
45PXR_NAMESPACE_OPEN_SCOPE
48struct TfPyFunctionFromPython;
50template <
typename Ret,
typename... Args>
51struct 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");
85 Ret operator()(Args... args) {
86 using namespace boost::python;
90 PyObject *self = PyWeakref_GetObject(weakSelf.
ptr());
91 if (self == Py_None) {
92 TF_WARN(
"Tried to call a method on an expired python instance");
95 object method(handle<>(PyMethod_New(func.
ptr(), self)));
100 TfPyFunctionFromPython() {
101 RegisterFunctionType<boost::function<Ret (Args...)>>();
102 RegisterFunctionType<std::function<Ret (Args...)>>();
105 template <
typename FuncType>
107 RegisterFunctionType() {
108 using namespace boost::python;
109 converter::registry::
110 insert(&convertible, &construct<FuncType>, type_id<FuncType>());
113 static void *convertible(PyObject *obj) {
114 return ((obj == Py_None) || PyCallable_Check(obj)) ? obj : 0;
117 template <
typename FuncType>
118 static void construct(PyObject *src, boost::python::converter::
119 rvalue_from_python_stage1_data *data) {
121 using namespace boost::python;
123 void *storage = ((converter::rvalue_from_python_storage<FuncType> *)
124 data)->storage.bytes;
126 if (src == Py_None) {
127 new (storage) FuncType();
149 object callable(handle<>(borrowed(src)));
150 PyObject *pyCallable = callable.ptr();
152 PyMethod_Check(pyCallable) ?
153 PyMethod_GET_SELF(pyCallable) : NULL;
158 object func(handle<>(borrowed(PyMethod_GET_FUNCTION(
160 object weakSelf(handle<>(PyWeakref_NewRef(self, NULL)));
167 }
else if (PyObject_HasAttrString(pyCallable,
"__name__") &&
168 extract<string>(callable.attr(
"__name__"))()
174 if (PyObject *weakCallable =
175 PyWeakref_NewRef(pyCallable, NULL)) {
179 object(handle<>(weakCallable)))});
188 data->convertible = storage;
192PXR_NAMESPACE_CLOSE_SCOPE
Miscellaneous Utilities for dealing with script.
TF_API bool TfPyIsNone(boost::python::object const &obj)
Return true iff obj is None.
Convenience class for accessing the Python Global Interpreter Lock.
Boost Python object wrapper.
TF_API PyObject * ptr() const
Underlying PyObject* access.
#define TF_WARN(...)
Issue a warning, but continue execution.
Utilities for calling python callables.
Provide a way to call a Python callable.