32 #include "pxr/base/tf/api.h"
33 #include "pxr/base/tf/pyObjWrapper.h"
34 #include "pxr/base/tf/pyUtils.h"
35 #include "pxr/base/tf/type.h"
37 #include "pxr/base/arch/demangle.h"
38 #include "pxr/base/tf/enum.h"
39 #include "pxr/base/tf/hash.h"
40 #include "pxr/base/tf/hashmap.h"
41 #include "pxr/base/tf/iterator.h"
42 #include "pxr/base/tf/singleton.h"
43 #include "pxr/base/tf/stringUtils.h"
45 #include <boost/preprocessor/stringize.hpp>
46 #include <boost/python/class.hpp>
47 #include <boost/python/converter/from_python.hpp>
48 #include <boost/python/converter/registered.hpp>
49 #include <boost/python/converter/rvalue_from_python_data.hpp>
50 #include <boost/python/list.hpp>
51 #include <boost/python/object.hpp>
52 #include <boost/python/operators.hpp>
53 #include <boost/python/refcount.hpp>
54 #include <boost/python/scope.hpp>
55 #include <boost/python/to_python_converter.hpp>
56 #include <boost/python/tuple.hpp>
60 PXR_NAMESPACE_OPEN_SCOPE
71 class Tf_PyEnumRegistry {
74 typedef Tf_PyEnumRegistry This;
78 virtual ~Tf_PyEnumRegistry();
88 void RegisterValue(
TfEnum const &e, boost::python::object
const &obj);
91 void RegisterEnumConversions() {
93 boost::python::to_python_converter<T, _EnumToPython<T> >();
100 struct _EnumFromPython {
102 boost::python::converter::registry::insert
103 (&convertible, &construct, boost::python::type_id<T>());
105 static void *convertible(PyObject *obj) {
106 TfHashMap<PyObject *, TfEnum, _ObjectHash>
const &o2e =
107 Tf_PyEnumRegistry::GetInstance()._objectsToEnums;
108 TfHashMap<PyObject *, TfEnum, _ObjectHash>::const_iterator
113 if (boost::is_same<T, TfEnum>::value ||
114 (boost::is_integral<T>::value && !boost::is_enum<T>::value))
115 return i != o2e.end() ? obj : 0;
117 return (i != o2e.end() && i->second.IsA<T>()) ? obj : 0;
119 static void construct(PyObject *src, boost::python::converter::
120 rvalue_from_python_stage1_data *data) {
122 ((boost::python::converter::
123 rvalue_from_python_storage<T> *)data)->storage.bytes;
124 new (storage) T(_GetEnumValue(src, (T *)0));
125 data->convertible = storage;
130 template <
typename U>
131 static U _GetEnumValue(PyObject *src, U *) {
132 return U(Tf_PyEnumRegistry::GetInstance()._objectsToEnums[src].
136 return Tf_PyEnumRegistry::GetInstance()._objectsToEnums[src];
140 template <
typename T>
141 struct _EnumToPython {
142 static PyObject *convert(T
const &t);
148 size_t operator()(PyObject *o)
const {
149 return reinterpret_cast<size_t>(o);
153 TfHashMap<TfEnum, PyObject *, TfHash> _enumsToObjects;
154 TfHashMap<PyObject *, TfEnum, _ObjectHash> _objectsToEnums;
162 std::string Tf_PyEnumRepr(boost::python::object
const &
self);
166 struct Tf_PyEnumWrapper
167 :
public Tf_PyEnum, boost::totally_ordered<Tf_PyEnumWrapper>
169 typedef Tf_PyEnumWrapper This;
171 Tf_PyEnumWrapper(std::string
const &n,
TfEnum const &val) :
172 name(n), value(val) {}
173 long GetValue()
const {
174 return value.GetValueAsInt();
176 std::string GetName()
const{
179 std::string GetDisplayName()
const {
182 std::string GetFullName()
const {
185 friend bool operator ==(Tf_PyEnumWrapper
const &
self,
187 return self.value.GetValueAsInt() == other;
190 friend bool operator ==(Tf_PyEnumWrapper
const &lhs,
191 Tf_PyEnumWrapper
const &rhs) {
192 return lhs.value == rhs.value;
195 friend bool operator <(Tf_PyEnumWrapper
const &lhs,
196 Tf_PyEnumWrapper
const &rhs)
202 if (!lhs.value.IsA(rhs.value.GetType()))
206 return lhs.GetValue() < rhs.GetValue();
216 friend TfEnum operator |(Tf_PyEnumWrapper
const &lhs,
217 Tf_PyEnumWrapper
const &rhs) {
218 if (lhs.value.IsA(rhs.value.GetType())) {
219 return TfEnum(lhs.value.GetType(),
220 lhs.value.GetValueAsInt() |
221 rhs.value.GetValueAsInt());
226 friend TfEnum operator |(Tf_PyEnumWrapper
const &lhs,
long rhs) {
227 return TfEnum(lhs.value.GetType(), lhs.value.GetValueAsInt() | rhs);
229 friend TfEnum operator |(
long lhs, Tf_PyEnumWrapper
const &rhs) {
230 return TfEnum(rhs.value.GetType(), lhs | rhs.value.GetValueAsInt());
233 friend TfEnum operator &(Tf_PyEnumWrapper
const &lhs,
234 Tf_PyEnumWrapper
const &rhs) {
235 if (lhs.value.IsA(rhs.value.GetType())) {
236 return TfEnum(lhs.value.GetType(),
237 lhs.value.GetValueAsInt() &
238 rhs.value.GetValueAsInt());
243 friend TfEnum operator &(Tf_PyEnumWrapper
const &lhs,
long rhs) {
244 return TfEnum(lhs.value.GetType(), lhs.value.GetValueAsInt() & rhs);
246 friend TfEnum operator &(
long lhs, Tf_PyEnumWrapper
const &rhs) {
247 return TfEnum(rhs.value.GetType(), lhs & rhs.value.GetValueAsInt());
251 Tf_PyEnumWrapper
const &rhs) {
252 if (lhs.value.IsA(rhs.value.GetType())) {
253 return TfEnum(lhs.value.GetType(),
254 lhs.value.GetValueAsInt() ^
255 rhs.value.GetValueAsInt());
261 return TfEnum(lhs.value.GetType(), lhs.value.GetValueAsInt() ^ rhs);
264 return TfEnum(rhs.value.GetType(), lhs ^ rhs.value.GetValueAsInt());
267 friend TfEnum operator ~(Tf_PyEnumWrapper
const &rhs) {
268 return TfEnum(rhs.value.GetType(), ~rhs.value.GetValueAsInt());
274 template <
typename T>
276 Tf_PyEnumRegistry::_EnumToPython<T>::convert(T
const &t)
282 if (!Tf_PyEnumRegistry::GetInstance()._enumsToObjects.count(e)) {
288 name =
"AutoGenerated_" + name +
"_" +
291 boost::python::object wrappedVal =
292 boost::python::object(Tf_PyEnumWrapper(name, e));
294 wrappedVal.attr(
"_baseName") = std::string();
296 Tf_PyEnumRegistry::GetInstance().RegisterValue(e, wrappedVal);
299 return boost::python::
300 incref(Tf_PyEnumRegistry::GetInstance()._enumsToObjects[e]);
305 template <
typename T>
306 struct Tf_TypedPyEnumWrapper : Tf_PyEnumWrapper
308 Tf_TypedPyEnumWrapper(std::string
const &n,
TfEnum const &val) :
309 Tf_PyEnumWrapper(n, val) {}
315 std::string Tf_PyCleanEnumName(std::string name);
320 void Tf_PyEnumAddAttribute(boost::python::scope &s,
321 const std::string &name,
322 const boost::python::object &value);
368 template <typename T, bool IsScopedEnum = !std::is_convertible<T, int>::value>
372 typedef boost::python::class_<
373 Tf_TypedPyEnumWrapper<T>, boost::python::bases<Tf_PyEnumWrapper> >
384 using namespace boost::python;
386 const bool explicitName = !name.empty();
389 std::string enumName = explicitName ? name :
395 if (baseName == enumName)
396 baseName = std::string();
405 if (!baseName.empty())
406 baseName = Tf_PyCleanEnumName(baseName);
408 enumName = Tf_PyCleanEnumName(enumName);
414 if (!baseName.empty()) {
417 baseName += enumName;
421 _EnumPyClassType enumClass(enumName.c_str(), no_init);
422 enumClass.setattr(
"_baseName", baseName);
425 Tf_PyEnumRegistry::GetInstance().RegisterEnumConversions<T>();
429 _ExportValues(baseName.empty(), enumClass);
434 const TfType &type = TfType::Find<T>();
435 if (!type.IsUnknown())
436 type.DefinePythonClass(enumClass);
444 void _ExportValues(
bool cleanNames, _EnumPyClassType &enumClass) {
445 boost::python::list valueList;
447 std::vector<std::string> names = TfEnum::GetAllNames<T>();
449 bool success =
false;
450 TfEnum enumValue = TfEnum::GetValueFromName<T>(*name, &success);
455 std::string cleanedName = cleanNames ?
456 Tf_PyCleanEnumName(*name) : *name;
459 Tf_TypedPyEnumWrapper<T> wrappedValue(cleanedName, enumValue);
460 boost::python::object pyValue(wrappedValue);
463 Tf_PyEnumRegistry::GetInstance().RegisterValue(enumValue, pyValue);
466 std::string valueName = wrappedValue.GetName();
469 boost::python::scope s(enumClass);
470 Tf_PyEnumAddAttribute(s, valueName, pyValue);
473 boost::python::scope s;
474 Tf_PyEnumAddAttribute(s, valueName, pyValue);
477 valueList.append(pyValue);
481 enumClass.setattr(
"allValues", boost::python::tuple(valueList));
486 PXR_NAMESPACE_CLOSE_SCOPE
488 #endif // TF_PYENUM_H
Manage a single instance of an object (see.
GfVec3d operator^(GfVec3d const &v1, GfVec3d const &v2)
Returns the cross product of v1 and v2.
TF_API std::string TfStringGetSuffix(const std::string &name, char delimiter= '.')
Returns the suffix of a string.
ARCH_API std::string ArchGetDemangled(const std::string &typeName)
Return demangled RTTI-generated type name.
An enum class that records both enum type and enum value.
static TF_API std::string GetDisplayName(TfEnum val)
Returns the display name for an enumerated value.
#define TF_FOR_ALL(iter, c)
Macro for iterating over a container.
TF_API void TfPyThrowTypeError(std::string const &msg)
Raises a python TypeError and throws a C++ exception.
static T & GetInstance()
Return a reference to an object of type T, creating it if necessary.
static TF_API std::string GetFullName(TfEnum val)
Returns the fully-qualified name for an enumerated value.
TfPyWrapEnum(std::string const &name=std::string())
Construct an enum wrapper object.
TfType represents a dynamic runtime type.
VT_API bool operator==(VtDictionary const &, VtDictionary const &)
Equality comparison.
TF_API std::string TfStringGetBeforeSuffix(const std::string &name, char delimiter= '.')
Returns everything up to the suffix of a string.
std::enable_if<!std::is_enum< T >::value, std::string >::type TfStringify(const T &v)
Convert an arbitrary type into a string.
Used to wrap enum types for script.
TF_API std::string TfStringReplace(const std::string &source, const std::string &from, const std::string &to)
Replaces all occurrences of string from with to in source.