// // 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/vt/dictionary.h" #include "pxr/base/vt/types.h" #include "pxr/base/vt/value.h" #include "pxr/base/tf/mallocTag.h" #include "pxr/base/tf/pyContainerConversions.h" #include "pxr/base/tf/pyUtils.h" #include "pxr/base/tf/iterator.h" #include "pxr/base/trace/trace.h" #include #include #include #include #include #include #include #include using namespace boost::python; PXR_NAMESPACE_USING_DIRECTIVE namespace { // Converter from std::vector to python list struct VtValueArrayToPython { static PyObject* convert(const std::vector &v) { // TODO Use result converter. TfPySequenceToList. list result; TF_FOR_ALL(i, v) { object o = TfPyObject(*i); result.append(o); } return incref(result.ptr()); } }; // Converter from VtDictionary to python dict. struct VtDictionaryToPython { static PyObject* convert(const VtDictionary &v) { TRACE_FUNCTION(); // TODO Use result converter TfPyMapToDictionary?? dict result; TF_FOR_ALL(i, v) { object o = TfPyObject(i->second); result.setdefault(i->first, o); } return incref(result.ptr()); } }; static bool _CanVtValueFromPython(object pVal); // Converts a python object to a VtValue, with some special behavior. // If the python object is a dictionary, puts a VtDictionary in the // result. If the python object is a list, puts an std::vector // in the result. If the python object can be converted to something // VtValue knows about, does that. In each of these cases, returns true. // // Otherwise, returns false. static bool _VtValueFromPython(object pVal, VtValue *result) { // Try to convert a nested dictionary into a VtDictionary. extract valDictProxy(pVal); if (valDictProxy.check()) { if (result) { VtDictionary dict = valDictProxy; result->Swap(dict); } return true; } // Try to convert a nested list into a vector. extract > valArrayProxy(pVal); if (valArrayProxy.check()) { if (result) { std::vector array = valArrayProxy; result->Swap(array); } return true; } // Try to convert a value into a VtValue. extract valProxy(pVal); if (valProxy.check()) { VtValue v = valProxy(); if (v.IsHolding()) { return false; } if (result) { result->Swap(v); } return true; } return false; } // Converter from python dict to VtValueArray. struct _VtValueArrayFromPython { _VtValueArrayFromPython() { converter::registry::insert( &convertible, &construct, type_id >()); } // Returns p if p can convert to an array, NULL otherwise. // If result is non-NULL, does the conversion into *result. static PyObject *convert(PyObject *p, std::vector *result) { extract dProxy(p); if (!dProxy.check()) { return NULL; } list d = dProxy(); int numElts = len(d); if (result) result->reserve(numElts); for (int i = 0; i < numElts; i++) { object pVal = d[i]; if (result) { result->push_back(VtValue()); if (!_VtValueFromPython(pVal, &result->back())) return NULL; // Fall through to return p. } else { // Test for convertibility. } } return p; } static void *convertible(PyObject *p) { return convert(p, NULL); } static void construct(PyObject* source, converter:: rvalue_from_python_stage1_data* data) { TfAutoMallocTag2 tag("Vt", "_VtValueArrayFromPython::construct"); void* storage = ( (converter::rvalue_from_python_storage >*) data)->storage.bytes; new (storage) std::vector(); data->convertible = storage; convert(source, (std::vector*)storage); } }; // Converter from python dict to VtDictionary. struct _VtDictionaryFromPython { _VtDictionaryFromPython() { converter::registry::insert( &convertible, &construct, type_id()); } // Returns p if p can convert to a dictionary, NULL otherwise. // If result is non-NULL, does the conversion into *result. static PyObject *convert(PyObject *p, VtDictionary *result) { if (!PyDict_Check(p)) { return NULL; } Py_ssize_t pos = 0; PyObject *pyKey = NULL, *pyVal = NULL; while (PyDict_Next(p, &pos, &pyKey, &pyVal)) { extract keyProxy(pyKey); if (!keyProxy.check()) return NULL; object pVal(handle<>(borrowed(pyVal))); if (result) { VtValue &val = (*result)[keyProxy()]; if (!_VtValueFromPython(pVal, &val)) return NULL; } else { if (!_CanVtValueFromPython(pVal)) return NULL; } } return p; } static void *convertible(PyObject *p) { TRACE_FUNCTION(); return convert(p, NULL); } static void construct(PyObject* source, converter:: rvalue_from_python_stage1_data* data) { TRACE_FUNCTION(); TfAutoMallocTag2 tag("Vt", "_VtDictionaryFromPython::construct"); void* storage = ( (converter::rvalue_from_python_storage*) data)->storage.bytes; new (storage) VtDictionary(0); data->convertible = storage; convert(source, (VtDictionary*)storage); } }; // Converter from python list to VtValue holding VtValueArray. struct _VtValueHoldingVtValueArrayFromPython { _VtValueHoldingVtValueArrayFromPython() { converter::registry::insert(&_VtValueArrayFromPython::convertible, &construct, type_id()); } static void construct(PyObject* source, converter:: rvalue_from_python_stage1_data* data) { TfAutoMallocTag2 tag("Vt", "_VtValueHoldingVtValueArrayFromPython::construct"); std::vector arr; _VtValueArrayFromPython::convert(source, &arr); void* storage = ( (converter::rvalue_from_python_storage*) data)->storage.bytes; new (storage) VtValue(); ((VtValue *)storage)->Swap(arr); data->convertible = storage; } }; // Converter from python dict to VtValue holding VtDictionary. struct _VtValueHoldingVtDictionaryFromPython { _VtValueHoldingVtDictionaryFromPython() { converter::registry::insert(&_VtDictionaryFromPython::convertible, &construct, type_id()); } static void construct(PyObject* source, converter:: rvalue_from_python_stage1_data* data) { TfAutoMallocTag2 tag("Vt", "_VtValueHoldingVtDictionaryFromPython::construct"); VtDictionary dictionary; _VtDictionaryFromPython::convert(source, &dictionary); void* storage = ( (converter::rvalue_from_python_storage*) data)->storage.bytes; new (storage) VtValue(); ((VtValue *)storage)->Swap(dictionary); data->convertible = storage; } }; static bool _CanVtValueFromPython(object pVal) { if (_VtDictionaryFromPython::convertible(pVal.ptr())) return true; if (_VtValueArrayFromPython::convertible(pVal.ptr())) return true; extract e(pVal); return e.check() && !e().IsHolding(); } static VtDictionary _ReturnDictionary(VtDictionary const &x) { return x; } } // anonymous namespace void wrapDictionary() { def("_ReturnDictionary", _ReturnDictionary); to_python_converter(); to_python_converter, VtValueArrayToPython>(); _VtValueArrayFromPython(); _VtDictionaryFromPython(); _VtValueHoldingVtValueArrayFromPython(); _VtValueHoldingVtDictionaryFromPython(); }