All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
makePyConstructor.h
Go to the documentation of this file.
1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 
25 #if !BOOST_PP_IS_ITERATING
26 
27 #ifndef TF_MAKE_CONSTRUCTOR_H
28 #define TF_MAKE_CONSTRUCTOR_H
29 
33 
34 #ifndef TF_MAX_ARITY
35 # define TF_MAX_ARITY 7
36 #endif // TF_MAX_ARITY
37 
38 
39 #include "pxr/pxr.h"
40 #include "pxr/base/tf/refPtr.h"
41 #include "pxr/base/tf/weakPtr.h"
42 #include "pxr/base/tf/diagnostic.h"
43 #include "pxr/base/tf/pyError.h"
44 #include "pxr/base/tf/pyIdentity.h"
45 #include "pxr/base/tf/pyUtils.h"
46 #include "pxr/base/tf/stringUtils.h"
47 
48 #include "pxr/base/arch/demangle.h"
49 
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>
69 
70 #include <string>
71 
72 PXR_NAMESPACE_OPEN_SCOPE
73 
74 // Helper for wrapping objects that are held by weak pointers, but may also be
75 // constructed from script. This lets one construct an object from script and
76 // stores a ref pointer to the C++ object inside the python object. This way,
77 // objects created from script are owned by script, but objects obtained from
78 // the C++ API cannot be owned by script. When the owning python object is
79 // collected, its ref pointer will go away and the C++ object will be
80 // deallocated.
81 //
82 // Example usage:
83 //
84 // class_<MyClass, MyClassPtr>("MyClass", no_init)
85 // .def(TfPyRefAndWeakPtr())
86 // .def(TfMakePyConstructor(MyClass::New))
87 // .def(...)
88 // ...
89 //
90 // TfMakePyConstructorWithVarArgs may be used to wrap an object so that it
91 // may be constructed with a variable number of positional and keyword
92 // arguments. The last two arguments of the function being wrapped must
93 // be a boost::python::tuple and dict. These will contain the remaining
94 // positional and keyword args after required arguments are parsed.
95 //
96 // Example usage:
97 //
98 // static MyObjectRefPtr MyObjectFactory(
99 // int formalArg1, const std::string& formalArg2,
100 // const boost::python::tuple& args, const boost::python::dict& kwargs);
101 //
102 // class_<MyClass, MyClassPtr>("MyClass", no_init)
103 // .def(TfPyRefAndWeakPtr())
104 // .def(TfMakePyConstructorWithVarArgs(MyObjectFactory))
105 // .def(...)
106 //
107 // NOTE: The current implementation does not handle boost::python::arg for
108 // specifying keywords for required arguments.
109 
110 namespace Tf_MakePyConstructor {
111 
112 namespace bp = boost::python;
113 
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) {}
119 
120  template <typename CLS>
121  void visit(CLS &c) const {
122  c.def("__init__", CTOR::template init_callable<CLS>(), _doc.c_str());
123  }
124 
125  template <class CLS, class Options>
126  void visit(CLS &c, char const* name, Options& options) const {
127  // Note: we ignore options.doc() in favor of _doc
128  c.def(name, CTOR::template init_callable<CLS>(options), _doc.c_str());
129  }
130 
131 };
132 
133 bp::object _DummyInit(bp::tuple const & /* args */,
134  bp::dict const & /* kw */);
135 
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) {}
141 
142  template <typename CLS>
143  void visit(CLS &c) const {
144  // If there's already a __new__ method, look through the staticmethod to
145  // get the underlying function, replace __new__ with that, then add the
146  // overload, and recreate the staticmethod. This is required because
147  // boost python needs to have all overloads exported before you say
148  // .staticmethod.
149 
150  // Note that it looks like this should do nothing, but it actually does
151  // something! Here's what it does: looking up __new__ on c doesn't
152  // actually produce the staticmethod object -- it does a "descriptor
153  // __get__" which produces the underlying function. Replacing __new__
154  // with that underlying thing has the effect of unwrapping the
155  // staticmethod, which is exactly what we want.
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__");
160 
161  //c.def("__init__", CTOR::template __init__<CLS>, _doc.c_str());
162  c.def("__init__", bp::raw_function(_DummyInit));
163  }
164 
165  template <class CLS, class Options>
166  void visit(CLS &c, char const* name, Options& options) const {
167  // If there's already a __new__ method, look through the staticmethod to
168  // get the underlying function, replace __new__ with that, then add the
169  // overload, and recreate the staticmethod. This is required because
170  // boost python needs to have all overloads exported before you say
171  // .staticmethod.
172 
173  // Note that it looks like this should do nothing, but it actually does
174  // something! Here's what it does: looking up __new__ on c doesn't
175  // actually produce the staticmethod object -- it does a "descriptor
176  // __get__" which produces the underlying function. Replacing __new__
177  // with that underlying thing has the effect of unwrapping the
178  // staticmethod, which is exactly what we want.
179  if (PyObject_HasAttrString(c.ptr(), "__new__"))
180  c.attr("__new__") = c.attr("__new__");
181  c.def("__new__", CTOR::template __new__<CLS>,
182  // Note: we ignore options.doc() in favor of _doc
183  _doc.c_str(),
184  options.keywords(),
185  options.policies()
186  );
187  c.staticmethod("__new__");
188 
189  //c.def("__init__", CTOR::template __init__<CLS>, _doc.c_str());
190  c.def("__init__", bp::raw_function(_DummyInit));
191  }
192 
193 };
194 
195 
196 typedef bp::object object;
197 
198 template <typename T>
199 struct InstallPolicy {
200  static void PostInstall(object const &self, T const &t,
201  const void *) {}
202 };
203 
204 // Specialize install policy for refptrs.
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) {
211  // Stash a self-reference ref ptr into the python object that will
212  // keep the object alive. Need to get a ref ptr to the held type,
213  // since that's what's wrapped.
214  Tf_PyAddPythonOwnership(ptr, uniqueId, self.ptr());
215  }
216 };
217 
218 template <typename CLS, typename T>
219 void Install(object const &self, T const &t, TfErrorMark const &m) {
220  // Stick the weakptr into the python object self to complete
221  // construction.
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;
226 
227  // CODE_COVERAGE_OFF
228  void *memory = Holder::
229  // CODE_COVERAGE_ON
230  allocate(self.ptr(), offsetof(instance_t, storage), sizeof(Holder));
231  try {
232  HeldType held(t);
233  Holder *holder = (new (memory) Holder(held));
234  // If there was a TfError, raise that back to python.
235  if (TfPyConvertTfErrorsToPythonException(m))
236  bp::throw_error_already_set();
237  // If no TfError, but object construction failed, raise a generic error
238  // back to python.
239  if (!held)
240  TfPyThrowRuntimeError("could not construct " +
241  ArchGetDemangled(typeid(HeldType)));
242  bp::detail::initialize_wrapper(self.ptr(), &(*(held.operator->())));
243  holder->install(self.ptr());
244 
245  // Set object identity
246  Tf_PySetPythonIdentity(held, self.ptr());
247 
248  Policy::PostInstall(self, t, held.GetUniqueIdentifier());
249 
250  } catch(...) {
251  Holder::deallocate(self.ptr(), memory); throw;
252  }
253 
254 }
255 
256 
257 template <typename WeakPtr, typename P>
258 struct _RefPtrFactoryConverter {
259  typedef typename boost::remove_reference<P>::type Ptr;
260  bool convertible() const {
261  // FIXME should actually check here... It's not really horrible because
262  // if the conversion will fail, we'll just get a runtime error down
263  // below when we try to create the resulting object. That's basically
264  // what we want anyway.
265  return true;
266  }
267  PyObject *operator()(Ptr const &p) const {
268  typedef InstallPolicy<Ptr> Policy;
269  WeakPtr ptr(static_cast<typename WeakPtr::DataType *>
270  (get_pointer(p)));
271 
272  // If resulting pointer is null, return None.
273  if (!ptr)
274  return bp::incref(Py_None);
275 
276  // The to-python converter will set identity here.
277  object result(ptr);
278 
279  Policy::PostInstall(result, p, ptr.GetUniqueIdentifier());
280  return bp::incref(result.ptr());
281  }
282  // Required for boost.python signature generator, in play when
283  // BOOST_PYTHON_NO_PY_SIGNATURES is undefined.
284  PyTypeObject const *get_pytype() const {
285  return boost::python::objects::registered_class_object(
286  boost::python::type_id<typename WeakPtr::DataType>()).get();
287  }
288 };
289 
290 template <typename WeakPtr = void>
291 struct RefPtrFactory {
292  template <typename FactoryResultPtr>
293  struct apply {
294  typedef typename boost::mpl::if_<boost::is_same<WeakPtr, void>,
296  WeakPtr>::type WeakPtrType;
297  typedef _RefPtrFactoryConverter<WeakPtrType, FactoryResultPtr> type;
298  };
299 };
300 
301 template <typename SIG>
302 struct CtorBase {
303  typedef SIG Sig;
304  static Sig *_func;
305  static void SetFunc(Sig *func) {
306  if (!_func)
307  _func = func;
308  else {
309  // CODE_COVERAGE_OFF
310  TF_CODING_ERROR("Ctor with signature '%s' is already registered. "
311  "Duplicate will be ignored.",
312  ArchGetDemangled(typeid(Sig)).c_str());
313  // CODE_COVERAGE_ON
314  }
315  }
316 };
317 
318 template <typename SIG> SIG *CtorBase<SIG>::_func = 0;
319 
320 // The following preprocessor code repeatedly includes this file to generate
321 // specializations of Ctor taking 0 through TF_MAX_ARITY parameters.
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()
330 /* comment needed for scons dependency scanner
331 #include "pxr/base/tf/makePyConstructor.h"
332 */
333 
334 }
335 
336 
337 template <typename T>
338 Tf_MakePyConstructor::InitVisitor
339 <typename Tf_MakePyConstructor::InitCtor<T> >
340 TfMakePyConstructor(T *func, const std::string &doc = std::string()) {
341  // Instantiate to set static constructor pointer, then return the visitor.
342  Tf_MakePyConstructor::InitCtor<T> Ctor(func);
343  return Tf_MakePyConstructor::InitVisitor
344  <Tf_MakePyConstructor::InitCtor<T> >(doc);
345 }
346 
347 template <typename T>
348 Tf_MakePyConstructor::InitVisitor
349 <typename Tf_MakePyConstructor::InitCtorWithBackReference<T> >
350 TfMakePyConstructorWithBackReference(T *func, const std::string &doc = std::string()) {
351  // Instantiate to set static constructor pointer, then return the visitor.
352  Tf_MakePyConstructor::InitCtorWithBackReference<T> Ctor(func);
353  return Tf_MakePyConstructor::InitVisitor
354  <Tf_MakePyConstructor::InitCtorWithBackReference<T> >(doc);
355 }
356 
357 template <typename T>
358 Tf_MakePyConstructor::InitVisitor
359 <typename Tf_MakePyConstructor::InitCtorWithVarArgs<T> >
360 TfMakePyConstructorWithVarArgs(T *func, const std::string &doc = std::string()) {
361  // Instantiate to set static constructor pointer, then return the visitor.
362  Tf_MakePyConstructor::InitCtorWithVarArgs<T> Ctor(func);
363  return Tf_MakePyConstructor::InitVisitor
364  <Tf_MakePyConstructor::InitCtorWithVarArgs<T> >(doc);
365 }
366 
367 template <typename T>
368 Tf_MakePyConstructor::NewVisitor
369 <typename Tf_MakePyConstructor::NewCtor<T> >
370 TfMakePyNew(T *func, const std::string &doc = std::string()) {
371  // Instantiate to set static constructor pointer, then return the visitor.
372  Tf_MakePyConstructor::NewCtor<T> Ctor(func);
373  return Tf_MakePyConstructor::NewVisitor
374  <Tf_MakePyConstructor::NewCtor<T> >(doc);
375 }
376 
377 template <typename T>
378 Tf_MakePyConstructor::NewVisitor
379 <typename Tf_MakePyConstructor::NewCtorWithClassReference<T> >
380 TfMakePyNewWithClassReference(T *func, const std::string &doc = std::string()) {
381  // Instantiate to set static constructor pointer, then return the visitor.
382  Tf_MakePyConstructor::NewCtorWithClassReference<T> Ctor(func);
383  return Tf_MakePyConstructor::NewVisitor
384  <Tf_MakePyConstructor::NewCtorWithClassReference<T> >(doc);
385 }
386 
387 
388 template <typename T = void>
389 struct TfPyRefPtrFactory : public Tf_MakePyConstructor::RefPtrFactory<T> {};
390 
391 template <typename T> struct Tf_PySequenceToListConverterRefPtrFactory;
392 
396  template <typename T>
397  struct apply {
398  typedef Tf_PySequenceToListConverterRefPtrFactory<T> type;
399  };
400 };
401 
402 // XXX: would be nicer to be able to compose converters with factory
403 template <typename T>
404 struct Tf_PySequenceToListConverterRefPtrFactory {
405  typedef typename boost::remove_reference<T>::type SeqType;
406  bool convertible() const {
407  return true;
408  }
409  PyObject *operator()(T seq) const {
410  using namespace boost::python;
411 
412  typedef typename Tf_MakePyConstructor::RefPtrFactory<>::
413  apply<typename SeqType::value_type>::type RefPtrFactory;
414 
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))));
419  }
420  return boost::python::incref(l.ptr());
421  }
422  // Required for boost.python signature generator, in play when
423  // BOOST_PYTHON_NO_PY_SIGNATURES is undefined.
424  PyTypeObject const *get_pytype() const {
425  return &PyList_Type;
426  }
427 };
428 
429 PXR_NAMESPACE_CLOSE_SCOPE
430 
431 #endif // TF_MAKE_CONSTRUCTOR_H
432 
433 #else // BOOST_PP_IS_ITERATING
434 
435 #define N BOOST_PP_ITERATION()
436 
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)
440 
441 // This generates multi-argument specializations for Tf_MakePyConstructor::Ctor.
442 // One nice thing about this style of PP repetition is that the debugger will
443 // actually step you over these lines for any instantiation of Ctor.
444 
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); }
450 
451  template <typename CLS>
452  static bp::object init_callable() {
453  return bp::make_function(__init__<CLS>);
454  }
455 
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()) ;
459  }
460 
461  template <typename CLS>
462  static void __init__(object &self PARAMLIST) {
463  TfErrorMark m;
464  Install<CLS>(self, Base::_func(ARGLIST), m);
465  }
466 };
467 
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); }
473 
474  template <class CLS>
475  static bp::object __new__(object &cls PARAMLIST) {
476  typedef typename CLS::metadata::held_type HeldType;
477  TfErrorMark m;
478  R r((Base::_func(ARGLIST)));
479  HeldType h((r));
480  if (TfPyConvertTfErrorsToPythonException(m))
481  bp::throw_error_already_set();
482  bp::object ret = TfPyObject(h);
483  if (TfPyIsNone(ret))
484  TfPyThrowRuntimeError("could not construct " +
485  ArchGetDemangled(typeid(HeldType)));
486 
487  bp::detail::initialize_wrapper(ret.ptr(), get_pointer(h));
488  // make the object have the right class.
489  bp::setattr(ret, "__class__", cls);
490 
491  InstallPolicy<R>::PostInstall(ret, r, h.GetUniqueIdentifier());
492  return ret;
493  }
494 };
495 
496 #define VAR_SIGNATURE \
497  R (BOOST_PP_ENUM_PARAMS(N, A) BOOST_PP_COMMA_IF(N) \
498  const bp::tuple&, const bp::dict&)
499 
500 #define FORMAT_STR(z, n, data) "%s, "
501 #define ARG_TYPE_STR_A(z, n, data) bp::type_id<A##n>().name()
502 
503 #define EXTRACT_REQ_ARG_A(z, n, data) \
504  /* The n'th required arg is stored at n + 1 in the positional args */ \
505  /* tuple as the 0'th element is always the self object */ \
506  bp::extract<typename boost::remove_reference<A##n>::type>(data[n + 1])
507 
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); }
513 
514  template <typename CLS>
515  static bp::object init_callable() {
516  // Specify min_args as 1 to account for just the 'self' argument.
517  // min_args really should be N + 1. However, we want to do this check
518  // ourselves later so we can emit a better error message.
519  return bp::raw_function(__init__<CLS>, /* min_args = */ 1);
520  }
521 
522  template <typename CLS, typename Options>
523  static bp::object init_callable(Options& options) {
524  // XXX: Note ignoring options.keywords(), current implementation can't
525  // handle that correctly.
526  return bp::raw_function(
527  bp::make_function(__init__<CLS>, options.policies()),
528  /* min_args = */ 1);
529  }
530 
531  template <typename CLS>
532  static bp::object __init__(const bp::tuple& args, const bp::dict& kwargs) {
533  TfErrorMark m;
534 
535  const unsigned int numArgs = bp::len(args);
536  if (numArgs - 1 < N) {
537  // User didn't provide enough positional arguments for the factory
538  // function. Complain.
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)
544  )
545  );
546  return bp::object();
547  }
548 
549  Install<CLS>(
550  // self object for new instance is the first arg to __init__
551  args[0],
552 
553  // Slice the first N arguments from positional arguments as
554  // those are the required arguments for the factory function.
555  Base::_func(
556  BOOST_PP_ENUM(N, EXTRACT_REQ_ARG_A, args) BOOST_PP_COMMA_IF(N)
557  bp::tuple(args.slice(N + 1, numArgs)), kwargs),
558  m);
559 
560  return bp::object();
561  }
562 
563 };
564 
565 #if N > 0
566 #undef PARAMLIST
567 #define PARAMLIST BOOST_PP_ENUM_BINARY_PARAMS(N, A, a)
568 
569 // This is a variant of Ctor which includes a back reference to self
570 // (the Python object being initialized) in the args passed to the
571 // constructor. This is used to expose the factory methods for classes
572 // which we expect to subclass in Python. When the constructor is called,
573 // it can examine self and initialize itself appropriately.
574 
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); }
580 
581  template <typename CLS>
582  static bp::object init_callable() {
583  return bp::make_function(__init__<CLS>);
584  }
585 
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());
589  }
590 
591  template <typename CLS>
592  static void __init__(PARAMLIST) {
593  TfErrorMark m;
594  Install<CLS>(a0, Base::_func(ARGLIST), m);
595  }
596 };
597 
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); }
603 
604  template <class CLS>
605  static bp::object __new__(PARAMLIST) {
606  typedef typename CLS::metadata::held_type HeldType;
607  TfErrorMark m;
608  R r(Base::_func(ARGLIST));
609  HeldType h(r);
610  if (TfPyConvertTfErrorsToPythonException(m))
611  bp::throw_error_already_set();
612  bp::object ret = TfPyObject(h);
613  if (TfPyIsNone(ret))
614  TfPyThrowRuntimeError("could not construct " +
615  ArchGetDemangled(typeid(HeldType)));
616 
617  bp::detail::initialize_wrapper(ret.ptr(), get_pointer(h));
618  // make the object have the right class.
619  bp::setattr(ret, "__class__", a0);
620 
621  InstallPolicy<R>::PostInstall(ret, r, h.GetUniqueIdentifier());
622  return ret;
623  }
624 };
625 
626 #endif
627 
628 #undef N
629 #undef SIGNATURE
630 #undef PARAMLIST
631 #undef ARGLIST
632 #undef VAR_SIGNATURE
633 #undef FORMAT_STR
634 #undef ARG_TYPE_STR_A
635 #undef EXTRACT_REQ_ARG_A
636 
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.
Definition: diagnostic.h:87
ARCH_API std::string ArchGetDemangled(const std::string &typeName)
Return demangled RTTI-generated type name.
Pointer storage with deletion detection.
Definition: hash.h:44
Class used to record the end of the error-list.
Definition: errorMark.h:66
TF_API void TfPyThrowTypeError(std::string const &msg)
Raises a python TypeError and throws a C++ exception.
TF_API void TfPyThrowRuntimeError(std::string const &msg)
Raises a python RuntimError and throws a C++ exception.
TF_API bool TfPyIsNone(boost::python::object const &obj)
Return true iff obj is None.
Reference-counted smart pointer utility class.
Definition: hash.h:45
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...
Definition: pyUtils.h:100