diff --git a/src/py-opentimelineio/opentimelineio-bindings/otio_anyDictionary.cpp b/src/py-opentimelineio/opentimelineio-bindings/otio_anyDictionary.cpp index 385fd70db..b8eb6009d 100644 --- a/src/py-opentimelineio/opentimelineio-bindings/otio_anyDictionary.cpp +++ b/src/py-opentimelineio/opentimelineio-bindings/otio_anyDictionary.cpp @@ -23,6 +23,13 @@ void otio_any_dictionary_bindings(py::module m) { py::class_(m, "AnyDictionary") .def(py::init<>()) + .def(py::init([](py::dict item) { + AnyDictionary d = py_to_any_dictionary(item); + auto proxy = new AnyDictionaryProxy; + proxy->fetch_any_dictionary().swap(*d.get_or_create_mutation_stamp()->any_dictionary); + + return proxy; + })) .def("__getitem__", &AnyDictionaryProxy::get_item, "key"_a) .def("__internal_setitem__", &AnyDictionaryProxy::set_item, "key"_a, "item"_a) .def("__delitem__", &AnyDictionaryProxy::del_item, "key"_a) diff --git a/src/py-opentimelineio/opentimelineio-bindings/otio_anyDictionary.h b/src/py-opentimelineio/opentimelineio-bindings/otio_anyDictionary.h index c49ebe887..8fccec6cb 100644 --- a/src/py-opentimelineio/opentimelineio-bindings/otio_anyDictionary.h +++ b/src/py-opentimelineio/opentimelineio-bindings/otio_anyDictionary.h @@ -11,10 +11,17 @@ namespace py = pybind11; struct AnyDictionaryProxy : public AnyDictionary::MutationStamp { + using MutationStamp = AnyDictionary::MutationStamp; + + AnyDictionaryProxy() {} + + // TODO: Should we instead just pass an AnyDictionary? + AnyDictionaryProxy(MutationStamp *d) { + any_dictionary = d->any_dictionary; + } + ~AnyDictionaryProxy() { } - - using MutationStamp = AnyDictionary::MutationStamp; static void throw_dictionary_was_deleted() { throw py::value_error("Underlying C++ AnyDictionary has been destroyed"); diff --git a/src/py-opentimelineio/opentimelineio-bindings/otio_anyVector.cpp b/src/py-opentimelineio/opentimelineio-bindings/otio_anyVector.cpp index 4d974383b..e3bc72a23 100644 --- a/src/py-opentimelineio/opentimelineio-bindings/otio_anyVector.cpp +++ b/src/py-opentimelineio/opentimelineio-bindings/otio_anyVector.cpp @@ -19,6 +19,14 @@ void otio_any_vector_bindings(py::module m) { py::class_(m, "AnyVector") .def(py::init<>()) + .def(py::init([](const py::iterable &it) { + any a; + py_to_any(it, &a); + AnyVector v = safely_cast_any_vector_any(a); + auto proxy = new AnyVectorProxy; + proxy->fetch_any_vector().swap(*v.get_or_create_mutation_stamp()->any_vector); + return proxy; + })) .def("__internal_getitem__", &AnyVectorProxy::get_item, "index"_a) .def("__internal_setitem__", &AnyVectorProxy::set_item, "index"_a, "item"_a) .def("__internal_delitem__", &AnyVectorProxy::del_item, "index"_a) diff --git a/src/py-opentimelineio/opentimelineio-bindings/otio_anyVector.h b/src/py-opentimelineio/opentimelineio-bindings/otio_anyVector.h index ed43e5dec..0df8397b4 100644 --- a/src/py-opentimelineio/opentimelineio-bindings/otio_anyVector.h +++ b/src/py-opentimelineio/opentimelineio-bindings/otio_anyVector.h @@ -13,6 +13,13 @@ namespace py = pybind11; struct AnyVectorProxy : public AnyVector::MutationStamp { using MutationStamp = AnyVector::MutationStamp; + AnyVectorProxy() {} + + // TODO: Should we instead just pass an AnyVector? + AnyVectorProxy(MutationStamp *v) { + any_vector = v->any_vector; + } + static void throw_array_was_deleted() { throw py::value_error("Underlying C++ AnyVector object has been destroyed"); } diff --git a/src/py-opentimelineio/opentimelineio-bindings/otio_utils.cpp b/src/py-opentimelineio/opentimelineio-bindings/otio_utils.cpp index c327374e3..9deb89d57 100644 --- a/src/py-opentimelineio/opentimelineio-bindings/otio_utils.cpp +++ b/src/py-opentimelineio/opentimelineio-bindings/otio_utils.cpp @@ -96,7 +96,7 @@ void _build_any_to_py_dispatch_table() { static py::object _value_to_any = py::none(); -static void py_to_any(py::object const& o, any* result) { +void py_to_any(py::object const& o, any* result) { if (_value_to_any.is_none()) { py::object core = py::module::import("opentimelineio.core"); _value_to_any = core.attr("_value_to_any"); diff --git a/src/py-opentimelineio/opentimelineio-bindings/otio_utils.h b/src/py-opentimelineio/opentimelineio-bindings/otio_utils.h index 2a979aabc..766479702 100644 --- a/src/py-opentimelineio/opentimelineio-bindings/otio_utils.h +++ b/src/py-opentimelineio/opentimelineio-bindings/otio_utils.h @@ -152,6 +152,7 @@ struct PyAny { pybind11::object any_to_py(any const& a, bool top_level = false); pybind11::object plain_string(std::string const& s); pybind11::object plain_int(int i); +void py_to_any(pybind11::object const& o, any* result); AnyDictionary py_to_any_dictionary(pybind11::object const& o); bool compare_typeids(std::type_info const& lhs, std::type_info const& rhs); diff --git a/tests/test_core_utils.py b/tests/test_core_utils.py index a0a7b9425..b1f5ac34f 100644 --- a/tests/test_core_utils.py +++ b/tests/test_core_utils.py @@ -2,6 +2,7 @@ import unittest import opentimelineio._otio +import opentimelineio.opentime import opentimelineio.core._core_utils @@ -61,6 +62,42 @@ def test_raise_on_mutation_during_iter(self): for key in d: del d['b'] + def test_construct_with_values(self): + d1 = opentimelineio.core._core_utils.AnyDictionary( + {'key1': 1234, 'key_2': {'asdasdasd': 5.6}} + ) + v = opentimelineio.core._core_utils.AnyVector() + v.append(1) + v.append('inside any vector') + + so = opentimelineio._otio.SerializableObject() + d2 = opentimelineio.core._core_utils.AnyDictionary( + { + 'string': 'myvalue', + 'int': -999999999999, + 'list': [1, 2.5, 'asd'], + 'dict': {'map1': [345]}, + 'AnyVector': v, + 'AnyDictionary': d1, + 'RationalTime': opentimelineio.opentime.RationalTime( + value=10.0, + rate=5.0 + ), + 'TimeRange': opentimelineio.opentime.TimeRange( + opentimelineio.opentime.RationalTime(value=1.0), + opentimelineio.opentime.RationalTime(value=100.0) + ), + 'TimeTransform': opentimelineio.opentime.TimeTransform( + offset=opentimelineio.opentime.RationalTime(value=55.0), + scale=999 + ), + 'SerializableObject': so + } + ) + self.assertEqual(d2['string'], 'myvalue') + self.assertEqual(d2['SerializableObject'], so) + self.assertEqual(d2['AnyDictionary'], d1) + def test_raises_if_ref_destroyed(self): d1 = opentimelineio.core._core_utils.AnyDictionary() opentimelineio._otio._testing.test_AnyDictionary_destroy(d1) @@ -196,6 +233,41 @@ def test_main(self): # Appending copies data, completely removing references to it. self.assertIsNot(v5[0], tmplist) + def test_construct_with_values(self): + d = opentimelineio.core._core_utils.AnyDictionary() + d['key_1'] = 1234 + d['key_2'] = {'asdasdasd': 5.6} + + v1 = opentimelineio.core._core_utils.AnyVector([1, 'inside any vector']) + + so = opentimelineio._otio.SerializableObject() + v2 = opentimelineio.core._core_utils.AnyVector( + [ + 'myvalue', + -999999999999, + [1, 2.5, 'asd'], + {'map1': [345]}, + v1, + d, + opentimelineio.opentime.RationalTime( + value=10.0, + rate=5.0 + ), + opentimelineio.opentime.TimeRange( + opentimelineio.opentime.RationalTime(value=1.0), + opentimelineio.opentime.RationalTime(value=100.0) + ), + opentimelineio.opentime.TimeTransform( + offset=opentimelineio.opentime.RationalTime(value=55.0), + scale=999 + ), + so + ] + ) + self.assertEqual(v2[0], 'myvalue') + self.assertEqual(v2[-1], so) + self.assertEqual(v2[5], d) + def test_raises_if_ref_destroyed(self): v1 = opentimelineio.core._core_utils.AnyVector() opentimelineio._otio._testing.test_AnyVector_destroy(v1)