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 #include "pxr/pxr.h"
26 
27 #include "pxr/base/tf/declarePtrs.h"
28 #include "pxr/base/tf/enum.h"
29 #include "pxr/base/tf/error.h"
30 #include "pxr/base/tf/makePyConstructor.h"
31 #include "pxr/base/tf/notice.h"
32 #include "pxr/base/tf/pyCall.h"
33 #include "pxr/base/tf/pyClassMethod.h"
34 #include "pxr/base/tf/pyEnum.h"
35 #include "pxr/base/tf/pyFunction.h"
36 #include "pxr/base/tf/pyPtrHelpers.h"
37 #include "pxr/base/tf/pyResultConversions.h"
38 #include "pxr/base/tf/refPtr.h"
39 #include "pxr/base/tf/staticData.h"
40 #include "pxr/base/tf/weakPtr.h"
41 
42 #include "pxr/base/tf/pyArg.h"
43 #include "pxr/base/tf/pyPolymorphic.h"
44 
45 #include <boost/assign/list_of.hpp>
46 #include <boost/python/class.hpp>
47 #include <boost/python/def.hpp>
48 #include <boost/python/list.hpp>
49 #include <boost/python/make_constructor.hpp>
50 #include <boost/python/manage_new_object.hpp>
51 #include <boost/python/pure_virtual.hpp>
52 #include <boost/python/register_ptr_to_python.hpp>
53 #include <boost/python/return_arg.hpp>
54 #include <boost/python/tuple.hpp>
55 
56 #include <boost/smart_ptr.hpp>
57 
58 #include <functional>
59 #include <string>
60 #include <vector>
61 
62 using namespace boost::python;
63 using std::string;
64 using std::vector;
65 
66 PXR_NAMESPACE_USING_DIRECTIVE
67 
68 PXR_NAMESPACE_OPEN_SCOPE
69 
70 // Base
71 typedef TfWeakPtr<class Tf_TestBase> Tf_TestBasePtr;
72 typedef TfWeakPtr<const class Tf_TestBase> Tf_TestBaseConstPtr;
73 typedef TfRefPtr<class Tf_TestBase> Tf_TestBaseRefPtr;
74 class Tf_TestBase : public TfRefBase, public TfWeakBase {
75   public:
~Tf_TestBase()76     virtual ~Tf_TestBase() {}
77     virtual string Virtual() const = 0;
78     virtual void Virtual2() const = 0;
79     virtual void Virtual3(string const &arg) = 0;
80 
Virtual4() const81     virtual string Virtual4() const { return "cpp base"; }
82 
VirtualCaller() const83     string VirtualCaller() const { return UnwrappedVirtual(); }
84     virtual string UnwrappedVirtual() const = 0;
85   protected:
Tf_TestBase()86     Tf_TestBase() {}
87 };
88 
89 // Derived
90 typedef TfWeakPtr<class Tf_TestDerived> Tf_TestDerivedPtr;
91 typedef TfRefPtr<class Tf_TestDerived> Tf_TestDerivedRefPtr;
92 class Tf_TestDerived : public Tf_TestBase {
93   public:
94     // CODE_COVERAGE_OFF_GCOV_BUG  woot
~Tf_TestDerived()95     virtual ~Tf_TestDerived() {}
96     // CODE_COVERAGE_ON_GCOV_BUG
Virtual() const97     virtual string Virtual() const { return "cpp derived"; }
Virtual2() const98     virtual void Virtual2() const {}
Virtual3(string const & arg)99     virtual void Virtual3(string const &arg) {
100         printf("cpp derived v3! : %s\n", arg.c_str());
101     }
UnwrappedVirtual() const102     virtual string UnwrappedVirtual() const { return "cpp derived"; }
103 
Factory()104     static Tf_TestDerivedRefPtr Factory() {
105         return TfCreateRefPtr(new Tf_TestDerived());
106     }
NullFactory()107     static Tf_TestDerivedRefPtr NullFactory() {
108         return Tf_TestDerivedRefPtr();
109     }
110   protected:
Tf_TestDerived()111     Tf_TestDerived() {}
112 };
113 
114 
TakesConstBase(Tf_TestBaseConstPtr base)115 static string TakesConstBase(Tf_TestBaseConstPtr base) {
116     return base->Virtual();
117 }
118 
ReturnsConstBase(Tf_TestBaseConstPtr base)119 static Tf_TestBaseConstPtr ReturnsConstBase(Tf_TestBaseConstPtr base) {
120     return base;
121 }
122 
ReturnsBase(Tf_TestBasePtr base)123 static Tf_TestBasePtr ReturnsBase(Tf_TestBasePtr base) {
124     return base;
125 }
126 
ReturnsBaseRefPtr(Tf_TestBasePtr base)127 static Tf_TestBaseRefPtr ReturnsBaseRefPtr(Tf_TestBasePtr base) {
128     return base;
129 }
130 
TakesBase(Tf_TestBasePtr base)131 static tuple TakesBase(Tf_TestBasePtr base) {
132     base->Virtual3("hello from TakesConstBase");
133     base->Virtual2();
134     bool isDerived = TfDynamic_cast<Tf_TestDerivedPtr>(base);
135     return boost::python::make_tuple(isDerived, base->Virtual());
136 }
137 
TakesDerived(Tf_TestDerivedPtr derived)138 static string TakesDerived(Tf_TestDerivedPtr derived) {
139     derived->Virtual3("A call to virtual 3!");
140     return derived->Virtual();
141 }
142 
TakesReference(Tf_TestDerivedRefPtr const & derived)143 static void TakesReference(Tf_TestDerivedRefPtr const &derived) {}
144 
TF_REGISTRY_FUNCTION(TfType)145 TF_REGISTRY_FUNCTION(TfType)
146 {
147     TfType::Define< Tf_TestBase >();
148     TfType::Define< Tf_TestDerived, TfType::Bases< Tf_TestBase > >();
149 }
150 
151 ////////////////////////////////
152 
153 template <typename T = Tf_TestBase>
154 struct polymorphic_Tf_TestBase : public T, public TfPyPolymorphic<T> {
155     typedef polymorphic_Tf_TestBase This;
Virtualpolymorphic_Tf_TestBase156     virtual string Virtual() const {
157         return this->template CallPureVirtual<string>("Virtual")();
158     }
Virtual2polymorphic_Tf_TestBase159     virtual void Virtual2() const {
160         return this->template CallPureVirtual<void>("Virtual2")();
161     }
Virtual3polymorphic_Tf_TestBase162     virtual void Virtual3(string const &arg) {
163         return this->template CallPureVirtual<void>("Virtual3")(arg);
164     }
default_Virtual4polymorphic_Tf_TestBase165     string default_Virtual4() const { return T::Virtual4(); }
Virtual4polymorphic_Tf_TestBase166     virtual string Virtual4() const {
167         return this->CallVirtual("Virtual4", &This::default_Virtual4)();
168     }
UnwrappedVirtualpolymorphic_Tf_TestBase169     virtual string UnwrappedVirtual() const {
170         return this->template CallPureVirtual<string>("UnwrappedVirtual")();
171     }
172 
173 };
174 
175 static string
callVirtual(Tf_TestBase * base)176 callVirtual(Tf_TestBase * base)
177 {
178     return base->VirtualCaller();
179 }
180 
181 template <typename T = Tf_TestDerived>
182 struct polymorphic_Tf_TestDerived : public polymorphic_Tf_TestBase<T> {
183     typedef polymorphic_Tf_TestDerived This;
default_Virtualpolymorphic_Tf_TestDerived184     string default_Virtual() const { return T::Virtual(); }
Virtualpolymorphic_Tf_TestDerived185     virtual string Virtual() const {
186         return this->CallVirtual("Virtual", &This::default_Virtual)();
187     }
default_Virtual2polymorphic_Tf_TestDerived188     void default_Virtual2() const { return T::Virtual2(); }
Virtual2polymorphic_Tf_TestDerived189     virtual void Virtual2() const {
190         return this->CallVirtual("Virtual2", &This::default_Virtual2)();
191     }
default_Virtual3polymorphic_Tf_TestDerived192     void default_Virtual3(string const &arg) { return T::Virtual3(arg); }
Virtual3polymorphic_Tf_TestDerived193     virtual void Virtual3(string const &arg) {
194         return this->CallVirtual("Virtual3", &This::default_Virtual3)(arg);
195     }
196 };
197 
198 
199 template <typename T>
200 static TfRefPtr<T>
__Ref_init__()201 __Ref_init__() {
202     return TfCreateRefPtr(new T);
203 }
204 
205 
206 enum TfPyTestErrorCodes {
207     TF_TEST_ERROR_1,
208     TF_TEST_ERROR_2
209 };
210 
TF_REGISTRY_FUNCTION(TfEnum)211 TF_REGISTRY_FUNCTION(TfEnum) {
212     TF_ADD_ENUM_NAME(TF_TEST_ERROR_1);
213     TF_ADD_ENUM_NAME(TF_TEST_ERROR_2);
214 }
215 
mightRaise(bool raise)216 static void mightRaise(bool raise) {
217     if (raise) {
218         TF_ERROR(TF_TEST_ERROR_1, "Test error 1!");
219         TF_ERROR(TF_TEST_ERROR_2, "Test error 2!");
220     }
221 }
222 
223 
doErrors()224 static void doErrors() {
225     TF_ERROR(TF_TEST_ERROR_1, "TestError 1!");
226     TF_ERROR(TF_TEST_ERROR_2, "TestError 2!");
227     TF_CODING_ERROR("nonfatal coding error %d", 1);
228     TF_RUNTIME_ERROR("a random runtime error %d", 2);
229     TF_WARN("diagnostic warning %d", 3);
230     TF_STATUS("status message %d", 4);
231 };
232 
233 
234 struct _TestStaticMethodError {
Error_TestStaticMethodError235     static void Error() {
236         TF_ERROR(TF_TEST_ERROR_1, "Test error 1!");
237     }
238 };
239 
240 
241 
242 ////////////////////////////////
243 // Enums
244 
245 enum Tf_TestEnum {
246     Tf_Alpha = 3,
247     Tf_Bravo,
248     Tf_Charlie,
249     Tf_Delta,
250 };
251 
252 enum class Tf_TestScopedEnum {
253     Hydrogen = 1,
254     Helium,
255     Lithium,
256     Beryllium,
257     Boron
258 };
259 
260 struct Tf_Enum {
261     enum TestEnum2 {
262         One = 1,
263         Two,
264         Three,
265     };
266     enum TestEnum3 {
267         _Alpha = 100,
268         _Beta,
269         _Gamma,
270     };
271     enum class TestScopedEnum {
272         Alef = 300,
273         Bet,
274         Gimel
275     };
276 };
277 
278 
TF_REGISTRY_FUNCTION(TfEnum)279 TF_REGISTRY_FUNCTION(TfEnum) {
280     TF_ADD_ENUM_NAME(Tf_Alpha, "A");
281     TF_ADD_ENUM_NAME(Tf_Bravo, "B");
282     TF_ADD_ENUM_NAME(Tf_Charlie, "C");
283     TF_ADD_ENUM_NAME(Tf_Delta, "D");
284 }
285 
TF_REGISTRY_FUNCTION(TfEnum)286 TF_REGISTRY_FUNCTION(TfEnum) {
287     TF_ADD_ENUM_NAME(Tf_Enum::One);
288     TF_ADD_ENUM_NAME(Tf_Enum::Two);
289     TF_ADD_ENUM_NAME(Tf_Enum::Three);
290 }
291 
TF_REGISTRY_FUNCTION(TfEnum)292 TF_REGISTRY_FUNCTION(TfEnum) {
293     TF_ADD_ENUM_NAME(Tf_Enum::_Alpha);
294     TF_ADD_ENUM_NAME(Tf_Enum::_Beta);
295     TF_ADD_ENUM_NAME(Tf_Enum::_Gamma);
296 }
297 
TF_REGISTRY_FUNCTION(TfEnum)298 TF_REGISTRY_FUNCTION(TfEnum) {
299     TF_ADD_ENUM_NAME(Tf_Enum::TestScopedEnum::Alef);
300     TF_ADD_ENUM_NAME(Tf_Enum::TestScopedEnum::Bet);
301     TF_ADD_ENUM_NAME(Tf_Enum::TestScopedEnum::Gimel);
302 }
303 
TF_REGISTRY_FUNCTION(TfEnum)304 TF_REGISTRY_FUNCTION(TfEnum) {
305     TF_ADD_ENUM_NAME(Tf_TestScopedEnum::Hydrogen, "H");
306     TF_ADD_ENUM_NAME(Tf_TestScopedEnum::Lithium, "Li");
307     TF_ADD_ENUM_NAME(Tf_TestScopedEnum::Beryllium, "Be");
308     TF_ADD_ENUM_NAME(Tf_TestScopedEnum::Boron, "B");
309 }
310 
takesTfEnum(TfEnum const & e)311 static void takesTfEnum(TfEnum const &e) {
312     printf("got enum '%s' with value '%d'\n",
313            TfEnum::GetName(e).c_str(), e.GetValueAsInt());
314 }
315 
returnsTfEnum(TfEnum const & e)316 static TfEnum returnsTfEnum(TfEnum  const &e) {
317     printf("returning enum '%s' with value '%d'\n",
318            TfEnum::GetName(e).c_str(), e.GetValueAsInt());
319     return e;
320 }
321 
takesTestEnum(Tf_TestEnum e)322 static void takesTestEnum(Tf_TestEnum e) {
323     printf("got enum %d with name '%s'\n",
324            (int)e, TfEnum::GetName(e).c_str());
325 }
326 
takesTestEnum2(Tf_Enum::TestEnum2 e)327 static void takesTestEnum2(Tf_Enum::TestEnum2 e) {
328     printf("got enum %d with name '%s'\n",
329            (int)e, TfEnum::GetName(e).c_str());
330 }
331 
registerInvalidEnum(object & obj)332 static void registerInvalidEnum(object &obj) {
333     scope s = obj;
334 
335     // This should be used to produce a coding error. The _Alpha value will
336     // conflict with the corresponding (sanitized) enum name that was already
337     // wrapped for Tf_TestEnum.
338     TfPyWrapEnum<Tf_Enum::TestEnum3>();
339 }
340 
341 
342 
343 ////////////////////////////////
344 // Function callback stuff.
345 
callback(std::function<void ()> const & f)346 static void callback(std::function<void ()> const &f) {
347     f();
348 }
349 
stringCallback(std::function<string ()> const & f)350 static string stringCallback(std::function<string ()> const &f) {
351     return f();
352 }
353 
stringStringCallback(std::function<string (string)> const & f)354 static string stringStringCallback(std::function<string (string)> const &f) {
355     return f("c++ is calling...");
356 }
357 
callUnboundInstance(std::function<string (string)> const & f,string const & str)358 static string callUnboundInstance(std::function<string (string)> const &f,
359                                   string const &str) {
360     return f(str);
361 }
362 
363 static TfStaticData<std::function<string ()> > _testCallback;
364 
setTestCallback(std::function<string ()> const & func)365 static void setTestCallback(std::function<string ()> const &func) {
366     *_testCallback = func;
367 }
368 
invokeTestCallback()369 static string invokeTestCallback() {
370     if (*_testCallback)
371         return (*_testCallback)();
372     return string();
373 }
374 
375 
376 ////////////////////////////////
377 // Sending notice from C++ sender
378 
sendTfNoticeWithSender(Tf_TestBasePtr const & base)379 static void sendTfNoticeWithSender(Tf_TestBasePtr const &base) {
380     TfNotice().Send(base);
381 }
382 
383 ////////////////////////////////
384 // TfPyClassMethod()
385 
386 class Tf_ClassWithClassMethod {
387 public:
Tf_ClassWithClassMethod()388     Tf_ClassWithClassMethod() {}
~Tf_ClassWithClassMethod()389     virtual ~Tf_ClassWithClassMethod() {}
390 };
391 
392 static tuple
_TestClassMethod(object & pyClassObj,const object & callable)393 _TestClassMethod( object & pyClassObj, const object & callable )
394 {
395     return boost::python::make_tuple(
396         pyClassObj, TfPyCall<object>(callable)() );
397 }
398 
399 // ////////////////////////////////
400 // // keywords and overloading.
401 
402 
403 // static void f1(string const &a1, int x, int y) {
404 //     printf("f1 with %s, %d, %d\n", a1.c_str(), x, y);
405 // }
406 
407 // static void f2(string const &a1, string const &a2, int x, int y) {
408 //     printf("f2 with %s, %s, %d, %d\n", a1.c_str(), a2.c_str(), x, y);
409 // }
410 
411 static std::string
_ThrowCppException()412 _ThrowCppException()
413 {
414     // Take the lock.
415     TfPyLock lock;
416     // Release the lock.
417     lock.BeginAllowThreads();
418     // Generate an exception.
419     throw std::logic_error("error");
420     // Not necessary, but shows usage.
421     lock.EndAllowThreads();
422     return std::string();
423 }
424 
TakesVecVecString(std::vector<std::vector<std::string>> arg)425 static size_t TakesVecVecString(std::vector<std::vector<std::string> > arg)
426 {
427     return arg.size();
428 }
429 
430 ////////////////////////////////
431 // TfPyArg and TfMakeConstructorWithVarArgs
432 
433 TF_DECLARE_WEAK_AND_REF_PTRS(Tf_ClassWithVarArgInit);
434 
435 class Tf_ClassWithVarArgInit : public TfRefBase, public TfWeakBase
436 {
437 public:
438     bool allowExtraArgs;
439     tuple args;
440     dict kwargs;
441 };
442 
443 static Tf_ClassWithVarArgInitRefPtr
_MakeClassWithVarArgInit(bool allowExtraArgs,const tuple & args,const dict & kwargs)444 _MakeClassWithVarArgInit(bool allowExtraArgs,
445                          const tuple& args, const dict& kwargs)
446 {
447     // To Python consumer, this class has 3 explicit optional arguments, named
448     // 'a', 'b', and 'c'.
449     const TfPyArgs optionalArgs = boost::assign::list_of<>
450         (TfPyArg("a", ""))
451         (TfPyArg("b", ""))
452         (TfPyArg("c", ""));
453 
454     const std::pair<tuple, dict> params =
455         TfPyProcessOptionalArgs(args, kwargs, optionalArgs, allowExtraArgs);
456 
457     Tf_ClassWithVarArgInitRefPtr rval =
458         TfCreateRefPtr(new Tf_ClassWithVarArgInit);
459     rval->allowExtraArgs = allowExtraArgs;
460     rval->args = params.first;
461     rval->kwargs = params.second;
462 
463     return rval;
464 }
465 
466 
467 ////////////////////////////////
468 // Bytearray conversion
469 
470 static object
_ConvertByteListToByteArray(const list & byteList)471 _ConvertByteListToByteArray(const list& byteList)
472 {
473     std::vector<char> inputList;
474     for (int i = 0; i < len(byteList); ++i) {
475         inputList.push_back(extract<char>(byteList[i]));
476     }
477 
478     return TfPyCopyBufferToByteArray(inputList.data(), inputList.size());
479 }
480 
481 
482 PXR_NAMESPACE_CLOSE_SCOPE
483 
wrapTf_TestTfPython()484 void wrapTf_TestTfPython()
485 {
486 
487 //      def("f", f1, (arg("x")=3, arg("y")=4));
488 //      def("f", f2, (arg("x")=5, arg("y")=6));
489 
490     def("_ConvertByteListToByteArray", _ConvertByteListToByteArray);
491 
492     def("_sendTfNoticeWithSender", sendTfNoticeWithSender);
493 
494     def("_callback", callback);
495     def("_stringCallback", stringCallback);
496     TfPyFunctionFromPython<string (string)>();
497     def("_stringStringCallback", stringStringCallback);
498     def("_setTestCallback", setTestCallback);
499     def("_invokeTestCallback", invokeTestCallback);
500     def("_callUnboundInstance", callUnboundInstance);
501 
502     TfPyWrapEnum<Tf_TestEnum>();
503 
504     {
505         scope enumScope = class_<Tf_Enum>("_Enum", no_init);
506         TfPyWrapEnum<Tf_Enum::TestEnum2>();
507         TfPyWrapEnum<Tf_Enum::TestScopedEnum>();
508     }
509 
510     TfPyWrapEnum<Tf_TestScopedEnum>();
511 
512     def("_takesTfEnum", takesTfEnum);
513     def("_returnsTfEnum", returnsTfEnum);
514     def("_takesTestEnum", takesTestEnum);
515     def("_takesTestEnum2", takesTestEnum2);
516     def("_registerInvalidEnum", registerInvalidEnum);
517 
518 
519     def("_doErrors", doErrors);
520 
521     def("_mightRaise", mightRaise);
522 
523     def("_ThrowCppException", _ThrowCppException);
524 
525     def("_TakesVecVecString", TakesVecVecString);
526 
527     class_<_TestStaticMethodError>("_TestStaticMethodError", no_init)
528         .def("Error", &_TestStaticMethodError::Error)
529         .staticmethod("Error")
530         ;
531 
532     def("_TakesReference", TakesReference);
533     def("_TakesConstBase", TakesConstBase);
534     def("_ReturnsConstBase", ReturnsConstBase);
535     def("_TakesBase", TakesBase);
536     def("_ReturnsBase", ReturnsBase);
537     def("_ReturnsBaseRefPtr", ReturnsBaseRefPtr);
538     def("_TakesDerived", TakesDerived);
539 
540     def("_DerivedFactory", Tf_TestDerived::Factory,
541         return_value_policy<TfPyRefPtrFactory<> >());
542 
543     def("_DerivedNullFactory", Tf_TestDerived::NullFactory,
544         return_value_policy<TfPyRefPtrFactory<> >());
545 
546     class_<polymorphic_Tf_TestBase<>,
547         TfWeakPtr<polymorphic_Tf_TestBase<> >, boost::noncopyable>
548         ("_TestBase", no_init)
549         .def(TfPyRefAndWeakPtr())
550         .def(TfMakePyConstructor(__Ref_init__<polymorphic_Tf_TestBase<> >))
551         .def("Virtual", pure_virtual(&Tf_TestBase::Virtual))
552         .def("Virtual2", pure_virtual(&Tf_TestBase::Virtual2))
553         .def("Virtual3", pure_virtual(&Tf_TestBase::Virtual3))
554         .def("Virtual4", &Tf_TestBase::Virtual4,
555              &polymorphic_Tf_TestBase<>::default_Virtual4)
556         .def("TestCallVirtual", &callVirtual)
557         ;
558 
559     class_<polymorphic_Tf_TestDerived<>,
560         TfWeakPtr<polymorphic_Tf_TestDerived<> >,
561         bases<Tf_TestBase>, boost::noncopyable>
562         ("_TestDerived", no_init)
563         .def(TfPyRefAndWeakPtr())
564         .def("__init__",
565              TfMakePyConstructor(__Ref_init__<polymorphic_Tf_TestDerived<> >))
566         .def("Virtual", &Tf_TestDerived::Virtual,
567              &polymorphic_Tf_TestDerived<>::default_Virtual)
568         .def("Virtual2", &Tf_TestDerived::Virtual2,
569              &polymorphic_Tf_TestDerived<>::default_Virtual2)
570         .def("Virtual3", &Tf_TestDerived::Virtual3,
571              &polymorphic_Tf_TestDerived<>::default_Virtual3)
572         ;
573 
574     class_<Tf_ClassWithClassMethod>("_ClassWithClassMethod", init<>() )
575         .def("Test", &_TestClassMethod)
576         .def(TfPyClassMethod("Test"))
577         ;
578 
579     class_<Tf_ClassWithVarArgInit, Tf_ClassWithVarArgInitPtr>
580         ("_ClassWithVarArgInit", no_init)
581         .def(TfPyRefAndWeakPtr())
582         .def(TfMakePyConstructorWithVarArgs(&_MakeClassWithVarArgInit))
583         .add_property("allowExtraArgs",
584                       &Tf_ClassWithVarArgInit::allowExtraArgs)
585         .add_property("args", &Tf_ClassWithVarArgInit::args)
586         .add_property("kwargs", &Tf_ClassWithVarArgInit::kwargs)
587         ;
588 
589 }
590 
591 TF_REFPTR_CONST_VOLATILE_GET(Tf_ClassWithVarArgInit)
592 TF_REFPTR_CONST_VOLATILE_GET(Tf_TestBase)
593 TF_REFPTR_CONST_VOLATILE_GET(Tf_TestDerived)
594 TF_REFPTR_CONST_VOLATILE_GET(polymorphic_Tf_TestBase<class Tf_TestBase>)
595 TF_REFPTR_CONST_VOLATILE_GET(polymorphic_Tf_TestDerived<class Tf_TestDerived>)
596