Closed reinecke closed 4 months ago
Composition
and SerializableCollection
are handled slightly differently:
Here is the backtrace with OTIO built in debug mode:
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 _otio.cpython-311-darwin.so 0x1062db050 opentimelineio::v1_0::Composable::parent() const + 12
1 _otio.cpython-311-darwin.so 0x10634b698 opentimelineio::v1_0::Composition::insert_child(int, opentimelineio::v1_0::Composable*, opentimelineio::v1_0::ErrorStatus*) + 44
2 _otio.cpython-311-darwin.so 0x10630b794 define_items_and_compositions(pybind11::module_)::$_67::operator()(opentimelineio::v1_0::Composition*, int, opentimelineio::v1_0::Composable*) const + 140
3 _otio.cpython-311-darwin.so 0x10630b6fc void pybind11::detail::argument_loader<opentimelineio::v1_0::Composition*, int, opentimelineio::v1_0::Composable*>::call_impl<void, define_items_and_compositions(pybind11::module_)::$_67&, 0ul, 1ul, 2ul, pybind11::detail::void_type>(define_items_and_compositions(pybind11::module_)::$_67&, std::__1::integer_sequence<unsigned long, 0ul, 1ul, 2ul>, pybind11::detail::void_type&&) && + 112
4 _otio.cpython-311-darwin.so 0x10630b680 std::__1::enable_if<std::is_void<void>::value, pybind11::detail::void_type>::type pybind11::detail::argument_loader<opentimelineio::v1_0::Composition*, int, opentimelineio::v1_0::Composable*>::call<void, pybind11::detail::void_type, define_items_and_compositions(pybind11::module_)::$_67&>(define_items_and_compositions(pybind11::module_)::$_67&) && + 36
5 _otio.cpython-311-darwin.so 0x10630b618 void pybind11::cpp_function::initialize<define_items_and_compositions(pybind11::module_)::$_67, void, opentimelineio::v1_0::Composition*, int, opentimelineio::v1_0::Composable*, pybind11::name, pybind11::is_method, pybind11::sibling, pybind11::arg, pybind11::arg>(define_items_and_compositions(pybind11::module_)::$_67&&, void (*)(opentimelineio::v1_0::Composition*, int, opentimelineio::v1_0::Composable*), pybind11::name const&, pybind11::is_method const&, pybind11::sibling const&, pybind11::arg const&, pybind11::arg const&)::'lambda'(pybind11::detail::function_call&)::operator()(pybind11::detail::function_call&) const + 132
6 _otio.cpython-311-darwin.so 0x10630b578 void pybind11::cpp_function::initialize<define_items_and_compositions(pybind11::module_)::$_67, void, opentimelineio::v1_0::Composition*, int, opentimelineio::v1_0::Composable*, pybind11::name, pybind11::is_method, pybind11::sibling, pybind11::arg, pybind11::arg>(define_items_and_compositions(pybind11::module_)::$_67&&, void (*)(opentimelineio::v1_0::Composition*, int, opentimelineio::v1_0::Composable*), pybind11::name const&, pybind11::is_method const&, pybind11::sibling const&, pybind11::arg const&, pybind11::arg const&)::'lambda'(pybind11::detail::function_call&)::__invoke(pybind11::detail::function_call&) + 28
7 _otio.cpython-311-darwin.so 0x1061b8354 pybind11::cpp_function::dispatcher(_object*, _object*, _object*) + 4020
8 Python 0x1048fef4c cfunction_call + 60
9 Python 0x1048b6cd0 _PyObject_MakeTpCall + 128
10 Python 0x10498fe34 _PyEval_EvalFrameDefault + 40596
11 Python 0x104985444 PyEval_EvalCode + 168
12 Python 0x1049daa18 run_eval_code_obj + 84
13 Python 0x1049da97c run_mod + 112
14 Python 0x1049dcdbc PyRun_StringFlags + 112
15 Python 0x1049dcd04 PyRun_SimpleStringFlags + 64
16 Python 0x1049f54e0 pymain_run_command + 144
17 Python 0x1049f4fb4 Py_RunMain + 228
18 Python 0x1049f62c8 Py_BytesMain + 40
19 dyld 0x18af1bf28 start + 2236
A fix could simply be something like
diff --git a/src/py-opentimelineio/opentimelineio-bindings/otio_serializableObjects.cpp b/src/py-opentimelineio/opentimelineio-bindings/otio_serializableObjects.cpp
index c52ab4c..37c5957 100644
--- a/src/py-opentimelineio/opentimelineio-bindings/otio_serializableObjects.cpp
+++ b/src/py-opentimelineio/opentimelineio-bindings/otio_serializableObjects.cpp
@@ -521,9 +521,9 @@ Should be subclassed (for example by :class:`.Track` and :class:`.Stack`), not u
index = adjusted_vector_index(index, c->children());
c->remove_child(index, ErrorStatusHandler());
}, "index"_a)
- .def("__internal_insert", [](Composition* c, int index, Composable* composable) {
+ .def("__internal_insert", [](Composition* c, int index, Composable &composable) {
index = adjusted_vector_index(index, c->children());
- c->insert_child(index, composable, ErrorStatusHandler());
+ c->insert_child(index, &composable, ErrorStatusHandler());
}, "index"_a, "item"_a)
.def("__contains__", &Composition::has_child, "composable"_a)
.def("__len__", [](Composition* c) {
which gives us what you want:
(.venv) jcmorin$ python -c 'import opentimelineio as otio; track = otio.schema.Track(); track.append(None)'
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "<frozen _collections_abc>", line 1078, in append
File "/private/tmp/asd/.venv/lib/python3.11/site-packages/opentimelineio/core/_core_utils.py", line 359, in insert
self.__internal_insert(
TypeError: __internal_insert(): incompatible function arguments. The following argument types are supported:
1. (self: opentimelineio._otio.Composition, index: int, item: opentimelineio._otio.Composable) -> None
Invoked with: otio.schema.Track(name='', children=[], source_range=None, metadata={}), 0, None
I personally always wondered why OTIO uses pointer parameters for these things instead of reference parameters in the python bindings.
Bug Report
Incorrect Functionality and General Questions
When
None
is passed to theappend
method on a collection, the python interpreter exits with a Segmentation Fault. I first encountered this inTrack
, but traced the behavior up the object hierarchy toCollection
and verified inStack
as well.Track
Stack
Composition
SerializableCollection
Interestingly,
SerializableCollection
behaves differently, but still incorrectly:To Reproduce
Expected Behavior
We should throw a
TypeError
exception as in the following example:Logs
Full crash log from macOS crash report: