Loading...
Searching...
No Matches
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#ifndef PXR_BASE_TF_MAKE_PY_CONSTRUCTOR_H
26#define PXR_BASE_TF_MAKE_PY_CONSTRUCTOR_H
27
31
32#ifndef TF_MAX_ARITY
33# define TF_MAX_ARITY 7
34#endif // TF_MAX_ARITY
35
36
37#include "pxr/pxr.h"
38#include "pxr/base/tf/api.h"
39#include "pxr/base/tf/functionTraits.h"
40#include "pxr/base/tf/refPtr.h"
41#include "pxr/base/tf/weakPtr.h"
43#include "pxr/base/tf/pyError.h"
44#include "pxr/base/tf/pyIdentity.h"
45#include "pxr/base/tf/pyUtils.h"
47
49
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>
58
59#include <array>
60#include <string>
61#include <type_traits>
62#include <utility>
63
64PXR_NAMESPACE_OPEN_SCOPE
65
66// Helper for wrapping objects that are held by weak pointers, but may also be
67// constructed from script. This lets one construct an object from script and
68// stores a ref pointer to the C++ object inside the python object. This way,
69// objects created from script are owned by script, but objects obtained from
70// the C++ API cannot be owned by script. When the owning python object is
71// collected, its ref pointer will go away and the C++ object will be
72// deallocated.
73//
74// Example usage:
75//
76// class_<MyClass, MyClassPtr>("MyClass", no_init)
77// .def(TfPyRefAndWeakPtr())
78// .def(TfMakePyConstructor(MyClass::New))
79// .def(...)
80// ...
81//
82// TfMakePyConstructorWithVarArgs may be used to wrap an object so that it
83// may be constructed with a variable number of positional and keyword
84// arguments. The last two arguments of the function being wrapped must
85// be a boost::python::tuple and dict. These will contain the remaining
86// positional and keyword args after required arguments are parsed.
87//
88// Example usage:
89//
90// static MyObjectRefPtr MyObjectFactory(
91// int formalArg1, const std::string& formalArg2,
92// const boost::python::tuple& args, const boost::python::dict& kwargs);
93//
94// class_<MyClass, MyClassPtr>("MyClass", no_init)
95// .def(TfPyRefAndWeakPtr())
96// .def(TfMakePyConstructorWithVarArgs(MyObjectFactory))
97// .def(...)
98//
99// NOTE: The current implementation does not handle boost::python::arg for
100// specifying keywords for required arguments.
101
102namespace Tf_MakePyConstructor {
103
104namespace bp = boost::python;
105
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) {}
111
112 template <typename CLS>
113 void visit(CLS &c) const {
114 c.def("__init__", CTOR::template init_callable<CLS>(), _doc.c_str());
115 }
116
117 template <class CLS, class Options>
118 void visit(CLS &c, char const* name, Options& options) const {
119 // Note: we ignore options.doc() in favor of _doc
120 c.def(name, CTOR::template init_callable<CLS>(options), _doc.c_str());
121 }
122
123};
124
125TF_API
126bp::object _DummyInit(bp::tuple const & /* args */,
127 bp::dict const & /* kw */);
128
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) {}
134
135 template <typename CLS>
136 void visit(CLS &c) const {
137 // If there's already a __new__ method, look through the staticmethod to
138 // get the underlying function, replace __new__ with that, then add the
139 // overload, and recreate the staticmethod. This is required because
140 // boost python needs to have all overloads exported before you say
141 // .staticmethod.
142
143 // Note that it looks like this should do nothing, but it actually does
144 // something! Here's what it does: looking up __new__ on c doesn't
145 // actually produce the staticmethod object -- it does a "descriptor
146 // __get__" which produces the underlying function. Replacing __new__
147 // with that underlying thing has the effect of unwrapping the
148 // staticmethod, which is exactly what we want.
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__");
153
154 //c.def("__init__", CTOR::template __init__<CLS>, _doc.c_str());
155 c.def("__init__", bp::raw_function(_DummyInit));
156 }
157
158 template <class CLS, class Options>
159 void visit(CLS &c, char const* name, Options& options) const {
160 // If there's already a __new__ method, look through the staticmethod to
161 // get the underlying function, replace __new__ with that, then add the
162 // overload, and recreate the staticmethod. This is required because
163 // boost python needs to have all overloads exported before you say
164 // .staticmethod.
165
166 // Note that it looks like this should do nothing, but it actually does
167 // something! Here's what it does: looking up __new__ on c doesn't
168 // actually produce the staticmethod object -- it does a "descriptor
169 // __get__" which produces the underlying function. Replacing __new__
170 // with that underlying thing has the effect of unwrapping the
171 // staticmethod, which is exactly what we want.
172 if (PyObject_HasAttrString(c.ptr(), "__new__"))
173 c.attr("__new__") = c.attr("__new__");
174 c.def("__new__", CTOR::template __new__<CLS>,
175 // Note: we ignore options.doc() in favor of _doc
176 _doc.c_str(),
177 options.keywords(),
178 options.policies()
179 );
180 c.staticmethod("__new__");
181
182 //c.def("__init__", CTOR::template __init__<CLS>, _doc.c_str());
183 c.def("__init__", bp::raw_function(_DummyInit));
184 }
185
186};
187
188
189typedef bp::object object;
190
191template <typename T>
192struct InstallPolicy {
193 static void PostInstall(object const &self, T const &t,
194 const void *) {}
195};
196
197// Specialize install policy for refptrs.
198template <typename T>
199struct InstallPolicy<TfRefPtr<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) {
204 // Stash a self-reference ref ptr into the python object that will
205 // keep the object alive. Need to get a ref ptr to the held type,
206 // since that's what's wrapped.
207 Tf_PyAddPythonOwnership(ptr, uniqueId, self.ptr());
208 }
209};
210
211template <typename CLS, typename T>
212void Install(object const &self, T const &t, TfErrorMark const &m) {
213 // Stick the weakptr into the python object self to complete
214 // construction.
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;
219
220 // CODE_COVERAGE_OFF
221 void *memory = Holder::
222 // CODE_COVERAGE_ON
223 allocate(self.ptr(), offsetof(instance_t, storage), sizeof(Holder));
224 try {
225 HeldType held(t);
226 Holder *holder = (new (memory) Holder(held));
227 // If there was a TfError, raise that back to python.
228 if (TfPyConvertTfErrorsToPythonException(m))
229 bp::throw_error_already_set();
230 // If no TfError, but object construction failed, raise a generic error
231 // back to python.
232 if (!held)
233 TfPyThrowRuntimeError("could not construct " +
234 ArchGetDemangled(typeid(HeldType)));
235 bp::detail::initialize_wrapper(self.ptr(), &(*(held.operator->())));
236 holder->install(self.ptr());
237
238 // Set object identity
239 Tf_PySetPythonIdentity(held, self.ptr());
240
241 Policy::PostInstall(self, t, held.GetUniqueIdentifier());
242
243 } catch(...) {
244 Holder::deallocate(self.ptr(), memory); throw;
245 }
246
247}
248
249
250template <typename WeakPtr, typename P>
251struct _RefPtrFactoryConverter {
252 typedef std::remove_reference_t<P> Ptr;
253 bool convertible() const {
254 // FIXME should actually check here... It's not really horrible because
255 // if the conversion will fail, we'll just get a runtime error down
256 // below when we try to create the resulting object. That's basically
257 // what we want anyway.
258 return true;
259 }
260 PyObject *operator()(Ptr const &p) const {
261 typedef InstallPolicy<Ptr> Policy;
262 WeakPtr ptr(static_cast<typename WeakPtr::DataType *>
263 (get_pointer(p)));
264
265 // If resulting pointer is null, return None.
266 if (!ptr)
267 return bp::incref(Py_None);
268
269 // The to-python converter will set identity here.
270 object result(ptr);
271
272 Policy::PostInstall(result, p, ptr.GetUniqueIdentifier());
273 return bp::incref(result.ptr());
274 }
275 // Required for boost.python signature generator, in play when
276 // BOOST_PYTHON_NO_PY_SIGNATURES is undefined.
277 PyTypeObject const *get_pytype() const {
278 return boost::python::objects::registered_class_object(
279 boost::python::type_id<typename WeakPtr::DataType>()).get();
280 }
281};
282
283template <typename WeakPtr = void>
284struct RefPtrFactory {
285 template <typename FactoryResultPtr>
286 struct apply {
287 using WeakPtrType = std::conditional_t<
288 std::is_same<WeakPtr, void>::value,
290 WeakPtr>;
291 typedef _RefPtrFactoryConverter<WeakPtrType, FactoryResultPtr> type;
292 };
293};
294
295// EXTRA_ARITY is added for InitCtorWithVarArgs backwards compatability.
296// The previous BOOST_PP implementation didn't count the tuple and dict
297// against the arity limit while the new version does. A future change
298// should remove EXTRA_ARITY and increase TF_MAX_ARITY now that the
299// implementations are templated and no longer generated by BOOST_PP
300template <typename SIG, size_t EXTRA_ARITY = 0>
301struct CtorBase {
302 typedef SIG Sig;
303 using Traits = TfFunctionTraits<SIG*>;
304 static_assert(Traits::Arity <= (TF_MAX_ARITY + EXTRA_ARITY));
305
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
320template <typename SIG, size_t EXTRA_ARITY>
321SIG *CtorBase<SIG, EXTRA_ARITY>::_func = nullptr;
322
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;
328
329}
330
331
332template <typename T>
333Tf_MakePyConstructor::InitVisitor
334<typename Tf_MakePyConstructor::InitCtor<T> >
335TfMakePyConstructor(T *func, const std::string &doc = std::string()) {
336 // Instantiate to set static constructor pointer, then return the visitor.
337 Tf_MakePyConstructor::InitCtor<T> Ctor(func);
338 return Tf_MakePyConstructor::InitVisitor
339 <Tf_MakePyConstructor::InitCtor<T> >(doc);
340}
341
342template <typename T>
343Tf_MakePyConstructor::InitVisitor
344<typename Tf_MakePyConstructor::InitCtorWithBackReference<T> >
345TfMakePyConstructorWithBackReference(T *func, const std::string &doc = std::string()) {
346 // Instantiate to set static constructor pointer, then return the visitor.
347 Tf_MakePyConstructor::InitCtorWithBackReference<T> Ctor(func);
348 return Tf_MakePyConstructor::InitVisitor
349 <Tf_MakePyConstructor::InitCtorWithBackReference<T> >(doc);
350}
351
352template <typename T>
353Tf_MakePyConstructor::InitVisitor
354<typename Tf_MakePyConstructor::InitCtorWithVarArgs<T> >
355TfMakePyConstructorWithVarArgs(T *func, const std::string &doc = std::string()) {
356 // Instantiate to set static constructor pointer, then return the visitor.
357 Tf_MakePyConstructor::InitCtorWithVarArgs<T> Ctor(func);
358 return Tf_MakePyConstructor::InitVisitor
359 <Tf_MakePyConstructor::InitCtorWithVarArgs<T> >(doc);
360}
361
362template <typename T>
363Tf_MakePyConstructor::NewVisitor
364<typename Tf_MakePyConstructor::NewCtor<T> >
365TfMakePyNew(T *func, const std::string &doc = std::string()) {
366 // Instantiate to set static constructor pointer, then return the visitor.
367 Tf_MakePyConstructor::NewCtor<T> Ctor(func);
368 return Tf_MakePyConstructor::NewVisitor
369 <Tf_MakePyConstructor::NewCtor<T> >(doc);
370}
371
372template <typename T>
373Tf_MakePyConstructor::NewVisitor
374<typename Tf_MakePyConstructor::NewCtorWithClassReference<T> >
375TfMakePyNewWithClassReference(T *func, const std::string &doc = std::string()) {
376 // Instantiate to set static constructor pointer, then return the visitor.
377 Tf_MakePyConstructor::NewCtorWithClassReference<T> Ctor(func);
378 return Tf_MakePyConstructor::NewVisitor
379 <Tf_MakePyConstructor::NewCtorWithClassReference<T> >(doc);
380}
381
382
383template <typename T = void>
384struct TfPyRefPtrFactory : public Tf_MakePyConstructor::RefPtrFactory<T> {};
385
386template <typename T> struct Tf_PySequenceToListConverterRefPtrFactory;
387
391 template <typename T>
392 struct apply {
393 typedef Tf_PySequenceToListConverterRefPtrFactory<T> type;
394 };
395};
396
397// XXX: would be nicer to be able to compose converters with factory
398template <typename T>
399struct Tf_PySequenceToListConverterRefPtrFactory {
400 typedef std::remove_reference_t<T> SeqType;
401 bool convertible() const {
402 return true;
403 }
404 PyObject *operator()(T seq) const {
405 using namespace boost::python;
406
407 typedef typename Tf_MakePyConstructor::RefPtrFactory<>::
408 apply<typename SeqType::value_type>::type RefPtrFactory;
409
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))));
414 }
415 return boost::python::incref(l.ptr());
416 }
417 // Required for boost.python signature generator, in play when
418 // BOOST_PYTHON_NO_PY_SIGNATURES is undefined.
419 PyTypeObject const *get_pytype() const {
420 return &PyList_Type;
421 }
422};
423
424namespace Tf_MakePyConstructor {
425
426template <typename R, typename... Args>
427struct InitCtor<R(Args...)> : CtorBase<R(Args...)> {
428 typedef CtorBase<R(Args...)> Base;
429 typedef typename Base::Sig Sig;
430
431 InitCtor(Sig* func) { Base::SetFunc(func); }
432
433 template <typename CLS>
434 static bp::object init_callable() {
435 return bp::make_function(__init__<CLS>);
436 }
437
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()) ;
441 }
442
443 template <typename CLS>
444 static void __init__(object &self, Args... args) {
445 TfErrorMark m;
446 Install<CLS>(self, Base::_func(args...), m);
447 }
448};
449
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); }
455
456 template <class CLS>
457 static bp::object __new__(object &cls, Args... args) {
458 typedef typename CLS::metadata::held_type HeldType;
459 TfErrorMark m;
460 R r((Base::_func(args...)));
461 HeldType h((r));
462 if (TfPyConvertTfErrorsToPythonException(m))
463 bp::throw_error_already_set();
464 bp::object ret = TfPyObject(h);
465 if (TfPyIsNone(ret))
466 TfPyThrowRuntimeError("could not construct " +
467 ArchGetDemangled(typeid(HeldType)));
468
469 bp::detail::initialize_wrapper(ret.ptr(), get_pointer(h));
470 // make the object have the right class.
471 bp::setattr(ret, "__class__", cls);
472
473 InstallPolicy<R>::PostInstall(ret, r, h.GetUniqueIdentifier());
474 return ret;
475 }
476};
477
478template <typename R, typename... Args>
479struct InitCtorWithVarArgs<R(Args...)> :
480 // Pad the arity for backwards compatability
481 CtorBase<R(Args...), /*EXTRA_ARITY*/ 2> {
482 typedef CtorBase<R(Args...), /*EXTRA_ARITY*/ 2> Base;
483 typedef typename Base::Sig Sig;
484
485 // Ideally, Arity would be pulled from Base::Traits, but
486 // compilers have inconsistently allowed this. Redefine
487 // Arity as a workaround for now.
488 using Arity = TfMetaLength<Args...>;
489
490 InitCtorWithVarArgs(Sig *func) { Base::SetFunc(func); }
491
492 static_assert((Arity::value >= 2) &&
493 (std::is_same_v<
494 const bp::tuple&,
495 typename Base::Traits::template NthArg<(Arity::value-2)>>) &&
496 (std::is_same_v<
497 const bp::dict&,
498 typename Base::Traits::template NthArg<(Arity::value-1)>>),
499 "InitCtorWithVarArgs requires a function of form "
500 "(..., const tuple&, const dict&)");
501
502 template <typename CLS>
503 static bp::object init_callable() {
504 // Specify min_args as 1 to account for just the 'self' argument.
505 // min_args really should be N + 1. However, we want to do this check
506 // ourselves later so we can emit a better error message.
507 return bp::raw_function(__init__<CLS>, /* min_args = */ 1);
508 }
509
510 template <typename CLS, typename Options>
511 static bp::object init_callable(Options& options) {
512 // XXX: Note ignoring options.keywords(), current implementation can't
513 // handle that correctly.
514 return bp::raw_function(
515 bp::make_function(__init__<CLS>, options.policies()),
516 /* min_args = */ 1);
517 }
518
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...>) {
523 TfErrorMark m;
524
525 // We know that there are at least two args because the specialization only
526 // matches against (..., *args, **kwargs)
527 const unsigned int expectedNamedArgs = Arity::value - 2;
528 // self is included in the tuple, so it should always be at least 1
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())...
534 }};
535 std::string joinedTypes = TfStringJoin(
536 std::begin(positionalArgTypes),
537 std::end(positionalArgTypes), ", "
538 );
539 if (!joinedTypes.empty()) {
540 joinedTypes += ", ";
541 }
542 // User didn't provide enough positional arguments for the factory
543 // function. Complain.
546 "Arguments to __init__ did not match C++ signature:\n"
547 "\t__init__(%s...)", joinedTypes.c_str()
548 )
549 );
550 return bp::object();
551 }
552
553 Install<CLS>(
554 // self object for new instance is the first arg to __init__
555 args[0],
556 Base::_func(
557 bp::extract<
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),
561 m);
562
563 return bp::object();
564 }
565
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>());
571
572 }
573};
574
575// This is a variant of Ctor which includes a back reference to self
576// (the Python object being initialized) in the args passed to the
577// constructor. This is used to expose the factory methods for classes
578// which we expect to subclass in Python. When the constructor is called,
579// it can examine self and initialize itself appropriately.
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); }
586
587 template <typename CLS>
588 static bp::object init_callable() {
589 return bp::make_function(__init__<CLS>);
590 }
591
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());
595 }
596
597 template <typename CLS>
598 static void __init__(SelfRef self, Args... args) {
599 TfErrorMark m;
600 Install<CLS>(self, Base::_func(self, args...), m);
601 }
602};
603
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); }
610
611 template <class CLS>
612 static bp::object __new__(ClsRef cls, Args... args) {
613 typedef typename CLS::metadata::held_type HeldType;
614 TfErrorMark m;
615 R r(Base::_func(cls, args...));
616 HeldType h(r);
617 if (TfPyConvertTfErrorsToPythonException(m))
618 bp::throw_error_already_set();
619 bp::object ret = TfPyObject(h);
620 if (TfPyIsNone(ret))
621 TfPyThrowRuntimeError("could not construct " +
622 ArchGetDemangled(typeid(HeldType)));
623
624 bp::detail::initialize_wrapper(ret.ptr(), get_pointer(h));
625 // make the object have the right class.
626 bp::setattr(ret, "__class__", cls);
627
628 InstallPolicy<R>::PostInstall(ret, r, h.GetUniqueIdentifier());
629 return ret;
630 }
631};
632}
633
634PXR_NAMESPACE_CLOSE_SCOPE
635
636#endif // PXR_BASE_TF_MAKE_PY_CONSTRUCTOR_H
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.
Definition: pyUtils.h:144
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.
Definition: errorMark.h:65
Reference-counted smart pointer utility class.
Definition: refPtr.h:601
Pointer storage with deletion detection.
Definition: weakPtr.h:145
Demangle C++ typenames generated by the typeid() facility.
std::string ArchGetDemangled()
Return demangled RTTI generated-type name.
Definition: demangle.h:103
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
Definition: diagnostic.h:85
std::string TfStringJoin(ForwardIterator begin, ForwardIterator end, const char *separator=" ")
Concatenates the strings (begin, end), with default separator.
Definition: stringUtils.h:374
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...
Reference counting.
Definitions of basic string utilities in tf.
Pointer storage with deletion detection.