25 #if !BOOST_PP_IS_ITERATING
27 #ifndef PXR_BASE_TF_MAKE_PY_CONSTRUCTOR_H
28 #define PXR_BASE_TF_MAKE_PY_CONSTRUCTOR_H
35 # define TF_MAX_ARITY 7
36 #endif // TF_MAX_ARITY
43 #include "pxr/base/tf/pyError.h"
44 #include "pxr/base/tf/pyIdentity.h"
50 #include <boost/preprocessor/iterate.hpp>
51 #include <boost/preprocessor/punctuation/comma_if.hpp>
52 #include <boost/preprocessor/repetition/enum.hpp>
53 #include <boost/preprocessor/repetition/enum_binary_params.hpp>
54 #include <boost/preprocessor/repetition/enum_params.hpp>
55 #include <boost/preprocessor/repetition/enum_trailing_binary_params.hpp>
56 #include <boost/preprocessor/repetition/enum_trailing_params.hpp>
57 #include <boost/preprocessor/repetition/repeat.hpp>
58 #include <boost/preprocessor/seq/for_each.hpp>
59 #include <boost/python/def_visitor.hpp>
60 #include <boost/python/dict.hpp>
61 #include <boost/python/errors.hpp>
62 #include <boost/python/list.hpp>
63 #include <boost/python/object/iterator.hpp>
64 #include <boost/python/raw_function.hpp>
65 #include <boost/python/tuple.hpp>
66 #include <boost/python/type_id.hpp>
67 #include <boost/type_traits/is_same.hpp>
68 #include <boost/type_traits/remove_reference.hpp>
72 PXR_NAMESPACE_OPEN_SCOPE
110 namespace Tf_MakePyConstructor {
112 namespace bp = boost::python;
114 template <
typename CTOR>
115 struct InitVisitor : bp::def_visitor<InitVisitor<CTOR> > {
116 friend class bp::def_visitor_access;
117 const std::string _doc;
118 InitVisitor(
const std::string &doc = std::string()) : _doc(doc) {}
120 template <
typename CLS>
121 void visit(CLS &c)
const {
122 c.def(
"__init__", CTOR::template init_callable<CLS>(), _doc.c_str());
125 template <
class CLS,
class Options>
126 void visit(CLS &c,
char const* name, Options& options)
const {
128 c.def(name, CTOR::template init_callable<CLS>(options), _doc.c_str());
133 bp::object _DummyInit(bp::tuple
const & ,
136 template <
typename CTOR>
137 struct NewVisitor : bp::def_visitor<NewVisitor<CTOR> > {
138 friend class bp::def_visitor_access;
139 const std::string _doc;
140 NewVisitor(
const std::string &doc = std::string()) : _doc(doc) {}
142 template <
typename CLS>
143 void visit(CLS &c)
const {
156 if (PyObject_HasAttrString(c.ptr(),
"__new__"))
157 c.attr(
"__new__") = c.attr(
"__new__");
158 c.def(
"__new__", CTOR::template __new__<CLS>, _doc.c_str());
159 c.staticmethod(
"__new__");
162 c.def(
"__init__", bp::raw_function(_DummyInit));
165 template <
class CLS,
class Options>
166 void visit(CLS &c,
char const* name, Options& options)
const {
179 if (PyObject_HasAttrString(c.ptr(),
"__new__"))
180 c.attr(
"__new__") = c.attr(
"__new__");
181 c.def(
"__new__", CTOR::template __new__<CLS>,
187 c.staticmethod(
"__new__");
190 c.def(
"__init__", bp::raw_function(_DummyInit));
196 typedef bp::object object;
198 template <
typename T>
199 struct InstallPolicy {
200 static void PostInstall(
object const &
self, T
const &t,
205 template <
typename T>
206 struct InstallPolicy<
TfRefPtr<T> > {
207 static_assert(Tf_SupportsUniqueChanged<T>::Value,
208 "Type T must support refcount unique changed notification.");
209 static void PostInstall(
object const &
self,
TfRefPtr<T> const &ptr,
210 const void *uniqueId) {
214 Tf_PyAddPythonOwnership(ptr, uniqueId,
self.ptr());
218 template <
typename CLS,
typename T>
219 void Install(
object const &
self, T
const &t,
TfErrorMark const &m) {
222 typedef typename CLS::metadata::holder Holder;
223 typedef typename bp::objects::instance<Holder> instance_t;
224 typedef InstallPolicy<T> Policy;
225 typedef typename CLS::metadata::held_type HeldType;
228 void *memory = Holder::
230 allocate(
self.ptr(), offsetof(instance_t, storage),
sizeof(Holder));
233 Holder *holder = (
new (memory) Holder(held));
235 if (TfPyConvertTfErrorsToPythonException(m))
236 bp::throw_error_already_set();
242 bp::detail::initialize_wrapper(
self.ptr(), &(*(held.operator->())));
243 holder->install(
self.ptr());
246 Tf_PySetPythonIdentity(held,
self.ptr());
248 Policy::PostInstall(
self, t, held.GetUniqueIdentifier());
251 Holder::deallocate(
self.ptr(), memory);
throw;
257 template <
typename WeakPtr,
typename P>
258 struct _RefPtrFactoryConverter {
259 typedef typename boost::remove_reference<P>::type Ptr;
260 bool convertible()
const {
267 PyObject *operator()(Ptr
const &p)
const {
268 typedef InstallPolicy<Ptr> Policy;
269 WeakPtr ptr(static_cast<typename WeakPtr::DataType *>
274 return bp::incref(Py_None);
279 Policy::PostInstall(result, p, ptr.GetUniqueIdentifier());
280 return bp::incref(result.ptr());
284 PyTypeObject
const *get_pytype()
const {
285 return boost::python::objects::registered_class_object(
286 boost::python::type_id<typename WeakPtr::DataType>()).get();
290 template <
typename WeakPtr =
void>
291 struct RefPtrFactory {
292 template <
typename FactoryResultPtr>
294 typedef typename boost::mpl::if_<boost::is_same<WeakPtr, void>,
296 WeakPtr>::type WeakPtrType;
297 typedef _RefPtrFactoryConverter<WeakPtrType, FactoryResultPtr> type;
301 template <
typename SIG>
305 static void SetFunc(Sig *func) {
311 "Duplicate will be ignored.",
318 template <
typename SIG> SIG *CtorBase<SIG>::_func = 0;
322 template <
typename SIG>
struct InitCtor;
323 template <
typename SIG>
struct InitCtorWithBackReference;
324 template <
typename SIG>
struct InitCtorWithVarArgs;
325 template <
typename SIG>
struct NewCtor;
326 template <
typename SIG>
struct NewCtorWithClassReference;
327 #define BOOST_PP_ITERATION_LIMITS (0, TF_MAX_ARITY)
328 #define BOOST_PP_FILENAME_1 "pxr/base/tf/makePyConstructor.h"
329 #include BOOST_PP_ITERATE()
337 template <
typename T>
338 Tf_MakePyConstructor::InitVisitor
339 <
typename Tf_MakePyConstructor::InitCtor<T> >
340 TfMakePyConstructor(T *func,
const std::string &doc = std::string()) {
342 Tf_MakePyConstructor::InitCtor<T> Ctor(func);
343 return Tf_MakePyConstructor::InitVisitor
344 <Tf_MakePyConstructor::InitCtor<T> >(doc);
347 template <
typename T>
348 Tf_MakePyConstructor::InitVisitor
349 <
typename Tf_MakePyConstructor::InitCtorWithBackReference<T> >
350 TfMakePyConstructorWithBackReference(T *func,
const std::string &doc = std::string()) {
352 Tf_MakePyConstructor::InitCtorWithBackReference<T> Ctor(func);
353 return Tf_MakePyConstructor::InitVisitor
354 <Tf_MakePyConstructor::InitCtorWithBackReference<T> >(doc);
357 template <
typename T>
358 Tf_MakePyConstructor::InitVisitor
359 <
typename Tf_MakePyConstructor::InitCtorWithVarArgs<T> >
360 TfMakePyConstructorWithVarArgs(T *func,
const std::string &doc = std::string()) {
362 Tf_MakePyConstructor::InitCtorWithVarArgs<T> Ctor(func);
363 return Tf_MakePyConstructor::InitVisitor
364 <Tf_MakePyConstructor::InitCtorWithVarArgs<T> >(doc);
367 template <
typename T>
368 Tf_MakePyConstructor::NewVisitor
369 <
typename Tf_MakePyConstructor::NewCtor<T> >
370 TfMakePyNew(T *func,
const std::string &doc = std::string()) {
372 Tf_MakePyConstructor::NewCtor<T> Ctor(func);
373 return Tf_MakePyConstructor::NewVisitor
374 <Tf_MakePyConstructor::NewCtor<T> >(doc);
377 template <
typename T>
378 Tf_MakePyConstructor::NewVisitor
379 <
typename Tf_MakePyConstructor::NewCtorWithClassReference<T> >
380 TfMakePyNewWithClassReference(T *func,
const std::string &doc = std::string()) {
382 Tf_MakePyConstructor::NewCtorWithClassReference<T> Ctor(func);
383 return Tf_MakePyConstructor::NewVisitor
384 <Tf_MakePyConstructor::NewCtorWithClassReference<T> >(doc);
388 template <
typename T =
void>
389 struct TfPyRefPtrFactory :
public Tf_MakePyConstructor::RefPtrFactory<T> {};
391 template <
typename T>
struct Tf_PySequenceToListConverterRefPtrFactory;
396 template <
typename T>
398 typedef Tf_PySequenceToListConverterRefPtrFactory<T> type;
403 template <
typename T>
404 struct Tf_PySequenceToListConverterRefPtrFactory {
405 typedef typename boost::remove_reference<T>::type SeqType;
406 bool convertible()
const {
409 PyObject *operator()(T seq)
const {
410 using namespace boost::python;
412 typedef typename Tf_MakePyConstructor::RefPtrFactory<>::
413 apply<typename SeqType::value_type>::type RefPtrFactory;
415 boost::python::list l;
416 for (
typename SeqType::const_iterator i = seq.begin();
417 i != seq.end(); ++i) {
418 l.append(
object(handle<>(RefPtrFactory()(*i))));
420 return boost::python::incref(l.ptr());
424 PyTypeObject
const *get_pytype()
const {
429 PXR_NAMESPACE_CLOSE_SCOPE
431 #endif // PXR_BASE_TF_MAKE_PY_CONSTRUCTOR_H
433 #else // BOOST_PP_IS_ITERATING
435 #define N BOOST_PP_ITERATION()
437 #define SIGNATURE R (BOOST_PP_ENUM_PARAMS(N, A))
438 #define PARAMLIST BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(N, A, a)
439 #define ARGLIST BOOST_PP_ENUM_PARAMS(N, a)
445 template <
typename R BOOST_PP_ENUM_TRAILING_PARAMS(N,
typename A)>
446 struct InitCtor<SIGNATURE> : CtorBase<SIGNATURE> {
447 typedef CtorBase<SIGNATURE> Base;
448 typedef typename Base::Sig Sig;
449 InitCtor(Sig *func) { Base::SetFunc(func); }
451 template <
typename CLS>
452 static bp::object init_callable() {
453 return bp::make_function(__init__<CLS>);
456 template <
typename CLS,
typename Options>
457 static bp::object init_callable(Options& o) {
458 return bp::make_function(__init__<CLS>, o.policies(), o.keywords()) ;
461 template <
typename CLS>
462 static void __init__(
object &
self PARAMLIST) {
464 Install<CLS>(
self, Base::_func(ARGLIST), m);
468 template <
typename R BOOST_PP_ENUM_TRAILING_PARAMS(N,
typename A)>
469 struct NewCtor<SIGNATURE> : CtorBase<SIGNATURE> {
470 typedef CtorBase<SIGNATURE> Base;
471 typedef typename Base::Sig Sig;
472 NewCtor(Sig *func) { Base::SetFunc(func); }
475 static bp::object __new__(
object &cls PARAMLIST) {
476 typedef typename CLS::metadata::held_type HeldType;
478 R r((Base::_func(ARGLIST)));
480 if (TfPyConvertTfErrorsToPythonException(m))
481 bp::throw_error_already_set();
487 bp::detail::initialize_wrapper(ret.ptr(), get_pointer(h));
489 bp::setattr(ret,
"__class__", cls);
491 InstallPolicy<R>::PostInstall(ret, r, h.GetUniqueIdentifier());
496 #define VAR_SIGNATURE \
497 R (BOOST_PP_ENUM_PARAMS(N, A) BOOST_PP_COMMA_IF(N) \
498 const bp::tuple&, const bp::dict&)
500 #define FORMAT_STR(z, n, data) "%s, "
501 #define ARG_TYPE_STR_A(z, n, data) bp::type_id<A##n>().name()
503 #define EXTRACT_REQ_ARG_A(z, n, data) \
506 bp::extract<typename boost::remove_reference<A##n>::type>(data[n + 1])
508 template <
typename R BOOST_PP_ENUM_TRAILING_PARAMS(N,
typename A)>
509 struct InitCtorWithVarArgs<VAR_SIGNATURE> : CtorBase<VAR_SIGNATURE> {
510 typedef CtorBase<VAR_SIGNATURE> Base;
511 typedef typename Base::Sig Sig;
512 InitCtorWithVarArgs(Sig *func) { Base::SetFunc(func); }
514 template <
typename CLS>
515 static bp::object init_callable() {
519 return bp::raw_function(__init__<CLS>, 1);
522 template <
typename CLS,
typename Options>
523 static bp::object init_callable(Options& options) {
526 return bp::raw_function(
527 bp::make_function(__init__<CLS>, options.policies()),
531 template <
typename CLS>
532 static bp::object __init__(
const bp::tuple& args,
const bp::dict& kwargs) {
535 const unsigned int numArgs = bp::len(args);
536 if (numArgs - 1 < N) {
541 "Arguments to __init__ did not match C++ signature:\n"
542 "\t__init__(" BOOST_PP_REPEAT(N, FORMAT_STR, 0)
"...)"
543 BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM(N, ARG_TYPE_STR_A, 0)
556 BOOST_PP_ENUM(N, EXTRACT_REQ_ARG_A, args) BOOST_PP_COMMA_IF(N)
557 bp::tuple(args.slice(N + 1, numArgs)), kwargs),
567 #define PARAMLIST BOOST_PP_ENUM_BINARY_PARAMS(N, A, a)
575 template <
typename R BOOST_PP_ENUM_TRAILING_PARAMS(N,
typename A)>
576 struct InitCtorWithBackReference<SIGNATURE> : CtorBase<SIGNATURE> {
577 typedef CtorBase<SIGNATURE> Base;
578 typedef typename Base::Sig Sig;
579 InitCtorWithBackReference(Sig *func) { Base::SetFunc(func); }
581 template <
typename CLS>
582 static bp::object init_callable() {
583 return bp::make_function(__init__<CLS>);
586 template <
typename CLS,
typename Options>
587 static bp::object init_callable(Options& o) {
588 return bp::make_function(__init__<CLS>, o.policies(), o.keywords());
591 template <
typename CLS>
592 static void __init__(PARAMLIST) {
594 Install<CLS>(a0, Base::_func(ARGLIST), m);
598 template <
typename R BOOST_PP_ENUM_TRAILING_PARAMS(N,
typename A)>
599 struct NewCtorWithClassReference<SIGNATURE> : CtorBase<SIGNATURE> {
600 typedef CtorBase<SIGNATURE> Base;
601 typedef typename Base::Sig Sig;
602 NewCtorWithClassReference(Sig *func) { Base::SetFunc(func); }
605 static bp::object __new__(PARAMLIST) {
606 typedef typename CLS::metadata::held_type HeldType;
608 R r(Base::_func(ARGLIST));
610 if (TfPyConvertTfErrorsToPythonException(m))
611 bp::throw_error_already_set();
617 bp::detail::initialize_wrapper(ret.ptr(), get_pointer(h));
619 bp::setattr(ret,
"__class__", a0);
621 InstallPolicy<R>::PostInstall(ret, r, h.GetUniqueIdentifier());
634 #undef ARG_TYPE_STR_A
635 #undef EXTRACT_REQ_ARG_A
637 #endif // BOOST_PP_IS_ITERATING
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...
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
ARCH_API std::string ArchGetDemangled(const std::string &typeName)
Return demangled RTTI-generated type name.
Definitions of basic string utilities in tf.
Low-level utilities for informing users of various internal and external diagnostic conditions...
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...
Miscellaneous Utilities for dealing with script.
Pointer storage with deletion detection.
Demangle C++ typenames generated by the typeid() facility.
Pointer storage with deletion detection.
Class used to record the end of the error-list.
TF_API bool TfPyIsNone(boost::python::object const &obj)
Return true iff obj is None.
TF_API void TfPyThrowTypeError(std::string const &msg)
Raises a python TypeError and throws a C++ exception.
Reference-counted smart pointer utility class.
TF_API void TfPyThrowRuntimeError(std::string const &msg)
Raises a python RuntimError and throws a C++ exception.