// // Copyright 2016 Pixar // // Licensed under the Apache License, Version 2.0 (the "Apache License") // with the following modification; you may not use this file except in // compliance with the Apache License and the following modification to it: // Section 6. Trademarks. is deleted and replaced with: // // 6. Trademarks. This License does not grant permission to use the trade // names, trademarks, service marks, or product names of the Licensor // and its affiliates, except as required to comply with Section 4(c) of // the License and to reproduce the content of the NOTICE file. // // You may obtain a copy of the Apache License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the Apache License with the above modification is // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the Apache License for the specific // language governing permissions and limitations under the Apache License. // #include "pxr/pxr.h" #include "pxr/base/tf/type.h" #include "pxr/base/tf/wrapTypeHelpers.h" #include "pxr/base/tf/hash.h" #include "pxr/base/tf/makePyConstructor.h" #include "pxr/base/tf/py3Compat.h" #include "pxr/base/tf/pyContainerConversions.h" #include "pxr/base/tf/pyObjectFinder.h" #include "pxr/base/tf/pyPtrHelpers.h" #include "pxr/base/tf/pyResultConversions.h" #include "pxr/base/tf/iterator.h" #include "pxr/base/tf/weakBase.h" #include #include #include #include #include #include #include #include #include using namespace boost::python; using namespace std; PXR_NAMESPACE_USING_DIRECTIVE namespace { //////////////////////////////////////////////////////////////////////// // Python -> C++ TfType conversion // Provide conversion of either string typenames or Python class objects // to TfTypes. static TfType _GetTfTypeFromPython(PyObject *p) { if (TfPyString_Check(p)) return TfType::FindByName( extract(p)() ); else return TfType::FindByPythonClass( object(borrowed(p)) ); } // A from-Python converter that uses the _GetTfTypeFromPython function. struct _TfTypeFromPython { _TfTypeFromPython() { converter::registry::insert(&_Convertible, &_Construct, type_id()); } private: static void* _Convertible(PyObject *p) { if (_GetTfTypeFromPython(p).IsUnknown()) { TfPyThrowTypeError( TfStringPrintf("cannot convert %s to TfType; has that type " "been defined as a TfType?", TfPyRepr( object(borrowed(p) ) ).c_str() ) ); } return p; } static void _Construct(PyObject *p, converter::rvalue_from_python_stage1_data *data) { void* const storage = ((converter::rvalue_from_python_storage *)data)->storage.bytes; TfType type = _GetTfTypeFromPython(p); new (storage) TfType(type); data->convertible = storage; } }; //////////////////////////////////////////////////////////////////////// // Base C++ class to test Python subclassing. #if 0 class Tf_TestCppBase : public TfWeakBase { public: virtual ~Tf_TestCppBase() {} // virtual int TestVirtual() = 0; }; // Polymorphic wrapper. class PolymorphicTestCppBase : public Tf_TestCppBase, public TfType::PyPolymorphicBase { public: static TfWeakPtr New() { // XXX leaks. return TfCreateWeakPtr(new PolymorphicTestCppBase()); } }; TF_REGISTRY_FUNCTION(TfType) { TfType::Define(); } // Helper function to test TfType::Find(obj) on Python subclasses of // wrapped C++ classes. TfType _TestFindType( Tf_TestCppBase & cppBase ) { printf("_TestFindType with '%s'\n", ArchGetDemangled(typeid(cppBase)).c_str()); return TfType::Find(cppBase); } static void wrapTestCppBase() { typedef Tf_TestCppBase This; typedef PolymorphicTestCppBase PolymorphicThis; class_, boost::noncopyable> ("TestCppBase", no_init) .def( TfPyWeakPtr() ) .def( TfMakePyConstructor(&PolymorphicThis::New)) ; def("_TestFindType", ::_TestFindType); } #endif //////////////////////////////////////////////////////////////////////// static string _Repr( const TfType & t ) { if (t.IsUnknown()) { return TF_PY_REPR_PREFIX + "Type.Unknown"; } else { // Use TfPyRepr() to get Python-style escaping. return TF_PY_REPR_PREFIX + "Type.FindByName(" + TfPyRepr(t.GetTypeName()) + ")"; } } static size_t _TypeHash( const TfType & t ) { return TfHash()(t); } // These methods exist just to distinguish from equivalently named templates. static bool _IsA( const TfType & t1, const TfType & t2 ) { return t1.IsA(t2); } static TfType _GetRoot() { return TfType::GetRoot(); } static TfType _FindDerivedByName( TfType &t, const std::string & name ) { return t.FindDerivedByName(name); } static TfType _FindByName( const std::string & name ) { return TfType::FindByName(name); } // Convert out parameter to return value static std::vector _GetAllDerivedTypes( TfType & t ) { set types; t.GetAllDerivedTypes(&types); return vector( types.begin(), types.end() ); } // Convert out parameter to return value static std::vector _GetAllAncestorTypes( TfType & t ) { vector types; t.GetAllAncestorTypes(&types); return types; } static TfType _FindByPythonClass(const boost::python::object & classObj) { // Guard against the potentially common mistake of calling Find() with a // string typename. Rather than returning the unknown type (assuming // of course that we never declare Python's string type as a TfType), // we instead direct the caller to use FindByName(). if (TfPyString_Check(classObj.ptr())) { TfPyThrowTypeError("String passed to Tf.Type.Find() -- you probably " "want Tf.Type.FindByName() instead"); } return TfType::FindByPythonClass(classObj); } static void _DumpTypeHierarchyRecursive( TfType t, int depth=0 ) { std::string indent; for (int i=0; i < depth; ++i) indent += " "; printf("%s%s\n", indent.c_str(), t.GetTypeName().c_str()); std::vector derived = t.GetDirectlyDerivedTypes(); TF_FOR_ALL(it, derived) { _DumpTypeHierarchyRecursive( *it, depth+1 ); } } static void _DumpTypeHierarchy( TfType t ) { _DumpTypeHierarchyRecursive(t); } } // anonymous namespace void wrapType() { typedef TfType This; class_ classDef( "Type" ); classDef .def( init() ) .def(!self) .def( self == self ) .def( self != self ) .def( self < self ) .def( self > self ) .def( self <= self ) .def( self >= self ) .def( "__repr__", &_Repr) .def( "__hash__", &_TypeHash) .def( "GetRoot", &_GetRoot) .staticmethod("GetRoot") .def( "Find", &_FindByPythonClass) .staticmethod("Find") .def( "FindByName", &_FindByName) .staticmethod("FindByName") .def("FindDerivedByName", &_FindDerivedByName) .def("IsA", &_IsA ) .add_property("isUnknown", &This::IsUnknown) .add_property("isEnumType", &This::IsEnumType) .add_property("isPlainOldDataType", &This::IsPlainOldDataType) .add_property("sizeof", &This::GetSizeof) .add_property("typeName", make_function( &This::GetTypeName, return_value_policy() ) ) .add_property("pythonClass", &This::GetPythonClass) .add_property("baseTypes", make_function( &This::GetBaseTypes, return_value_policy< TfPySequenceToTuple >() ) ) .add_property("derivedTypes", make_function( &This::GetDirectlyDerivedTypes, return_value_policy< TfPySequenceToTuple >() ) ) .def("GetAliases", &This::GetAliases, return_value_policy< TfPySequenceToTuple >() ) .def("GetAllDerivedTypes", &_GetAllDerivedTypes, return_value_policy< TfPySequenceToTuple >() ) .def("GetAllAncestorTypes", &_GetAllAncestorTypes, return_value_policy< TfPySequenceToTuple >() ) .def("Define", &TfType_DefinePythonTypeAndBases) .staticmethod("Define") .def("AddAlias", (void (TfType::*)(TfType, const std::string &) const) &This::AddAlias) .def("_DumpTypeHierarchy", &_DumpTypeHierarchy, "_DumpTypeHierarchy(TfType): " "Diagnostic method to print the type hierarchy beneath a given " "TfType.") .staticmethod("_DumpTypeHierarchy") ; // Create an attribute to use for the repr() for the Unknown type. // We do not wrap the GetUnknownType() method, favoring this instead. classDef.attr("Unknown") = TfType(); // Register from-python conversions. _TfTypeFromPython(); // Handle a sequence of TfTypes TfPyContainerConversions::from_python_sequence< std::vector< TfType >, TfPyContainerConversions::variable_capacity_policy >(); TfPyContainerConversions::from_python_sequence< std::set , TfPyContainerConversions::set_policy >(); #if 0 wrapTestCppBase(); #endif }