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 PXR_BASE_TF_MAKE_PY_CONSTRUCTOR_H
28 #define PXR_BASE_TF_MAKE_PY_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/api.h"
41 #include "pxr/base/tf/refPtr.h"
42 #include "pxr/base/tf/weakPtr.h"
43 #include "pxr/base/tf/diagnostic.h"
44 #include "pxr/base/tf/pyError.h"
45 #include "pxr/base/tf/pyIdentity.h"
46 #include "pxr/base/tf/pyUtils.h"
48 
49 #include "pxr/base/arch/demangle.h"
50 
51 #include <boost/preprocessor/iterate.hpp>
52 #include <boost/preprocessor/punctuation/comma_if.hpp>
53 #include <boost/preprocessor/repetition/enum.hpp>
54 #include <boost/preprocessor/repetition/enum_binary_params.hpp>
55 #include <boost/preprocessor/repetition/enum_params.hpp>
56 #include <boost/preprocessor/repetition/enum_trailing_binary_params.hpp>
57 #include <boost/preprocessor/repetition/enum_trailing_params.hpp>
58 #include <boost/preprocessor/repetition/repeat.hpp>
59 #include <boost/preprocessor/seq/for_each.hpp>
60 #include <boost/python/def_visitor.hpp>
61 #include <boost/python/dict.hpp>
62 #include <boost/python/errors.hpp>
63 #include <boost/python/list.hpp>
64 #include <boost/python/object/iterator.hpp>
65 #include <boost/python/raw_function.hpp>
66 #include <boost/python/tuple.hpp>
67 #include <boost/python/type_id.hpp>
68 #include <boost/type_traits/is_same.hpp>
69 #include <boost/type_traits/remove_reference.hpp>
70 
71 #include <string>
72 
73 PXR_NAMESPACE_OPEN_SCOPE
74 
75 // Helper for wrapping objects that are held by weak pointers, but may also be
76 // constructed from script. This lets one construct an object from script and
77 // stores a ref pointer to the C++ object inside the python object. This way,
78 // objects created from script are owned by script, but objects obtained from
79 // the C++ API cannot be owned by script. When the owning python object is
80 // collected, its ref pointer will go away and the C++ object will be
81 // deallocated.
82 //
83 // Example usage:
84 //
85 // class_<MyClass, MyClassPtr>("MyClass", no_init)
86 // .def(TfPyRefAndWeakPtr())
87 // .def(TfMakePyConstructor(MyClass::New))
88 // .def(...)
89 // ...
90 //
91 // TfMakePyConstructorWithVarArgs may be used to wrap an object so that it
92 // may be constructed with a variable number of positional and keyword
93 // arguments. The last two arguments of the function being wrapped must
94 // be a boost::python::tuple and dict. These will contain the remaining
95 // positional and keyword args after required arguments are parsed.
96 //
97 // Example usage:
98 //
99 // static MyObjectRefPtr MyObjectFactory(
100 // int formalArg1, const std::string& formalArg2,
101 // const boost::python::tuple& args, const boost::python::dict& kwargs);
102 //
103 // class_<MyClass, MyClassPtr>("MyClass", no_init)
104 // .def(TfPyRefAndWeakPtr())
105 // .def(TfMakePyConstructorWithVarArgs(MyObjectFactory))
106 // .def(...)
107 //
108 // NOTE: The current implementation does not handle boost::python::arg for
109 // specifying keywords for required arguments.
110 
111 namespace Tf_MakePyConstructor {
112 
113 namespace bp = boost::python;
114 
115 template <typename CTOR>
116 struct InitVisitor : bp::def_visitor<InitVisitor<CTOR> > {
117  friend class bp::def_visitor_access;
118  const std::string _doc;
119  InitVisitor(const std::string &doc = std::string()) : _doc(doc) {}
120 
121  template <typename CLS>
122  void visit(CLS &c) const {
123  c.def("__init__", CTOR::template init_callable<CLS>(), _doc.c_str());
124  }
125 
126  template <class CLS, class Options>
127  void visit(CLS &c, char const* name, Options& options) const {
128  // Note: we ignore options.doc() in favor of _doc
129  c.def(name, CTOR::template init_callable<CLS>(options), _doc.c_str());
130  }
131 
132 };
133 
134 TF_API
135 bp::object _DummyInit(bp::tuple const & /* args */,
136  bp::dict const & /* kw */);
137 
138 template <typename CTOR>
139 struct NewVisitor : bp::def_visitor<NewVisitor<CTOR> > {
140  friend class bp::def_visitor_access;
141  const std::string _doc;
142  NewVisitor(const std::string &doc = std::string()) : _doc(doc) {}
143 
144  template <typename CLS>
145  void visit(CLS &c) const {
146  // If there's already a __new__ method, look through the staticmethod to
147  // get the underlying function, replace __new__ with that, then add the
148  // overload, and recreate the staticmethod. This is required because
149  // boost python needs to have all overloads exported before you say
150  // .staticmethod.
151 
152  // Note that it looks like this should do nothing, but it actually does
153  // something! Here's what it does: looking up __new__ on c doesn't
154  // actually produce the staticmethod object -- it does a "descriptor
155  // __get__" which produces the underlying function. Replacing __new__
156  // with that underlying thing has the effect of unwrapping the
157  // staticmethod, which is exactly what we want.
158  if (PyObject_HasAttrString(c.ptr(), "__new__"))
159  c.attr("__new__") = c.attr("__new__");
160  c.def("__new__", CTOR::template __new__<CLS>, _doc.c_str());
161  c.staticmethod("__new__");
162 
163  //c.def("__init__", CTOR::template __init__<CLS>, _doc.c_str());
164  c.def("__init__", bp::raw_function(_DummyInit));
165  }
166 
167  template <class CLS, class Options>
168  void visit(CLS &c, char const* name, Options& options) const {
169  // If there's already a __new__ method, look through the staticmethod to
170  // get the underlying function, replace __new__ with that, then add the
171  // overload, and recreate the staticmethod. This is required because
172  // boost python needs to have all overloads exported before you say
173  // .staticmethod.
174 
175  // Note that it looks like this should do nothing, but it actually does
176  // something! Here's what it does: looking up __new__ on c doesn't
177  // actually produce the staticmethod object -- it does a "descriptor
178  // __get__" which produces the underlying function. Replacing __new__
179  // with that underlying thing has the effect of unwrapping the
180  // staticmethod, which is exactly what we want.
181  if (PyObject_HasAttrString(c.ptr(), "__new__"))
182  c.attr("__new__") = c.attr("__new__");
183  c.def("__new__", CTOR::template __new__<CLS>,
184  // Note: we ignore options.doc() in favor of _doc
185  _doc.c_str(),
186  options.keywords(),
187  options.policies()
188  );
189  c.staticmethod("__new__");
190 
191  //c.def("__init__", CTOR::template __init__<CLS>, _doc.c_str());
192  c.def("__init__", bp::raw_function(_DummyInit));
193  }
194 
195 };
196 
197 
198 typedef bp::object object;
199 
200 template <typename T>
201 struct InstallPolicy {
202  static void PostInstall(object const &self, T const &t,
203  const void *) {}
204 };
205 
206 // Specialize install policy for refptrs.
207 template <typename T>
208 struct InstallPolicy<TfRefPtr<T> > {
209  static_assert(Tf_SupportsUniqueChanged<T>::Value,
210  "Type T must support refcount unique changed notification.");
211  static void PostInstall(object const &self, TfRefPtr<T> const &ptr,
212  const void *uniqueId) {
213  // Stash a self-reference ref ptr into the python object that will
214  // keep the object alive. Need to get a ref ptr to the held type,
215  // since that's what's wrapped.
216  Tf_PyAddPythonOwnership(ptr, uniqueId, self.ptr());
217  }
218 };
219 
220 template <typename CLS, typename T>
221 void Install(object const &self, T const &t, TfErrorMark const &m) {
222  // Stick the weakptr into the python object self to complete
223  // construction.
224  typedef typename CLS::metadata::holder Holder;
225  typedef typename bp::objects::instance<Holder> instance_t;
226  typedef InstallPolicy<T> Policy;
227  typedef typename CLS::metadata::held_type HeldType;
228 
229  // CODE_COVERAGE_OFF
230  void *memory = Holder::
231  // CODE_COVERAGE_ON
232  allocate(self.ptr(), offsetof(instance_t, storage), sizeof(Holder));
233  try {
234  HeldType held(t);
235  Holder *holder = (new (memory) Holder(held));
236  // If there was a TfError, raise that back to python.
237  if (TfPyConvertTfErrorsToPythonException(m))
238  bp::throw_error_already_set();
239  // If no TfError, but object construction failed, raise a generic error
240  // back to python.
241  if (!held)
242  TfPyThrowRuntimeError("could not construct " +
243  ArchGetDemangled(typeid(HeldType)));
244  bp::detail::initialize_wrapper(self.ptr(), &(*(held.operator->())));
245  holder->install(self.ptr());
246 
247  // Set object identity
248  Tf_PySetPythonIdentity(held, self.ptr());
249 
250  Policy::PostInstall(self, t, held.GetUniqueIdentifier());
251 
252  } catch(...) {
253  Holder::deallocate(self.ptr(), memory); throw;
254  }
255 
256 }
257 
258 
259 template <typename WeakPtr, typename P>
260 struct _RefPtrFactoryConverter {
261  typedef typename boost::remove_reference<P>::type Ptr;
262  bool convertible() const {
263  // FIXME should actually check here... It's not really horrible because
264  // if the conversion will fail, we'll just get a runtime error down
265  // below when we try to create the resulting object. That's basically
266  // what we want anyway.
267  return true;
268  }
269  PyObject *operator()(Ptr const &p) const {
270  typedef InstallPolicy<Ptr> Policy;
271  WeakPtr ptr(static_cast<typename WeakPtr::DataType *>
272  (get_pointer(p)));
273 
274  // If resulting pointer is null, return None.
275  if (!ptr)
276  return bp::incref(Py_None);
277 
278  // The to-python converter will set identity here.
279  object result(ptr);
280 
281  Policy::PostInstall(result, p, ptr.GetUniqueIdentifier());
282  return bp::incref(result.ptr());
283  }
284  // Required for boost.python signature generator, in play when
285  // BOOST_PYTHON_NO_PY_SIGNATURES is undefined.
286  PyTypeObject const *get_pytype() const {
287  return boost::python::objects::registered_class_object(
288  boost::python::type_id<typename WeakPtr::DataType>()).get();
289  }
290 };
291 
292 template <typename WeakPtr = void>
293 struct RefPtrFactory {
294  template <typename FactoryResultPtr>
295  struct apply {
296  typedef typename boost::mpl::if_<boost::is_same<WeakPtr, void>,
298  WeakPtr>::type WeakPtrType;
299  typedef _RefPtrFactoryConverter<WeakPtrType, FactoryResultPtr> type;
300  };
301 };
302 
303 template <typename SIG>
304 struct CtorBase {
305  typedef SIG Sig;
306  static Sig *_func;
307  static void SetFunc(Sig *func) {
308  if (!_func)
309  _func = func;
310  else {
311  // CODE_COVERAGE_OFF
312  TF_CODING_ERROR("Ctor with signature '%s' is already registered. "
313  "Duplicate will be ignored.",
314  ArchGetDemangled(typeid(Sig)).c_str());
315  // CODE_COVERAGE_ON
316  }
317  }
318 };
319 
320 template <typename SIG> SIG *CtorBase<SIG>::_func = 0;
321 
322 // The following preprocessor code repeatedly includes this file to generate
323 // specializations of Ctor taking 0 through TF_MAX_ARITY parameters.
324 template <typename SIG> struct InitCtor;
325 template <typename SIG> struct InitCtorWithBackReference;
326 template <typename SIG> struct InitCtorWithVarArgs;
327 template <typename SIG> struct NewCtor;
328 template <typename SIG> struct NewCtorWithClassReference;
329 #define BOOST_PP_ITERATION_LIMITS (0, TF_MAX_ARITY)
330 #define BOOST_PP_FILENAME_1 "pxr/base/tf/makePyConstructor.h"
331 #include BOOST_PP_ITERATE()
332 /* comment needed for scons dependency scanner
333 #include "pxr/base/tf/makePyConstructor.h"
334 */
335 
336 }
337 
338 
339 template <typename T>
340 Tf_MakePyConstructor::InitVisitor
341 <typename Tf_MakePyConstructor::InitCtor<T> >
342 TfMakePyConstructor(T *func, const std::string &doc = std::string()) {
343  // Instantiate to set static constructor pointer, then return the visitor.
344  Tf_MakePyConstructor::InitCtor<T> Ctor(func);
345  return Tf_MakePyConstructor::InitVisitor
346  <Tf_MakePyConstructor::InitCtor<T> >(doc);
347 }
348 
349 template <typename T>
350 Tf_MakePyConstructor::InitVisitor
351 <typename Tf_MakePyConstructor::InitCtorWithBackReference<T> >
352 TfMakePyConstructorWithBackReference(T *func, const std::string &doc = std::string()) {
353  // Instantiate to set static constructor pointer, then return the visitor.
354  Tf_MakePyConstructor::InitCtorWithBackReference<T> Ctor(func);
355  return Tf_MakePyConstructor::InitVisitor
356  <Tf_MakePyConstructor::InitCtorWithBackReference<T> >(doc);
357 }
358 
359 template <typename T>
360 Tf_MakePyConstructor::InitVisitor
361 <typename Tf_MakePyConstructor::InitCtorWithVarArgs<T> >
362 TfMakePyConstructorWithVarArgs(T *func, const std::string &doc = std::string()) {
363  // Instantiate to set static constructor pointer, then return the visitor.
364  Tf_MakePyConstructor::InitCtorWithVarArgs<T> Ctor(func);
365  return Tf_MakePyConstructor::InitVisitor
366  <Tf_MakePyConstructor::InitCtorWithVarArgs<T> >(doc);
367 }
368 
369 template <typename T>
370 Tf_MakePyConstructor::NewVisitor
371 <typename Tf_MakePyConstructor::NewCtor<T> >
372 TfMakePyNew(T *func, const std::string &doc = std::string()) {
373  // Instantiate to set static constructor pointer, then return the visitor.
374  Tf_MakePyConstructor::NewCtor<T> Ctor(func);
375  return Tf_MakePyConstructor::NewVisitor
376  <Tf_MakePyConstructor::NewCtor<T> >(doc);
377 }
378 
379 template <typename T>
380 Tf_MakePyConstructor::NewVisitor
381 <typename Tf_MakePyConstructor::NewCtorWithClassReference<T> >
382 TfMakePyNewWithClassReference(T *func, const std::string &doc = std::string()) {
383  // Instantiate to set static constructor pointer, then return the visitor.
384  Tf_MakePyConstructor::NewCtorWithClassReference<T> Ctor(func);
385  return Tf_MakePyConstructor::NewVisitor
386  <Tf_MakePyConstructor::NewCtorWithClassReference<T> >(doc);
387 }
388 
389 
390 template <typename T = void>
391 struct TfPyRefPtrFactory : public Tf_MakePyConstructor::RefPtrFactory<T> {};
392 
393 template <typename T> struct Tf_PySequenceToListConverterRefPtrFactory;
394 
398  template <typename T>
399  struct apply {
400  typedef Tf_PySequenceToListConverterRefPtrFactory<T> type;
401  };
402 };
403 
404 // XXX: would be nicer to be able to compose converters with factory
405 template <typename T>
406 struct Tf_PySequenceToListConverterRefPtrFactory {
407  typedef typename boost::remove_reference<T>::type SeqType;
408  bool convertible() const {
409  return true;
410  }
411  PyObject *operator()(T seq) const {
412  using namespace boost::python;
413 
414  typedef typename Tf_MakePyConstructor::RefPtrFactory<>::
415  apply<typename SeqType::value_type>::type RefPtrFactory;
416 
417  boost::python::list l;
418  for (typename SeqType::const_iterator i = seq.begin();
419  i != seq.end(); ++i) {
420  l.append(object(handle<>(RefPtrFactory()(*i))));
421  }
422  return boost::python::incref(l.ptr());
423  }
424  // Required for boost.python signature generator, in play when
425  // BOOST_PYTHON_NO_PY_SIGNATURES is undefined.
426  PyTypeObject const *get_pytype() const {
427  return &PyList_Type;
428  }
429 };
430 
431 PXR_NAMESPACE_CLOSE_SCOPE
432 
433 #endif // PXR_BASE_TF_MAKE_PY_CONSTRUCTOR_H
434 
435 #else // BOOST_PP_IS_ITERATING
436 
437 #define N BOOST_PP_ITERATION()
438 
439 #define SIGNATURE R (BOOST_PP_ENUM_PARAMS(N, A))
440 #define PARAMLIST BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(N, A, a)
441 #define ARGLIST BOOST_PP_ENUM_PARAMS(N, a)
442 
443 // This generates multi-argument specializations for Tf_MakePyConstructor::Ctor.
444 // One nice thing about this style of PP repetition is that the debugger will
445 // actually step you over these lines for any instantiation of Ctor.
446 
447 template <typename R BOOST_PP_ENUM_TRAILING_PARAMS(N, typename A)>
448 struct InitCtor<SIGNATURE> : CtorBase<SIGNATURE> {
449  typedef CtorBase<SIGNATURE> Base;
450  typedef typename Base::Sig Sig;
451  InitCtor(Sig *func) { Base::SetFunc(func); }
452 
453  template <typename CLS>
454  static bp::object init_callable() {
455  return bp::make_function(__init__<CLS>);
456  }
457 
458  template <typename CLS, typename Options>
459  static bp::object init_callable(Options& o) {
460  return bp::make_function(__init__<CLS>, o.policies(), o.keywords()) ;
461  }
462 
463  template <typename CLS>
464  static void __init__(object &self PARAMLIST) {
465  TfErrorMark m;
466  Install<CLS>(self, Base::_func(ARGLIST), m);
467  }
468 };
469 
470 template <typename R BOOST_PP_ENUM_TRAILING_PARAMS(N, typename A)>
471 struct NewCtor<SIGNATURE> : CtorBase<SIGNATURE> {
472  typedef CtorBase<SIGNATURE> Base;
473  typedef typename Base::Sig Sig;
474  NewCtor(Sig *func) { Base::SetFunc(func); }
475 
476  template <class CLS>
477  static bp::object __new__(object &cls PARAMLIST) {
478  typedef typename CLS::metadata::held_type HeldType;
479  TfErrorMark m;
480  R r((Base::_func(ARGLIST)));
481  HeldType h((r));
482  if (TfPyConvertTfErrorsToPythonException(m))
483  bp::throw_error_already_set();
484  bp::object ret = TfPyObject(h);
485  if (TfPyIsNone(ret))
486  TfPyThrowRuntimeError("could not construct " +
487  ArchGetDemangled(typeid(HeldType)));
488 
489  bp::detail::initialize_wrapper(ret.ptr(), get_pointer(h));
490  // make the object have the right class.
491  bp::setattr(ret, "__class__", cls);
492 
493  InstallPolicy<R>::PostInstall(ret, r, h.GetUniqueIdentifier());
494  return ret;
495  }
496 };
497 
498 #define VAR_SIGNATURE \
499  R (BOOST_PP_ENUM_PARAMS(N, A) BOOST_PP_COMMA_IF(N) \
500  const bp::tuple&, const bp::dict&)
501 
502 #define FORMAT_STR(z, n, data) "%s, "
503 #define ARG_TYPE_STR_A(z, n, data) bp::type_id<A##n>().name()
504 
505 #define EXTRACT_REQ_ARG_A(z, n, data) \
506  /* The n'th required arg is stored at n + 1 in the positional args */ \
507  /* tuple as the 0'th element is always the self object */ \
508  bp::extract<typename boost::remove_reference<A##n>::type>(data[n + 1])
509 
510 template <typename R BOOST_PP_ENUM_TRAILING_PARAMS(N, typename A)>
511 struct InitCtorWithVarArgs<VAR_SIGNATURE> : CtorBase<VAR_SIGNATURE> {
512  typedef CtorBase<VAR_SIGNATURE> Base;
513  typedef typename Base::Sig Sig;
514  InitCtorWithVarArgs(Sig *func) { Base::SetFunc(func); }
515 
516  template <typename CLS>
517  static bp::object init_callable() {
518  // Specify min_args as 1 to account for just the 'self' argument.
519  // min_args really should be N + 1. However, we want to do this check
520  // ourselves later so we can emit a better error message.
521  return bp::raw_function(__init__<CLS>, /* min_args = */ 1);
522  }
523 
524  template <typename CLS, typename Options>
525  static bp::object init_callable(Options& options) {
526  // XXX: Note ignoring options.keywords(), current implementation can't
527  // handle that correctly.
528  return bp::raw_function(
529  bp::make_function(__init__<CLS>, options.policies()),
530  /* min_args = */ 1);
531  }
532 
533  template <typename CLS>
534  static bp::object __init__(const bp::tuple& args, const bp::dict& kwargs) {
535  TfErrorMark m;
536 
537  const unsigned int numArgs = bp::len(args);
538  if (numArgs - 1 < N) {
539  // User didn't provide enough positional arguments for the factory
540  // function. Complain.
543  "Arguments to __init__ did not match C++ signature:\n"
544  "\t__init__(" BOOST_PP_REPEAT(N, FORMAT_STR, 0) "...)"
545  BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM(N, ARG_TYPE_STR_A, 0)
546  )
547  );
548  return bp::object();
549  }
550 
551  Install<CLS>(
552  // self object for new instance is the first arg to __init__
553  args[0],
554 
555  // Slice the first N arguments from positional arguments as
556  // those are the required arguments for the factory function.
557  Base::_func(
558  BOOST_PP_ENUM(N, EXTRACT_REQ_ARG_A, args) BOOST_PP_COMMA_IF(N)
559  bp::tuple(args.slice(N + 1, numArgs)), kwargs),
560  m);
561 
562  return bp::object();
563  }
564 
565 };
566 
567 #if N > 0
568 #undef PARAMLIST
569 #define PARAMLIST BOOST_PP_ENUM_BINARY_PARAMS(N, A, a)
570 
571 // This is a variant of Ctor which includes a back reference to self
572 // (the Python object being initialized) in the args passed to the
573 // constructor. This is used to expose the factory methods for classes
574 // which we expect to subclass in Python. When the constructor is called,
575 // it can examine self and initialize itself appropriately.
576 
577 template <typename R BOOST_PP_ENUM_TRAILING_PARAMS(N, typename A)>
578 struct InitCtorWithBackReference<SIGNATURE> : CtorBase<SIGNATURE> {
579  typedef CtorBase<SIGNATURE> Base;
580  typedef typename Base::Sig Sig;
581  InitCtorWithBackReference(Sig *func) { Base::SetFunc(func); }
582 
583  template <typename CLS>
584  static bp::object init_callable() {
585  return bp::make_function(__init__<CLS>);
586  }
587 
588  template <typename CLS, typename Options>
589  static bp::object init_callable(Options& o) {
590  return bp::make_function(__init__<CLS>, o.policies(), o.keywords());
591  }
592 
593  template <typename CLS>
594  static void __init__(PARAMLIST) {
595  TfErrorMark m;
596  Install<CLS>(a0, Base::_func(ARGLIST), m);
597  }
598 };
599 
600 template <typename R BOOST_PP_ENUM_TRAILING_PARAMS(N, typename A)>
601 struct NewCtorWithClassReference<SIGNATURE> : CtorBase<SIGNATURE> {
602  typedef CtorBase<SIGNATURE> Base;
603  typedef typename Base::Sig Sig;
604  NewCtorWithClassReference(Sig *func) { Base::SetFunc(func); }
605 
606  template <class CLS>
607  static bp::object __new__(PARAMLIST) {
608  typedef typename CLS::metadata::held_type HeldType;
609  TfErrorMark m;
610  R r(Base::_func(ARGLIST));
611  HeldType h(r);
612  if (TfPyConvertTfErrorsToPythonException(m))
613  bp::throw_error_already_set();
614  bp::object ret = TfPyObject(h);
615  if (TfPyIsNone(ret))
616  TfPyThrowRuntimeError("could not construct " +
617  ArchGetDemangled(typeid(HeldType)));
618 
619  bp::detail::initialize_wrapper(ret.ptr(), get_pointer(h));
620  // make the object have the right class.
621  bp::setattr(ret, "__class__", a0);
622 
623  InstallPolicy<R>::PostInstall(ret, r, h.GetUniqueIdentifier());
624  return ret;
625  }
626 };
627 
628 #endif
629 
630 #undef N
631 #undef SIGNATURE
632 #undef PARAMLIST
633 #undef ARGLIST
634 #undef VAR_SIGNATURE
635 #undef FORMAT_STR
636 #undef ARG_TYPE_STR_A
637 #undef EXTRACT_REQ_ARG_A
638 
639 #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:85
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.
Definition: pyUtils.h:102
Miscellaneous Utilities for dealing with script.
Pointer storage with deletion detection.
Demangle C++ typenames generated by the typeid() facility.
Pointer storage with deletion detection.
Definition: refBase.h:38
Class used to record the end of the error-list.
Definition: errorMark.h:66
TF_API bool TfPyIsNone(boost::python::object const &obj)
Return true iff obj is None.
Reference counting.
TF_API void TfPyThrowTypeError(std::string const &msg)
Raises a python TypeError and throws a C++ exception.
Reference-counted smart pointer utility class.
Definition: refBase.h:37
TF_API void TfPyThrowRuntimeError(std::string const &msg)
Raises a python RuntimError and throws a C++ exception.