25#ifndef PXR_BASE_TF_MAKE_PY_CONSTRUCTOR_H
26#define PXR_BASE_TF_MAKE_PY_CONSTRUCTOR_H
33# define TF_MAX_ARITY 7
38#include "pxr/base/tf/api.h"
39#include "pxr/base/tf/functionTraits.h"
43#include "pxr/base/tf/pyError.h"
44#include "pxr/base/tf/pyIdentity.h"
50#include <boost/python/def_visitor.hpp>
51#include <boost/python/dict.hpp>
52#include <boost/python/errors.hpp>
53#include <boost/python/list.hpp>
54#include <boost/python/object/iterator.hpp>
55#include <boost/python/raw_function.hpp>
56#include <boost/python/tuple.hpp>
57#include <boost/python/type_id.hpp>
64PXR_NAMESPACE_OPEN_SCOPE
102namespace Tf_MakePyConstructor {
104namespace bp = boost::python;
106template <
typename CTOR>
107struct InitVisitor : bp::def_visitor<InitVisitor<CTOR> > {
108 friend class bp::def_visitor_access;
109 const std::string _doc;
110 InitVisitor(
const std::string &doc = std::string()) : _doc(doc) {}
112 template <
typename CLS>
113 void visit(CLS &c)
const {
114 c.def(
"__init__", CTOR::template init_callable<CLS>(), _doc.c_str());
117 template <
class CLS,
class Options>
118 void visit(CLS &c,
char const* name, Options& options)
const {
120 c.def(name, CTOR::template init_callable<CLS>(options), _doc.c_str());
126bp::object _DummyInit(bp::tuple
const & ,
129template <
typename CTOR>
130struct NewVisitor : bp::def_visitor<NewVisitor<CTOR> > {
131 friend class bp::def_visitor_access;
132 const std::string _doc;
133 NewVisitor(
const std::string &doc = std::string()) : _doc(doc) {}
135 template <
typename CLS>
136 void visit(CLS &c)
const {
149 if (PyObject_HasAttrString(c.ptr(),
"__new__"))
150 c.attr(
"__new__") = c.attr(
"__new__");
151 c.def(
"__new__", CTOR::template __new__<CLS>, _doc.c_str());
152 c.staticmethod(
"__new__");
155 c.def(
"__init__", bp::raw_function(_DummyInit));
158 template <
class CLS,
class Options>
159 void visit(CLS &c,
char const* name, Options& options)
const {
172 if (PyObject_HasAttrString(c.ptr(),
"__new__"))
173 c.attr(
"__new__") = c.attr(
"__new__");
174 c.def(
"__new__", CTOR::template __new__<CLS>,
180 c.staticmethod(
"__new__");
183 c.def(
"__init__", bp::raw_function(_DummyInit));
189typedef bp::object object;
192struct InstallPolicy {
193 static void PostInstall(
object const &self, T
const &t,
200 static_assert(Tf_SupportsUniqueChanged<T>::Value,
201 "Type T must support refcount unique changed notification.");
202 static void PostInstall(
object const &self,
TfRefPtr<T> const &ptr,
203 const void *uniqueId) {
207 Tf_PyAddPythonOwnership(ptr, uniqueId, self.ptr());
211template <
typename CLS,
typename T>
212void Install(
object const &self, T
const &t,
TfErrorMark const &m) {
215 typedef typename CLS::metadata::holder Holder;
216 typedef typename bp::objects::instance<Holder> instance_t;
217 typedef InstallPolicy<T> Policy;
218 typedef typename CLS::metadata::held_type HeldType;
221 void *memory = Holder::
223 allocate(self.ptr(), offsetof(instance_t, storage),
sizeof(Holder));
226 Holder *holder = (
new (memory) Holder(held));
228 if (TfPyConvertTfErrorsToPythonException(m))
229 bp::throw_error_already_set();
235 bp::detail::initialize_wrapper(self.ptr(), &(*(held.operator->())));
236 holder->install(self.ptr());
239 Tf_PySetPythonIdentity(held, self.ptr());
241 Policy::PostInstall(self, t, held.GetUniqueIdentifier());
244 Holder::deallocate(self.ptr(), memory);
throw;
250template <
typename WeakPtr,
typename P>
251struct _RefPtrFactoryConverter {
252 typedef std::remove_reference_t<P> Ptr;
253 bool convertible()
const {
260 PyObject *operator()(Ptr
const &p)
const {
261 typedef InstallPolicy<Ptr> Policy;
262 WeakPtr ptr(
static_cast<typename WeakPtr::DataType *
>
267 return bp::incref(Py_None);
272 Policy::PostInstall(result, p, ptr.GetUniqueIdentifier());
273 return bp::incref(result.ptr());
277 PyTypeObject
const *get_pytype()
const {
278 return boost::python::objects::registered_class_object(
279 boost::python::type_id<typename WeakPtr::DataType>()).get();
283template <
typename WeakPtr =
void>
284struct RefPtrFactory {
285 template <
typename FactoryResultPtr>
287 using WeakPtrType = std::conditional_t<
288 std::is_same<WeakPtr, void>::value,
291 typedef _RefPtrFactoryConverter<WeakPtrType, FactoryResultPtr> type;
300template <
typename SIG,
size_t EXTRA_ARITY = 0>
303 using Traits = TfFunctionTraits<SIG*>;
304 static_assert(Traits::Arity <= (TF_MAX_ARITY + EXTRA_ARITY));
307 static void SetFunc(Sig *func) {
313 "Duplicate will be ignored.",
320template <
typename SIG,
size_t EXTRA_ARITY>
321SIG *CtorBase<SIG, EXTRA_ARITY>::_func =
nullptr;
323template <
typename SIG>
struct InitCtor;
324template <
typename SIG>
struct InitCtorWithBackReference;
325template <
typename SIG>
struct InitCtorWithVarArgs;
326template <
typename SIG>
struct NewCtor;
327template <
typename SIG>
struct NewCtorWithClassReference;
333Tf_MakePyConstructor::InitVisitor
334<
typename Tf_MakePyConstructor::InitCtor<T> >
335TfMakePyConstructor(T *func,
const std::string &doc = std::string()) {
337 Tf_MakePyConstructor::InitCtor<T> Ctor(func);
338 return Tf_MakePyConstructor::InitVisitor
339 <Tf_MakePyConstructor::InitCtor<T> >(doc);
343Tf_MakePyConstructor::InitVisitor
344<
typename Tf_MakePyConstructor::InitCtorWithBackReference<T> >
345TfMakePyConstructorWithBackReference(T *func,
const std::string &doc = std::string()) {
347 Tf_MakePyConstructor::InitCtorWithBackReference<T> Ctor(func);
348 return Tf_MakePyConstructor::InitVisitor
349 <Tf_MakePyConstructor::InitCtorWithBackReference<T> >(doc);
353Tf_MakePyConstructor::InitVisitor
354<
typename Tf_MakePyConstructor::InitCtorWithVarArgs<T> >
355TfMakePyConstructorWithVarArgs(T *func,
const std::string &doc = std::string()) {
357 Tf_MakePyConstructor::InitCtorWithVarArgs<T> Ctor(func);
358 return Tf_MakePyConstructor::InitVisitor
359 <Tf_MakePyConstructor::InitCtorWithVarArgs<T> >(doc);
363Tf_MakePyConstructor::NewVisitor
364<
typename Tf_MakePyConstructor::NewCtor<T> >
365TfMakePyNew(T *func,
const std::string &doc = std::string()) {
367 Tf_MakePyConstructor::NewCtor<T> Ctor(func);
368 return Tf_MakePyConstructor::NewVisitor
369 <Tf_MakePyConstructor::NewCtor<T> >(doc);
373Tf_MakePyConstructor::NewVisitor
374<
typename Tf_MakePyConstructor::NewCtorWithClassReference<T> >
375TfMakePyNewWithClassReference(T *func,
const std::string &doc = std::string()) {
377 Tf_MakePyConstructor::NewCtorWithClassReference<T> Ctor(func);
378 return Tf_MakePyConstructor::NewVisitor
379 <Tf_MakePyConstructor::NewCtorWithClassReference<T> >(doc);
383template <
typename T =
void>
384struct TfPyRefPtrFactory :
public Tf_MakePyConstructor::RefPtrFactory<T> {};
386template <
typename T>
struct Tf_PySequenceToListConverterRefPtrFactory;
391 template <
typename T>
393 typedef Tf_PySequenceToListConverterRefPtrFactory<T> type;
399struct Tf_PySequenceToListConverterRefPtrFactory {
400 typedef std::remove_reference_t<T> SeqType;
401 bool convertible()
const {
404 PyObject *operator()(T seq)
const {
405 using namespace boost::python;
407 typedef typename Tf_MakePyConstructor::RefPtrFactory<>::
408 apply<typename SeqType::value_type>::type RefPtrFactory;
410 boost::python::list l;
411 for (
typename SeqType::const_iterator i = seq.begin();
412 i != seq.end(); ++i) {
413 l.append(
object(handle<>(RefPtrFactory()(*i))));
415 return boost::python::incref(l.ptr());
419 PyTypeObject
const *get_pytype()
const {
424namespace Tf_MakePyConstructor {
426template <
typename R,
typename... Args>
427struct InitCtor<R(Args...)> : CtorBase<R(Args...)> {
428 typedef CtorBase<R(Args...)> Base;
429 typedef typename Base::Sig Sig;
431 InitCtor(Sig* func) { Base::SetFunc(func); }
433 template <
typename CLS>
434 static bp::object init_callable() {
435 return bp::make_function(__init__<CLS>);
438 template <
typename CLS,
typename Options>
439 static bp::object init_callable(Options& o) {
440 return bp::make_function(__init__<CLS>, o.policies(), o.keywords()) ;
443 template <
typename CLS>
444 static void __init__(
object &self, Args... args) {
446 Install<CLS>(self, Base::_func(args...), m);
450template <
typename R,
typename... Args>
451struct NewCtor<R(Args...)> : CtorBase<R(Args...)> {
452 typedef CtorBase<R(Args...)> Base;
453 typedef typename Base::Sig Sig;
454 NewCtor(Sig *func) { Base::SetFunc(func); }
457 static bp::object __new__(
object &cls, Args... args) {
458 typedef typename CLS::metadata::held_type HeldType;
460 R r((Base::_func(args...)));
462 if (TfPyConvertTfErrorsToPythonException(m))
463 bp::throw_error_already_set();
469 bp::detail::initialize_wrapper(ret.ptr(), get_pointer(h));
471 bp::setattr(ret,
"__class__", cls);
473 InstallPolicy<R>::PostInstall(ret, r, h.GetUniqueIdentifier());
478template <
typename R,
typename... Args>
479struct InitCtorWithVarArgs<R(Args...)> :
481 CtorBase<R(Args...), 2> {
482 typedef CtorBase<R(Args...), 2> Base;
483 typedef typename Base::Sig Sig;
488 using Arity = TfMetaLength<Args...>;
490 InitCtorWithVarArgs(Sig *func) { Base::SetFunc(func); }
492 static_assert((Arity::value >= 2) &&
495 typename Base::Traits::template NthArg<(Arity::value-2)>>) &&
498 typename Base::Traits::template NthArg<(Arity::value-1)>>),
499 "InitCtorWithVarArgs requires a function of form "
500 "(..., const tuple&, const dict&)");
502 template <
typename CLS>
503 static bp::object init_callable() {
507 return bp::raw_function(__init__<CLS>, 1);
510 template <
typename CLS,
typename Options>
511 static bp::object init_callable(Options& options) {
514 return bp::raw_function(
515 bp::make_function(__init__<CLS>, options.policies()),
519 template <
typename CLS,
size_t... I>
520 static bp::object __init__impl(
const bp::tuple& args,
521 const bp::dict& kwargs,
522 std::index_sequence<I...>) {
527 const unsigned int expectedNamedArgs = Arity::value - 2;
529 const unsigned int positionalArgs = bp::len(args) - 1;
530 if (positionalArgs < expectedNamedArgs) {
531 std::array<std::string, Arity::value - 2>
532 positionalArgTypes = {{
533 (bp::type_id<typename Base::Traits::template NthArg<I>>().name())...
536 std::begin(positionalArgTypes),
537 std::end(positionalArgTypes),
", "
539 if (!joinedTypes.empty()) {
546 "Arguments to __init__ did not match C++ signature:\n"
547 "\t__init__(%s...)", joinedTypes.c_str()
558 std::remove_reference_t<
559 typename Base::Traits::template NthArg<I>>>(args[I + 1])...,
560 bp::tuple(args.slice(expectedNamedArgs + 1, bp::len(args))), kwargs),
566 template <
typename CLS>
567 static bp::object __init__(
const bp::tuple& args,
568 const bp::dict& kwargs) {
569 return __init__impl<CLS>(
570 args, kwargs, std::make_index_sequence<Arity::value - 2>());
580template <
typename R,
typename SelfRef,
typename... Args>
581struct InitCtorWithBackReference<R(SelfRef, Args...)> :
582 CtorBase<R(SelfRef, Args...)> {
583 typedef CtorBase<R(SelfRef, Args...)> Base;
584 typedef typename Base::Sig Sig;
585 InitCtorWithBackReference(Sig *func) { Base::SetFunc(func); }
587 template <
typename CLS>
588 static bp::object init_callable() {
589 return bp::make_function(__init__<CLS>);
592 template <
typename CLS,
typename Options>
593 static bp::object init_callable(Options& o) {
594 return bp::make_function(__init__<CLS>, o.policies(), o.keywords());
597 template <
typename CLS>
598 static void __init__(SelfRef self, Args... args) {
600 Install<CLS>(self, Base::_func(self, args...), m);
604template <
typename R,
typename ClsRef,
typename... Args>
605struct NewCtorWithClassReference<R(ClsRef, Args...)> :
606 CtorBase<R(ClsRef, Args...)> {
607 typedef CtorBase<R(ClsRef, Args...)> Base;
608 typedef typename Base::Sig Sig;
609 NewCtorWithClassReference(Sig *func) { Base::SetFunc(func); }
612 static bp::object __new__(ClsRef cls, Args... args) {
613 typedef typename CLS::metadata::held_type HeldType;
615 R r(Base::_func(cls, args...));
617 if (TfPyConvertTfErrorsToPythonException(m))
618 bp::throw_error_already_set();
624 bp::detail::initialize_wrapper(ret.ptr(), get_pointer(h));
626 bp::setattr(ret,
"__class__", cls);
628 InstallPolicy<R>::PostInstall(ret, r, h.GetUniqueIdentifier());
634PXR_NAMESPACE_CLOSE_SCOPE
Low-level utilities for informing users of various internal and external diagnostic conditions.
Miscellaneous Utilities for dealing with script.
TF_API void TfPyThrowRuntimeError(const char *msg)
Raises a Python RuntimeError with the given error msg and throws a boost::python::error_already_set e...
TF_API bool TfPyIsNone(boost::python::object const &obj)
Return true iff obj is None.
boost::python::object TfPyObject(T const &t, bool complainOnFailure=true)
Return a python object for the given C++ object, loading the appropriate wrapper code if necessary.
TF_API void TfPyThrowTypeError(const char *msg)
Raises a Python TypeError with the given error msg and throws a boost::python::error_already_set exce...
Class used to record the end of the error-list.
Reference-counted smart pointer utility class.
Pointer storage with deletion detection.
Demangle C++ typenames generated by the typeid() facility.
std::string ArchGetDemangled()
Return demangled RTTI generated-type name.
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
std::string TfStringJoin(ForwardIterator begin, ForwardIterator end, const char *separator=" ")
Concatenates the strings (begin, end), with default separator.
TF_API std::string TfStringPrintf(const char *fmt,...)
Returns a string formed by a printf()-like specification.
A boost::python result converter generator which converts standard library sequences to lists of pyth...
Definitions of basic string utilities in tf.
Pointer storage with deletion detection.