From 898ebcb381ab9462feed58ddcb199908a55e1993 Mon Sep 17 00:00:00 2001 From: Joshua Minor Date: Mon, 27 Apr 2026 17:28:07 -0700 Subject: [PATCH 1/3] Remove trailing whitespace from Makefile Signed-off-by: Joshua Minor --- Makefile | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index f1fc21b071..90e303ef83 100644 --- a/Makefile +++ b/Makefile @@ -169,7 +169,7 @@ ifndef CHECK_MANIFEST_PROG endif @check-manifest @echo "check-manifest succeeded" - + doc-model: @python src/py-opentimelineio/opentimelineio/console/autogen_serialized_datamodel.py --dryrun @@ -196,10 +196,10 @@ doc-html: @# if you just want to build the docs yourself outside of RTD @cd docs; ${MAKE_PROG} html -doc-cpp: - @cd doxygen ; doxygen config/dox_config ; cd .. +doc-cpp: + @cd doxygen ; doxygen config/dox_config ; cd .. @echo "wrote doxygen output to: doxygen/output/html/index.html" - + # release related targets confirm-release-intent: ifndef OTIO_DO_RELEASE @@ -231,7 +231,7 @@ unfreeze-ci-versions: @echo "unfreezing CI versions..." @python maintainers/freeze_ci_versions.py -u -# needs to happen _before_ version-map-update so that version in +# needs to happen _before_ version-map-update so that version in # CORE_VERSION_MAP does not have the .dev1 suffix at release time remove-dev-suffix: @echo "Removing .dev1 suffix" @@ -252,7 +252,7 @@ update-contributors: check-github-token dev-python-install: @python setup.py install -# make target for preparing a release candidate +# make target for preparing a release candidate release: \ confirm-release-intent \ check-git-status \ @@ -264,7 +264,7 @@ release: \ dev-python-install \ version-map-update \ test-core \ - update-contributors + update-contributors @echo "Release is ready. Commit, push and open a PR!" # targets for creating a new version (after making a release, to start the next From 2ba04f1cb761688444fa9e78984ec02a35ee23ae Mon Sep 17 00:00:00 2001 From: Joshua Minor Date: Mon, 27 Apr 2026 17:28:41 -0700 Subject: [PATCH 2/3] Fix Makefile format rule to catch all source files Signed-off-by: Joshua Minor --- Makefile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 90e303ef83..4c0a20621f 100644 --- a/Makefile +++ b/Makefile @@ -155,10 +155,11 @@ format: ifndef CLANG_FORMAT_PROG $(error $(newline)$(ccred)clang-format is not available on $$PATH$(ccend)) endif - $(eval DIRS = src/opentime src/opentimelineio) - $(eval DIRS += src/py-opentimelineio/opentime-opentime-bindings) - $(eval DIRS += src/py-opentimelineio/opentimelineio-opentime-bindings) + $(eval DIRS = src/opentime src/opentimelineio src/opentimelineio/algo) + $(eval DIRS += src/py-opentimelineio/opentime-bindings) + $(eval DIRS += src/py-opentimelineio/opentimelineio-bindings) $(eval FILES_TO_FORMAT = $(wildcard $(addsuffix /*.h, $(DIRS)) $(addsuffix /*.cpp, $(DIRS)))) + echo "formatting..." $(FILES_TO_FORMAT) $(shell clang-format -i -style=file $(FILES_TO_FORMAT)) manifest: From e61f00cf0d82daa43cb8dbc07f33a2a7e7c4f86a Mon Sep 17 00:00:00 2001 From: Joshua Minor Date: Mon, 27 Apr 2026 17:29:10 -0700 Subject: [PATCH 3/3] Apply clang-format rules to cpp and h files that were previously missed. Signed-off-by: Joshua Minor --- src/opentimelineio/algo/editAlgorithm.cpp | 260 +-- src/opentimelineio/algo/editAlgorithm.h | 25 +- .../opentime-bindings/opentime_bindings.cpp | 5 +- .../opentime-bindings/opentime_bindings.h | 2 +- .../opentime_rationalTime.cpp | 338 ++- .../opentime-bindings/opentime_timeRange.cpp | 226 +- .../opentime_timeTransform.cpp | 75 +- .../otio_anyDictionary.cpp | 23 +- .../otio_anyDictionary.h | 98 +- .../otio_anyVector.cpp | 27 +- .../opentimelineio-bindings/otio_anyVector.h | 94 +- .../opentimelineio-bindings/otio_bindings.cpp | 383 ++-- .../otio_errorStatusHandler.cpp | 166 +- .../otio_errorStatusHandler.h | 11 +- .../opentimelineio-bindings/otio_imath.cpp | 173 +- .../otio_serializableObjects.cpp | 1958 +++++++++++------ .../opentimelineio-bindings/otio_tests.cpp | 153 +- .../opentimelineio-bindings/otio_utils.cpp | 223 +- .../opentimelineio-bindings/otio_utils.h | 137 +- 19 files changed, 2815 insertions(+), 1562 deletions(-) diff --git a/src/opentimelineio/algo/editAlgorithm.cpp b/src/opentimelineio/algo/editAlgorithm.cpp index 4619dc7608..55e41f2265 100644 --- a/src/opentimelineio/algo/editAlgorithm.cpp +++ b/src/opentimelineio/algo/editAlgorithm.cpp @@ -16,8 +16,8 @@ namespace otime = opentime::OPENTIME_VERSION_NS; using otime::RationalTime; using otime::TimeRange; -namespace opentimelineio { namespace OPENTIMELINEIO_VERSION_NS { namespace algo { - +namespace opentimelineio { namespace OPENTIMELINEIO_VERSION_NS { +namespace algo { #include @@ -31,14 +31,12 @@ operator<<(std::ostream& os, const RationalTime& value) inline std::ostream& operator<<(std::ostream& os, const TimeRange& value) { - os << std::fixed << value.start_time().value() << "/" << - value.duration().value() << "/" << - value.duration().rate(); + os << std::fixed << value.start_time().value() << "/" + << value.duration().value() << "/" << value.duration().rate(); return os; } -namespace -{ +namespace { // We are not testing values outside of one million seconds. // At one million second, and double precision, the smallest @@ -56,7 +54,7 @@ isEqual(double a, double b) { return (std::abs(a - b) <= double_epsilon); } - + } // namespace void @@ -68,8 +66,8 @@ overwrite( Item* fill_template, ErrorStatus* error_status) { - const TimeRange composition_range = composition->trimmed_range(); - const RationalTime start_time = range.start_time(); + const TimeRange composition_range = composition->trimmed_range(); + const RationalTime start_time = range.start_time(); if (start_time >= composition_range.end_time_exclusive()) { // Append the item and a possible fill (gap). @@ -86,8 +84,9 @@ overwrite( } composition->append_child(item); } - else if (start_time < composition_range.start_time() && - range.end_time_exclusive() < composition_range.start_time()) + else if ( + start_time < composition_range.start_time() + && range.end_time_exclusive() < composition_range.start_time()) { const RationalTime fill_duration = composition_range.start_time() - start_time - range.duration(); @@ -113,7 +112,7 @@ overwrite( true); if (!transitions.empty()) { - for (const auto& transition : transitions) + for (const auto& transition: transitions) { int index = composition->index_of_child(transition); if (index < 0 @@ -139,7 +138,7 @@ overwrite( if (1 == items.size() && item_range.contains(range, 0.0)) { auto first_item = items.front(); - + bool is_fill_fit = false; // We check if we are replacing a gap with a clip with timewarp, @@ -147,7 +146,7 @@ overwrite( if (dynamic_retainer_cast(first_item)) { auto effects = item->effects(); - for (auto& effect : effects) + for (auto& effect: effects) { if (dynamic_retainer_cast(effect)) { @@ -156,14 +155,14 @@ overwrite( } } } - + // The item overwrites a portion inside an item. const RationalTime first_duration = range.start_time() - item_range.start_time(); const RationalTime second_duration = item_range.duration() - range.duration() - first_duration; - int first_index = composition->index_of_child(first_item); - int insert_index = first_index; + int first_index = composition->index_of_child(first_item); + int insert_index = first_index; TimeRange trimmed_range = first_item->trimmed_range(); TimeRange source_range(trimmed_range.start_time(), first_duration); if (isEqual(first_duration.value(), 0.0)) @@ -186,7 +185,7 @@ overwrite( trimmed_range = second_item->trimmed_range(); source_range = TimeRange( trimmed_range.start_time() + first_duration - + range.duration(), + + range.duration(), second_duration); ++insert_index; second_item->set_source_range(source_range); @@ -281,13 +280,11 @@ insert( if (remove_transitions) { TimeRange range(time, RationalTime(1.0, time.rate())); - auto transitions = composition->find_children( - error_status, - range, - true); + auto transitions = + composition->find_children(error_status, range, true); if (!transitions.empty()) { - for (const auto& transition : transitions) + for (const auto& transition: transitions) { int index = composition->index_of_child(transition); if (index < 0 @@ -300,7 +297,7 @@ insert( } const TimeRange composition_range = composition->trimmed_range(); - + // Find the item to insert into. auto item = dynamic_retainer_cast( composition->child_at_time(time, error_status)); @@ -333,13 +330,13 @@ insert( } return; } - + const int index = composition->index_of_child(item); const TimeRange range = composition->trimmed_range_of_child_at_index(index); - int insert_index = index; + int insert_index = index; // Item is partially split - bool split = false; + bool split = false; const TimeRange first_source_range( item->trimmed_range().start_time(), time - range.start_time()); @@ -352,31 +349,33 @@ insert( // Insert the new item composition->insert_child(insert_index, insert_item); - const TimeRange insert_range = composition->trimmed_range_of_child_at_index(insert_index); + const TimeRange insert_range = + composition->trimmed_range_of_child_at_index(insert_index); // Second item from splitting item if (split) { const TimeRange second_source_range( - first_source_range.start_time() + - insert_range.start_time() + insert_range.duration(), + first_source_range.start_time() + insert_range.start_time() + + insert_range.duration(), range.end_time_exclusive() - time); // Clone the item for the second partially overwritten item. if (!isEqual(second_source_range.duration().value(), 0.0)) { - auto second_item = dynamic_cast(item->clone()); + auto second_item = dynamic_cast(item->clone()); second_item->set_source_range(second_source_range); composition->insert_child(insert_index + 1, second_item); } } } -void trim( - Item* item, +void +trim( + Item* item, RationalTime const& delta_in, RationalTime const& delta_out, - Item* fill_template, - ErrorStatus* error_status) + Item* fill_template, + ErrorStatus* error_status) { Composition* composition = item->parent(); if (!composition) @@ -385,18 +384,18 @@ void trim( *error_status = ErrorStatus::NOT_A_CHILD_OF; return; } - auto children = composition->children(); - const int index = composition->index_of_child(item); + auto children = composition->children(); + const int index = composition->index_of_child(item); if (index < 0) - { + { if (error_status) *error_status = ErrorStatus::NOT_AN_ITEM; return; } - - const TimeRange range = item->trimmed_range(); - RationalTime start_time = range.start_time(); - RationalTime end_time_exclusive = range.end_time_exclusive(); + + const TimeRange range = item->trimmed_range(); + RationalTime start_time = range.start_time(); + RationalTime end_time_exclusive = range.end_time_exclusive(); if (delta_in.value() != 0.0) { start_time += delta_in; @@ -404,8 +403,9 @@ void trim( { auto previous = dynamic_retainer_cast(children[index - 1]); TimeRange previous_range = previous->trimmed_range(); - previous_range = TimeRange(previous_range.start_time(), - previous_range.duration() + delta_in); + previous_range = TimeRange( + previous_range.start_time(), + previous_range.duration() + delta_in); previous->set_source_range(previous_range); } } @@ -414,7 +414,7 @@ void trim( const int next_index = index + 1; if (static_cast(next_index) < children.size()) { - auto next = dynamic_retainer_cast(children[next_index]); + auto next = dynamic_retainer_cast(children[next_index]); auto gap_next = dynamic_retainer_cast(children[next_index]); if (gap_next && delta_out.value() > 0.0) { @@ -469,16 +469,15 @@ slice( *error_status = ErrorStatus::NOT_AN_ITEM; return; } - + const int index = composition->index_of_child(item); const TimeRange range = composition->trimmed_range_of_child_at_index(index); - // Check for slice at start of clip (invalid slice) const RationalTime duration = time - range.start_time(); if (isEqual(duration.value(), 0.0)) return; - + // Accumulate intersecting transitions std::vector transitions; if (auto track = dynamic_cast(composition)) @@ -503,13 +502,13 @@ slice( } } } - + // Remove transitions if (!transitions.empty()) { if (remove_transitions) { - for (auto transition : transitions) + for (auto transition: transitions) { const int child_index = composition->index_of_child(transition); composition->remove_child(child_index); @@ -522,12 +521,12 @@ slice( return; } } - + // Adjust the source range for the first slice. const TimeRange first_source_range( item->trimmed_range().start_time(), duration); - + item->set_source_range(first_source_range); // Clone the item for the second slice. @@ -541,62 +540,61 @@ slice( composition->insert_child(static_cast(index) + 1, second_item); } } - -void slip( - Item* item, - RationalTime const& delta) + +void +slip(Item* item, RationalTime const& delta) { - const TimeRange range = item->trimmed_range(); - RationalTime start_time = range.start_time(); + const TimeRange range = item->trimmed_range(); + RationalTime start_time = range.start_time(); start_time += delta; // Clamp to available range of media if present - const TimeRange available_range = item->available_range(); + const TimeRange available_range = item->available_range(); if (!isEqual(available_range.duration().value(), 0.0)) { if (start_time < available_range.start_time()) { start_time = available_range.start_time(); } - else if (start_time + range.duration() > - available_range.end_time_exclusive()) + else if ( + start_time + range.duration() + > available_range.end_time_exclusive()) { // S---E (move <- source start time so that E matches) // A-----E - const RationalTime end_diff = start_time + range.duration() - - available_range.end_time_exclusive(); + const RationalTime end_diff = + start_time + range.duration() + - available_range.end_time_exclusive(); start_time -= end_diff; } } - + const TimeRange new_range(start_time, range.duration()); item->set_source_range(new_range); } - -void slide( - Item* item, - RationalTime const& delta) +void +slide(Item* item, RationalTime const& delta) { Composition* composition = item->parent(); if (!composition) { return; } - - const int index = composition->index_of_child(item); + + const int index = composition->index_of_child(item); // Exit early if we are at the first clip or if the delta is 0. if (index <= 0 || delta.value() == 0.0) { return; } - - auto children = composition->children(); - auto previous = dynamic_retainer_cast(children[index - 1]); - const TimeRange range = previous->trimmed_range(); + + auto children = composition->children(); + auto previous = dynamic_retainer_cast(children[index - 1]); + const TimeRange range = previous->trimmed_range(); const TimeRange available_range = previous->available_range(); - RationalTime offset = delta; + RationalTime offset = delta; if (delta.value() < 0.0) { @@ -610,29 +608,32 @@ void slide( { // Check we don't move right beyond the previous clip's // available duration - if (!isEqual(available_range.duration().value(), 0.0) && - range.duration() + delta > available_range.duration()) + if (!isEqual(available_range.duration().value(), 0.0) + && range.duration() + delta > available_range.duration()) { offset = available_range.duration() - range.duration(); } } - - const otime::TimeRange new_range(range.start_time(), - range.duration() + offset); + + const otime::TimeRange new_range( + range.start_time(), + range.duration() + offset); previous->set_source_range(new_range); } -void ripple( - Item* item, +void +ripple( + Item* item, RationalTime const& delta_in, RationalTime const& delta_out, - ErrorStatus* error_status) + ErrorStatus* error_status) { - if (error_status) *error_status = ErrorStatus::OK; - - const TimeRange range = item->trimmed_range(); - RationalTime start_time = range.start_time(); - RationalTime end_time_exclusive = range.end_time_exclusive(); + if (error_status) + *error_status = ErrorStatus::OK; + + const TimeRange range = item->trimmed_range(); + RationalTime start_time = range.start_time(); + RationalTime end_time_exclusive = range.end_time_exclusive(); if (delta_in.value() != 0.0) { RationalTime in_offset = delta_in; @@ -655,8 +656,8 @@ void ripple( // Check we don't move right beyond the clip's // available duration - if (!(isEqual(available_range.duration().value(), 0.0)) && - range.duration() + delta_out > available_range.duration()) + if (!(isEqual(available_range.duration().value(), 0.0)) + && range.duration() + delta_out > available_range.duration()) { out_offset = available_range.duration() - range.duration(); } @@ -683,23 +684,23 @@ roll( *error_status = ErrorStatus::NOT_A_CHILD_OF; return; } - auto children = composition->children(); - const int index = composition->index_of_child(item); + auto children = composition->children(); + const int index = composition->index_of_child(item); if (index < 0) { if (error_status) *error_status = ErrorStatus::NOT_AN_ITEM; return; } - - const TimeRange range = item->trimmed_range(); - const TimeRange available_range = item->available_range(); - RationalTime start_time = range.start_time(); - RationalTime end_time_exclusive = range.end_time_exclusive(); + + const TimeRange range = item->trimmed_range(); + const TimeRange available_range = item->available_range(); + RationalTime start_time = range.start_time(); + RationalTime end_time_exclusive = range.end_time_exclusive(); if (delta_in.value() != 0.0) { const RationalTime available_start_time = available_range.start_time(); - RationalTime in_offset = delta_in; + RationalTime in_offset = delta_in; if (-in_offset > start_time) in_offset = -start_time; if (index > 0) @@ -712,10 +713,11 @@ roll( if (duration < -in_offset) { duration -= RationalTime(1.0, duration.rate()); - in_offset -= duration; + in_offset -= duration; } - previous_range = TimeRange(previous_range.start_time(), - previous_range.duration() + in_offset); + previous_range = TimeRange( + previous_range.start_time(), + previous_range.duration() + in_offset); previous->set_source_range(previous_range); } start_time += in_offset; @@ -732,11 +734,11 @@ roll( const size_t next_index = index + 1; if (next_index < children.size()) { - auto next = dynamic_retainer_cast(children[next_index]); - TimeRange next_range = next->trimmed_range(); + auto next = dynamic_retainer_cast(children[next_index]); + TimeRange next_range = next->trimmed_range(); const TimeRange next_available_range = next->available_range(); - RationalTime next_start_time = next_range.start_time(); - RationalTime out_offset = delta_out; + RationalTime next_start_time = next_range.start_time(); + RationalTime out_offset = delta_out; // If available range, clamp to it. if (!(isEqual(available_range.duration().value(), 0.0))) @@ -751,11 +753,10 @@ roll( if (-out_offset > next_start_time) out_offset = -next_start_time; } - + end_time_exclusive += out_offset; - next_start_time += out_offset; - next_range = TimeRange(next_start_time, - next_range.duration()); + next_start_time += out_offset; + next_range = TimeRange(next_start_time, next_range.duration()); next->set_source_range(next_range); } } @@ -782,17 +783,17 @@ fill( return; } - const TimeRange clip_range = item->trimmed_range(); - const TimeRange gap_range = gap->trimmed_range(); - TimeRange gap_track_range = track->trimmed_range_of_child(gap).value(); - RationalTime duration = clip_range.duration(); + const TimeRange clip_range = item->trimmed_range(); + const TimeRange gap_range = gap->trimmed_range(); + TimeRange gap_track_range = track->trimmed_range_of_child(gap).value(); + RationalTime duration = clip_range.duration(); switch (reference_point) { case ReferencePoint::Sequence: { - RationalTime start_time = clip_range.start_time(); + RationalTime start_time = clip_range.start_time(); const RationalTime gap_start_time = gap_range.start_time(); - auto track_item = dynamic_cast(item->clone()); + auto track_item = dynamic_cast(item->clone()); // Check if start time is less than gap's start time (trim it if so) if (start_time < gap_start_time) @@ -800,7 +801,7 @@ fill( duration -= gap_start_time - start_time; start_time = gap_start_time; } - + // Check if end time is longer (trim it if it is) if (clip_range.end_time_exclusive() > gap_range.end_time_exclusive()) @@ -810,13 +811,11 @@ fill( const TimeRange new_clip_range(start_time, duration); track_item->set_source_range(new_clip_range); - if (duration - > gap_track_range.end_time_exclusive() - track_time) + if (duration > gap_track_range.end_time_exclusive() - track_time) { - duration = - gap_track_range.end_time_exclusive() - track_time; + duration = gap_track_range.end_time_exclusive() - track_time; } - + const TimeRange time_range(track_time, duration); overwrite( track_item, @@ -829,14 +828,14 @@ fill( } case ReferencePoint::Fit: { - const double pct = gap_range.duration().to_seconds() - / duration.to_seconds(); + const double pct = + gap_range.duration().to_seconds() / duration.to_seconds(); const std::string& name = item->name(); - LinearTimeWarp* timeWarp = + LinearTimeWarp* timeWarp = new LinearTimeWarp(name, name + "_timeWarp", pct); - auto& effects = item->effects(); + auto& effects = item->effects(); std::vector effectList; - for (auto& effect : effects) + for (auto& effect: effects) effectList.push_back(effect); effectList.push_back(timeWarp); item = new Item(name, clip_range, AnyDictionary(), effectList); @@ -856,10 +855,11 @@ fill( } } -void remove( +void +remove( Composition* composition, RationalTime const& time, - bool const fill, + bool const fill, Item* fill_template, ErrorStatus* error_status) { @@ -882,5 +882,5 @@ void remove( composition->insert_child(index, fill_template); } } - + }}} // namespace opentimelineio::OPENTIMELINEIO_VERSION_NS::algo diff --git a/src/opentimelineio/algo/editAlgorithm.h b/src/opentimelineio/algo/editAlgorithm.h index ca18baba13..7d727015d7 100644 --- a/src/opentimelineio/algo/editAlgorithm.h +++ b/src/opentimelineio/algo/editAlgorithm.h @@ -5,7 +5,8 @@ #include "opentimelineio/composition.h" -namespace opentimelineio { namespace OPENTIMELINEIO_VERSION_NS { namespace algo { +namespace opentimelineio { namespace OPENTIMELINEIO_VERSION_NS { +namespace algo { //! Enum used by 3/4 Point Edit (aka. as fill) enum class ReferencePoint @@ -35,7 +36,7 @@ enum class ReferencePoint // // If overwrite range starts before A and partially overlaps it, C is // added at the beginning and A is partitioned. -// +// // If overwrite range starts and ends before A, a gap hole is filled with // fill_template. OTIO_API void overwrite( @@ -75,7 +76,7 @@ OTIO_API void insert( // // | A | B | C | -> | A |FILL| B | C | // <--* -// +// // item = Item to apply trim to (usually a clip) // delta_in = RationalTime that the item's source_range().start_time() // will be adjusted by @@ -83,11 +84,11 @@ OTIO_API void insert( // source_range().end_time_exclusive() will be adjusted by // fill_template = item to fill in (usually a gap), // when time > composition's time. -// +// // Do not affect other clips. // Fill now-"empty" time with gap or template // Unless item is meeting a Gap, then, existing Gap's duration will be augmented -// +// OTIO_API void trim( Item* item, RationalTime const& delta_in, @@ -115,7 +116,7 @@ OTIO_API void slice( // // item = item to slip (usually a clip) // delta = +/- rational time to slip the item by. -// +// // Do not affect item duration. // Do not affect surrounding items. // Clamp to available_range of media (if available) @@ -140,7 +141,7 @@ OTIO_API void slide(Item* item, RationalTime const& delta); // // | A | B | -> | A | B |FILL| // <--* -// +// // item = Item to apply ripple to (usually a clip) // delta_in = RationalTime that the item's source_range().start_time() // will be adjusted by @@ -162,7 +163,7 @@ OTIO_API void ripple( // // | A | B | -> | A | B | // <--* -// +// // item = Item to apply roll to (usually a clip) // delta_in = RationalTime that the item's source_range().start_time() // will be adjusted by @@ -191,11 +192,11 @@ OTIO_API void fill( Composition* track, RationalTime const& track_time, ReferencePoint const reference_point = ReferencePoint::Source, - ErrorStatus* error_status = nullptr); + ErrorStatus* error_status = nullptr); // // Remove item(s) at a time and fill them, optionally with a gap. -// +// // | A | C | B | -> | A |GAP| B | // ^ // | @@ -210,8 +211,8 @@ OTIO_API void fill( OTIO_API void remove( Composition* composition, RationalTime const& time, - bool const fill = true, + bool const fill = true, Item* fill_template = nullptr, - ErrorStatus* error_status = nullptr); + ErrorStatus* error_status = nullptr); }}} // namespace opentimelineio::OPENTIMELINEIO_VERSION_NS::algo diff --git a/src/py-opentimelineio/opentime-bindings/opentime_bindings.cpp b/src/py-opentimelineio/opentime-bindings/opentime_bindings.cpp index 55cf2a586e..0cf86047a8 100644 --- a/src/py-opentimelineio/opentime-bindings/opentime_bindings.cpp +++ b/src/py-opentimelineio/opentime-bindings/opentime_bindings.cpp @@ -1,10 +1,11 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright Contributors to the OpenTimelineIO project -#include #include "opentime_bindings.h" +#include -PYBIND11_MODULE(_opentime, m) { +PYBIND11_MODULE(_opentime, m) +{ m.doc() = "Bindings to C++ OTIO implementation"; opentime_rationalTime_bindings(m); opentime_timeRange_bindings(m); diff --git a/src/py-opentimelineio/opentime-bindings/opentime_bindings.h b/src/py-opentimelineio/opentime-bindings/opentime_bindings.h index eb62dcd9a8..5a2ce43ba0 100644 --- a/src/py-opentimelineio/opentime-bindings/opentime_bindings.h +++ b/src/py-opentimelineio/opentime-bindings/opentime_bindings.h @@ -4,9 +4,9 @@ #ifndef OTIO_OPENTIME_BINDINGS_H #define OTIO_OPENTIME_BINDINGS_H +#include "opentime/rationalTime.h" #include #include -#include "opentime/rationalTime.h" void opentime_rationalTime_bindings(pybind11::module); void opentime_timeRange_bindings(pybind11::module); diff --git a/src/py-opentimelineio/opentime-bindings/opentime_rationalTime.cpp b/src/py-opentimelineio/opentime-bindings/opentime_rationalTime.cpp index 1c3c43cfc4..448d499e9f 100644 --- a/src/py-opentimelineio/opentime-bindings/opentime_rationalTime.cpp +++ b/src/py-opentimelineio/opentime-bindings/opentime_rationalTime.cpp @@ -1,8 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright Contributors to the OpenTimelineIO project -#include #include +#include #include #include "opentime/rationalTime.h" @@ -14,14 +14,15 @@ using namespace pybind11::literals; using namespace opentime; namespace { -struct ErrorStatusConverter { - operator ErrorStatus* () { - return &error_status; - } +struct ErrorStatusConverter +{ + operator ErrorStatus*() { return &error_status; } - ~ErrorStatusConverter() noexcept(false) { + ~ErrorStatusConverter() noexcept(false) + { namespace py = pybind11; - if (is_error(error_status)) { + if (is_error(error_status)) + { throw py::value_error(error_status.details); } } @@ -29,37 +30,61 @@ struct ErrorStatusConverter { ErrorStatus error_status; }; -IsDropFrameRate df_enum_converter(std::optional& df) { - if (!df.has_value()) { +IsDropFrameRate +df_enum_converter(std::optional& df) +{ + if (!df.has_value()) + { return IsDropFrameRate::InferFromRate; - } else if (df.value()) { + } + else if (df.value()) + { return IsDropFrameRate::ForceYes; - } else { + } + else + { return IsDropFrameRate::ForceNo; } } -} +} // namespace -std::string opentime_python_str(RationalTime rt) { +std::string +opentime_python_str(RationalTime rt) +{ return string_printf("RationalTime(%g, %g)", rt.value(), rt.rate()); } -std::string opentime_python_repr(RationalTime rt) { - return string_printf("otio.opentime.RationalTime(value=%g, rate=%g)", rt.value(), rt.rate()); +std::string +opentime_python_repr(RationalTime rt) +{ + return string_printf( + "otio.opentime.RationalTime(value=%g, rate=%g)", + rt.value(), + rt.rate()); } -RationalTime _type_checked(py::object const& rhs, char const* op) { - try { +RationalTime +_type_checked(py::object const& rhs, char const* op) +{ + try + { return py::cast(rhs); } - catch (...) { - std::string rhs_type = py::cast(py::type::of(rhs).attr("__name__")); - throw py::type_error(string_printf("unsupported operand type(s) for %s: " - "RationalTime and %s", op, rhs_type.c_str())); + catch (...) + { + std::string rhs_type = + py::cast(py::type::of(rhs).attr("__name__")); + throw py::type_error(string_printf( + "unsupported operand type(s) for %s: " + "RationalTime and %s", + op, + rhs_type.c_str())); } } -void opentime_rationalTime_bindings(py::module m) { +void +opentime_rationalTime_bindings(py::module m) +{ py::class_(m, "RationalTime", R"docstring( The RationalTime class represents a measure of time of :math:`rt.value/rt.rate` seconds. It can be rescaled into another :class:`~RationalTime`'s rate. @@ -75,120 +100,219 @@ and the rate is greater than zero. )docstring") .def_property_readonly("value", &RationalTime::value) .def_property_readonly("rate", &RationalTime::rate) - .def("rescaled_to", (RationalTime (RationalTime::*)(double) const) &RationalTime::rescaled_to, - "new_rate"_a, R"docstring(Returns the time value for time converted to new_rate.)docstring") - .def("rescaled_to", (RationalTime (RationalTime::*)(RationalTime) const) &RationalTime::rescaled_to, - "other"_a, R"docstring(Returns the time for time converted to new_rate.)docstring") - .def("value_rescaled_to", (double (RationalTime::*)(double) const) &RationalTime::value_rescaled_to, - "new_rate"_a, R"docstring(Returns the time value for "self" converted to new_rate.)docstring") - .def("value_rescaled_to", (double (RationalTime::*)(RationalTime) const) &RationalTime::value_rescaled_to, - "other"_a) - .def("almost_equal", &RationalTime::almost_equal, "other"_a, "delta"_a = 0) + .def( + "rescaled_to", + (RationalTime (RationalTime::*)(double) const) + & RationalTime::rescaled_to, + "new_rate"_a, + R"docstring(Returns the time value for time converted to new_rate.)docstring") + .def( + "rescaled_to", + (RationalTime (RationalTime::*)(RationalTime) const) + & RationalTime::rescaled_to, + "other"_a, + R"docstring(Returns the time for time converted to new_rate.)docstring") + .def( + "value_rescaled_to", + (double (RationalTime::*)(double) const) + & RationalTime::value_rescaled_to, + "new_rate"_a, + R"docstring(Returns the time value for "self" converted to new_rate.)docstring") + .def( + "value_rescaled_to", + (double (RationalTime::*)(RationalTime) const) + & RationalTime::value_rescaled_to, + "other"_a) + .def( + "almost_equal", + &RationalTime::almost_equal, + "other"_a, + "delta"_a = 0) .def("strictly_equal", &RationalTime::strictly_equal, "other"_a) .def("floor", &RationalTime::floor) .def("ceil", &RationalTime::ceil) .def("round", &RationalTime::round) - .def("__copy__", [](RationalTime rt) { - return rt; - }) - .def("__deepcopy__", [](RationalTime rt, py::object) { - return rt; - }, "copier"_a = py::none()) - .def_static("duration_from_start_end_time", &RationalTime::duration_from_start_end_time, - "start_time"_a, "end_time_exclusive"_a, R"docstring( + .def("__copy__", [](RationalTime rt) { return rt; }) + .def( + "__deepcopy__", + [](RationalTime rt, py::object) { return rt; }, + "copier"_a = py::none()) + .def_static( + "duration_from_start_end_time", + &RationalTime::duration_from_start_end_time, + "start_time"_a, + "end_time_exclusive"_a, + R"docstring( Compute the duration of samples from first to last (excluding last). This is not the same as distance. For example, the duration of a clip from frame 10 to frame 15 is 5 frames. Result will be in the rate of start_time. )docstring") - .def_static("duration_from_start_end_time_inclusive", &RationalTime::duration_from_start_end_time_inclusive, - "start_time"_a, "end_time_inclusive"_a, R"docstring( + .def_static( + "duration_from_start_end_time_inclusive", + &RationalTime::duration_from_start_end_time_inclusive, + "start_time"_a, + "end_time_inclusive"_a, + R"docstring( Compute the duration of samples from first to last (including last). This is not the same as distance. For example, the duration of a clip from frame 10 to frame 15 is 6 frames. Result will be in the rate of start_time. )docstring") - .def_static("is_valid_timecode_rate", &RationalTime::is_valid_timecode_rate, "rate"_a, + .def_static( + "is_valid_timecode_rate", + &RationalTime::is_valid_timecode_rate, + "rate"_a, "Deprecated. Please use `is_smpte_timecode_rate` instead. This function will be removed in a future release.") - .def_static("is_smpte_timecode_rate", &RationalTime::is_smpte_timecode_rate, "rate"_a, + .def_static( + "is_smpte_timecode_rate", + &RationalTime::is_smpte_timecode_rate, + "rate"_a, "Returns true if the rate is valid for use with SMPTE timecode.") - .def_static("nearest_valid_timecode_rate", &RationalTime::nearest_valid_timecode_rate, "rate"_a, + .def_static( + "nearest_valid_timecode_rate", + &RationalTime::nearest_valid_timecode_rate, + "rate"_a, "Deprecated. Please use `nearest_smpte_timecode_rate` instead. This function will be removed in a future release.") - .def_static("nearest_smpte_timecode_rate", &RationalTime::nearest_smpte_timecode_rate, "rate"_a, + .def_static( + "nearest_smpte_timecode_rate", + &RationalTime::nearest_smpte_timecode_rate, + "rate"_a, "Returns the first SMPTE timecode rate that has the least difference from the given value.") - .def_static("from_frames", &RationalTime::from_frames, "frame"_a, "rate"_a, + .def_static( + "from_frames", + &RationalTime::from_frames, + "frame"_a, + "rate"_a, "Turn a frame number and rate into a :class:`~RationalTime` object.") - .def_static("from_seconds", static_cast (&RationalTime::from_seconds), "seconds"_a, "rate"_a) - .def_static("from_seconds", static_cast (&RationalTime::from_seconds), "seconds"_a) - .def("to_frames", (int (RationalTime::*)() const) &RationalTime::to_frames, + .def_static( + "from_seconds", + static_cast( + &RationalTime::from_seconds), + "seconds"_a, + "rate"_a) + .def_static( + "from_seconds", + static_cast(&RationalTime::from_seconds), + "seconds"_a) + .def( + "to_frames", + (int (RationalTime::*)() const) & RationalTime::to_frames, "Returns the frame number based on the current rate.") - .def("to_frames", (int (RationalTime::*)(double) const) &RationalTime::to_frames, "rate"_a, + .def( + "to_frames", + (int (RationalTime::*)(double) const) & RationalTime::to_frames, + "rate"_a, "Returns the frame number based on the given rate.") .def("to_seconds", &RationalTime::to_seconds) - .def("to_timecode", [](RationalTime rt, double rate, std::optional drop_frame) { + .def( + "to_timecode", + [](RationalTime rt, double rate, std::optional drop_frame) { return rt.to_timecode( - rate, - df_enum_converter(drop_frame), - ErrorStatusConverter() - ); - }, "rate"_a, "drop_frame"_a, "Convert to timecode (``HH:MM:SS;FRAME``)") - .def("to_timecode", [](RationalTime rt, double rate) { + rate, + df_enum_converter(drop_frame), + ErrorStatusConverter()); + }, + "rate"_a, + "drop_frame"_a, + "Convert to timecode (``HH:MM:SS;FRAME``)") + .def( + "to_timecode", + [](RationalTime rt, double rate) { return rt.to_timecode( - rate, - IsDropFrameRate::InferFromRate, - ErrorStatusConverter() - ); - }, "rate"_a) - .def("to_timecode", [](RationalTime rt) { + rate, + IsDropFrameRate::InferFromRate, + ErrorStatusConverter()); + }, + "rate"_a) + .def( + "to_timecode", + [](RationalTime rt) { return rt.to_timecode( - rt.rate(), - IsDropFrameRate::InferFromRate, - ErrorStatusConverter()); - }) - .def("to_nearest_timecode", [](RationalTime rt, double rate, std::optional drop_frame) { + rt.rate(), + IsDropFrameRate::InferFromRate, + ErrorStatusConverter()); + }) + .def( + "to_nearest_timecode", + [](RationalTime rt, double rate, std::optional drop_frame) { return rt.to_nearest_timecode( - rate, - df_enum_converter(drop_frame), - ErrorStatusConverter() - ); - }, "rate"_a, "drop_frame"_a, "Convert to nearest timecode (``HH:MM:SS;FRAME``)") - .def("to_nearest_timecode", [](RationalTime rt, double rate) { + rate, + df_enum_converter(drop_frame), + ErrorStatusConverter()); + }, + "rate"_a, + "drop_frame"_a, + "Convert to nearest timecode (``HH:MM:SS;FRAME``)") + .def( + "to_nearest_timecode", + [](RationalTime rt, double rate) { return rt.to_nearest_timecode( - rate, - IsDropFrameRate::InferFromRate, - ErrorStatusConverter() - ); - }, "rate"_a) - .def("to_nearest_timecode", [](RationalTime rt) { + rate, + IsDropFrameRate::InferFromRate, + ErrorStatusConverter()); + }, + "rate"_a) + .def( + "to_nearest_timecode", + [](RationalTime rt) { return rt.to_nearest_timecode( - rt.rate(), - IsDropFrameRate::InferFromRate, - ErrorStatusConverter()); - }) + rt.rate(), + IsDropFrameRate::InferFromRate, + ErrorStatusConverter()); + }) .def("to_time_string", &RationalTime::to_time_string) - .def_static("from_timecode", [](std::string s, double rate) { - return RationalTime::from_timecode(s, rate, ErrorStatusConverter()); - }, "timecode"_a, "rate"_a, "Convert a timecode string (``HH:MM:SS;FRAME``) into a :class:`~RationalTime`.") - .def_static("from_time_string", [](std::string s, double rate) { - return RationalTime::from_time_string(s, rate, ErrorStatusConverter()); - }, "time_string"_a, "rate"_a, "Convert a time with microseconds string (``HH:MM:ss`` where ``ss`` is an integer or a decimal number) into a :class:`~RationalTime`.") + .def_static( + "from_timecode", + [](std::string s, double rate) { + return RationalTime::from_timecode( + s, + rate, + ErrorStatusConverter()); + }, + "timecode"_a, + "rate"_a, + "Convert a timecode string (``HH:MM:SS;FRAME``) into a :class:`~RationalTime`.") + .def_static( + "from_time_string", + [](std::string s, double rate) { + return RationalTime::from_time_string( + s, + rate, + ErrorStatusConverter()); + }, + "time_string"_a, + "rate"_a, + "Convert a time with microseconds string (``HH:MM:ss`` where ``ss`` is an integer or a decimal number) into a :class:`~RationalTime`.") .def("__str__", &opentime_python_str) .def("__repr__", &opentime_python_repr) - .def(- py::self) - .def("__lt__", [](RationalTime lhs, py::object const& rhs) { + .def(-py::self) + .def( + "__lt__", + [](RationalTime lhs, py::object const& rhs) { return lhs < _type_checked(rhs, "<"); }) - .def("__gt__", [](RationalTime lhs, py::object const& rhs) { + .def( + "__gt__", + [](RationalTime lhs, py::object const& rhs) { return lhs > _type_checked(rhs, ">"); }) - .def("__le__", [](RationalTime lhs, py::object const& rhs) { + .def( + "__le__", + [](RationalTime lhs, py::object const& rhs) { return lhs <= _type_checked(rhs, "<="); }) - .def("__ge__", [](RationalTime lhs, py::object const& rhs) { + .def( + "__ge__", + [](RationalTime lhs, py::object const& rhs) { return lhs >= _type_checked(rhs, ">="); }) - .def("__eq__", [](RationalTime lhs, py::object const& rhs) { + .def( + "__eq__", + [](RationalTime lhs, py::object const& rhs) { return lhs == _type_checked(rhs, "=="); }) - .def("__ne__", [](RationalTime lhs, py::object const& rhs) { + .def( + "__ne__", + [](RationalTime lhs, py::object const& rhs) { return lhs != _type_checked(rhs, "!="); }) .def(py::self - py::self) @@ -198,15 +322,17 @@ For example, the duration of a clip from frame 10 to frame 15 is 6 frames. Resul // to avoid mutating any additional references, since this class has complete value semantics. .def("__iadd__", [](RationalTime lhs, RationalTime rhs) { - return lhs += rhs; - }); + return lhs += rhs; + }); - py::module test = m.def_submodule("_testing", "Module for regression tests"); + py::module test = + m.def_submodule("_testing", "Module for regression tests"); test.def("add_many", [](RationalTime step_time, int final_frame_number) { - RationalTime sum = step_time; - for (int i = 1; i < final_frame_number; i++) { - sum += step_time; - } - return sum; - }); + RationalTime sum = step_time; + for (int i = 1; i < final_frame_number; i++) + { + sum += step_time; + } + return sum; + }); } diff --git a/src/py-opentimelineio/opentime-bindings/opentime_timeRange.cpp b/src/py-opentimelineio/opentime-bindings/opentime_timeRange.cpp index abdb4a3633..7dc4bd79e2 100644 --- a/src/py-opentimelineio/opentime-bindings/opentime_timeRange.cpp +++ b/src/py-opentimelineio/opentime-bindings/opentime_timeRange.cpp @@ -1,48 +1,57 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright Contributors to the OpenTimelineIO project -#include #include +#include -#include "opentime_bindings.h" -#include "opentime/timeRange.h" #include "opentime/stringPrintf.h" +#include "opentime/timeRange.h" +#include "opentime_bindings.h" namespace py = pybind11; using namespace pybind11::literals; using namespace opentime; - -void opentime_timeRange_bindings(py::module m) { +void +opentime_timeRange_bindings(py::module m) +{ py::class_(m, "TimeRange", R"docstring( The TimeRange class represents a range in time. It encodes the start time and the duration, meaning that :meth:`end_time_inclusive` (last portion of a sample in the time range) and :meth:`end_time_exclusive` can be computed. )docstring") // matches the python constructor behavior - .def(py::init( - [](RationalTime* start_time, RationalTime* duration) { - if (start_time == nullptr && duration == nullptr) { - return TimeRange(); - } - else if (start_time == nullptr) { - return TimeRange( - RationalTime(0.0, duration->rate()), - *duration - ); - } - // duration == nullptr - else if (duration == nullptr) { - return TimeRange( - *start_time, - RationalTime(0.0, start_time->rate()) - ); - } - else { - return TimeRange(*start_time, *duration); - } - }), "start_time"_a=nullptr, "duration"_a=nullptr) - .def(py::init(), "start_time"_a, "duration"_a, "rate"_a) + .def( + py::init([](RationalTime* start_time, RationalTime* duration) { + if (start_time == nullptr && duration == nullptr) + { + return TimeRange(); + } + else if (start_time == nullptr) + { + return TimeRange( + RationalTime(0.0, duration->rate()), + *duration); + } + // duration == nullptr + else if (duration == nullptr) + { + return TimeRange( + *start_time, + RationalTime(0.0, start_time->rate())); + } + else + { + return TimeRange(*start_time, *duration); + } + }), + "start_time"_a = nullptr, + "duration"_a = nullptr) + .def( + py::init(), + "start_time"_a, + "duration"_a, + "rate"_a) .def("is_invalid_range", &TimeRange::is_invalid_range, R"docstring( Returns true if the time range is invalid. The time range is considered invalid if either the start time or duration is invalid, or if the duration is less than zero. @@ -73,17 +82,37 @@ because the last time with data in this range is 14. If start frame is 10 and duration is 5.5, then end_time_exclusive is 15.5, because the last time with data in this range is 15. )docstring") - .def("duration_extended_by", &TimeRange::duration_extended_by, "other"_a) - .def("extended_by", &TimeRange::extended_by, "other"_a, "Construct a new :class:`~TimeRange` that is this one extended by other.") - .def("clamped", (RationalTime (TimeRange::*)(RationalTime) const) &TimeRange::clamped, "other"_a, R"docstring( + .def( + "duration_extended_by", + &TimeRange::duration_extended_by, + "other"_a) + .def( + "extended_by", + &TimeRange::extended_by, + "other"_a, + "Construct a new :class:`~TimeRange` that is this one extended by other.") + .def( + "clamped", + (RationalTime (TimeRange::*)(RationalTime) const) + & TimeRange::clamped, + "other"_a, + R"docstring( Clamp 'other' (:class:`~RationalTime`) according to :attr:`start_time`/:attr:`end_time_exclusive` and bound arguments. )docstring") - .def("clamped", (TimeRange (TimeRange::*)(TimeRange) const) &TimeRange::clamped, "other"_a, R"docstring( + .def( + "clamped", + (TimeRange (TimeRange::*)(TimeRange) const) & TimeRange::clamped, + "other"_a, + R"docstring( Clamp 'other' (:class:`~TimeRange`) according to :attr:`start_time`/:attr:`end_time_exclusive` and bound arguments. )docstring") - .def("contains", (bool (TimeRange::*)(RationalTime) const) &TimeRange::contains, "other"_a, R"docstring( + .def( + "contains", + (bool (TimeRange::*)(RationalTime) const) & TimeRange::contains, + "other"_a, + R"docstring( The start of `this` precedes `other`. `other` precedes the end of `this`. :: @@ -94,7 +123,13 @@ The start of `this` precedes `other`. [ this ] )docstring") - .def("contains", (bool (TimeRange::*)(TimeRange, double) const) &TimeRange::contains, "other"_a, "epsilon_s"_a=opentime::DEFAULT_EPSILON_s, R"docstring( + .def( + "contains", + (bool (TimeRange::*)(TimeRange, double) const) + & TimeRange::contains, + "other"_a, + "epsilon_s"_a = opentime::DEFAULT_EPSILON_s, + R"docstring( The start of `this` precedes start of `other`. The end of `this` antecedes end of `other`. :: @@ -104,7 +139,11 @@ The end of `this` antecedes end of `other`. The converse would be ``other.contains(this)`` )docstring") - .def("overlaps", (bool (TimeRange::*)(RationalTime) const) &TimeRange::overlaps, "other"_a, R"docstring( + .def( + "overlaps", + (bool (TimeRange::*)(RationalTime) const) & TimeRange::overlaps, + "other"_a, + R"docstring( `this` contains `other`. :: @@ -114,7 +153,13 @@ The converse would be ``other.contains(this)`` [ this ] )docstring") - .def("overlaps", (bool (TimeRange::*)(TimeRange, double) const) &TimeRange::overlaps, "other"_a, "epsilon_s"_a=opentime::DEFAULT_EPSILON_s, R"docstring( + .def( + "overlaps", + (bool (TimeRange::*)(TimeRange, double) const) + & TimeRange::overlaps, + "other"_a, + "epsilon_s"_a = opentime::DEFAULT_EPSILON_s, + R"docstring( The start of `this` strictly precedes end of `other` by a value >= `epsilon_s`. The end of `this` strictly antecedes start of `other` by a value >= `epsilon_s`. :: @@ -124,7 +169,13 @@ The end of `this` strictly antecedes start of `other` by a value >= `epsilon_s`. The converse would be ``other.overlaps(this)`` )docstring") - .def("before", (bool (TimeRange::*)(RationalTime, double ) const) &TimeRange::before, "other"_a, "epsilon_s"_a=opentime::DEFAULT_EPSILON_s, R"docstring( + .def( + "before", + (bool (TimeRange::*)(RationalTime, double) const) + & TimeRange::before, + "other"_a, + "epsilon_s"_a = opentime::DEFAULT_EPSILON_s, + R"docstring( The end of `this` strictly precedes `other` by a value >= `epsilon_s`. :: @@ -133,7 +184,12 @@ The end of `this` strictly precedes `other` by a value >= `epsilon_s`. [ this ] * )docstring") - .def("before", (bool (TimeRange::*)(TimeRange, double) const) &TimeRange::before, "other"_a, "epsilon_s"_a=opentime::DEFAULT_EPSILON_s, R"docstring( + .def( + "before", + (bool (TimeRange::*)(TimeRange, double) const) & TimeRange::before, + "other"_a, + "epsilon_s"_a = opentime::DEFAULT_EPSILON_s, + R"docstring( The end of `this` strictly equals the start of `other` and the start of `this` strictly equals the end of `other`. :: @@ -142,7 +198,12 @@ the start of `this` strictly equals the end of `other`. The converse would be ``other.meets(this)`` )docstring") - .def("meets", (bool (TimeRange::*)(TimeRange, double) const) &TimeRange::meets, "other"_a, "epsilon_s"_a=opentime::DEFAULT_EPSILON_s, R"docstring( + .def( + "meets", + (bool (TimeRange::*)(TimeRange, double) const) & TimeRange::meets, + "other"_a, + "epsilon_s"_a = opentime::DEFAULT_EPSILON_s, + R"docstring( The end of `this` strictly equals the start of `other` and the start of `this` strictly equals the end of `other`. :: @@ -151,7 +212,13 @@ the start of `this` strictly equals the end of `other`. The converse would be ``other.meets(this)`` )docstring") - .def("begins", (bool (TimeRange::*)(RationalTime, double) const) &TimeRange::begins, "other"_a, "epsilon_s"_a=opentime::DEFAULT_EPSILON_s, R"docstring( + .def( + "begins", + (bool (TimeRange::*)(RationalTime, double) const) + & TimeRange::begins, + "other"_a, + "epsilon_s"_a = opentime::DEFAULT_EPSILON_s, + R"docstring( The start of `this` strictly equals `other`. :: @@ -161,7 +228,12 @@ The start of `this` strictly equals `other`. [ this ] )docstring") - .def("begins", (bool (TimeRange::*)(TimeRange, double) const) &TimeRange::begins, "other"_a, "epsilon_s"_a=opentime::DEFAULT_EPSILON_s, R"docstring( + .def( + "begins", + (bool (TimeRange::*)(TimeRange, double) const) & TimeRange::begins, + "other"_a, + "epsilon_s"_a = opentime::DEFAULT_EPSILON_s, + R"docstring( The start of `this` strictly equals the start of `other`. The end of `this` strictly precedes the end of `other` by a value >= `epsilon_s`. :: @@ -171,7 +243,13 @@ The end of `this` strictly precedes the end of `other` by a value >= `epsilon_s` The converse would be ``other.begins(this)`` )docstring") - .def("finishes", (bool (TimeRange::*)(RationalTime, double) const) &TimeRange::finishes, "other"_a, "epsilon_s"_a=opentime::DEFAULT_EPSILON_s, R"docstring( + .def( + "finishes", + (bool (TimeRange::*)(RationalTime, double) const) + & TimeRange::finishes, + "other"_a, + "epsilon_s"_a = opentime::DEFAULT_EPSILON_s, + R"docstring( The end of `this` strictly equals `other`. :: @@ -181,7 +259,13 @@ The end of `this` strictly equals `other`. [ this ] )docstring") - .def("finishes", (bool (TimeRange::*)(TimeRange, double) const) &TimeRange::finishes, "other"_a, "epsilon_s"_a=opentime::DEFAULT_EPSILON_s, R"docstring( + .def( + "finishes", + (bool (TimeRange::*)(TimeRange, double) const) + & TimeRange::finishes, + "other"_a, + "epsilon_s"_a = opentime::DEFAULT_EPSILON_s, + R"docstring( The start of `this` strictly antecedes the start of `other` by a value >= `epsilon_s`. The end of `this` strictly equals the end of `other`. :: @@ -191,7 +275,13 @@ The end of `this` strictly equals the end of `other`. The converse would be ``other.finishes(this)`` )docstring") - .def("intersects", (bool (TimeRange::*)(TimeRange, double) const) &TimeRange::intersects, "other"_a, "epsilon_s"_a=opentime::DEFAULT_EPSILON_s, R"docstring( + .def( + "intersects", + (bool (TimeRange::*)(TimeRange, double) const) + & TimeRange::intersects, + "other"_a, + "epsilon_s"_a = opentime::DEFAULT_EPSILON_s, + R"docstring( The start of `this` precedes or equals the end of `other` by a value >= `epsilon_s`. The end of `this` antecedes or equals the start of `other` by a value >= `epsilon_s`. :: @@ -201,36 +291,42 @@ The end of `this` antecedes or equals the start of `other` by a value >= `epsilo The converse would be ``other.finishes(this)`` )docstring") - .def("__copy__", [](TimeRange tr) { - return tr; - }) - .def("__deepcopy__", [](TimeRange tr, py::object memo) { - return tr; - }) - .def_static("range_from_start_end_time", &TimeRange::range_from_start_end_time, - "start_time"_a, "end_time_exclusive"_a, R"docstring( + .def("__copy__", [](TimeRange tr) { return tr; }) + .def("__deepcopy__", [](TimeRange tr, py::object memo) { return tr; }) + .def_static( + "range_from_start_end_time", + &TimeRange::range_from_start_end_time, + "start_time"_a, + "end_time_exclusive"_a, + R"docstring( Creates a :class:`~TimeRange` from start and end :class:`~RationalTime`\s (exclusive). For example, if start_time is 1 and end_time is 10, the returned will have a duration of 9. )docstring") - .def_static("range_from_start_end_time_inclusive", &TimeRange::range_from_start_end_time_inclusive, - "start_time"_a, "end_time_inclusive"_a, R"docstring( + .def_static( + "range_from_start_end_time_inclusive", + &TimeRange::range_from_start_end_time_inclusive, + "start_time"_a, + "end_time_inclusive"_a, + R"docstring( Creates a :class:`~TimeRange` from start and end :class:`~RationalTime`\s (inclusive). For example, if start_time is 1 and end_time is 10, the returned will have a duration of 10. )docstring") .def(py::self == py::self) - .def(py::self != py::self) - .def("__str__", [](TimeRange tr) { - return string_printf("TimeRange(%s, %s)", - opentime_python_str(tr.start_time()).c_str(), - opentime_python_str(tr.duration()).c_str()); - + .def(py::self != py::self) + .def( + "__str__", + [](TimeRange tr) { + return string_printf( + "TimeRange(%s, %s)", + opentime_python_str(tr.start_time()).c_str(), + opentime_python_str(tr.duration()).c_str()); }) .def("__repr__", [](TimeRange tr) { - return string_printf("otio.opentime.TimeRange(start_time=%s, duration=%s)", - opentime_python_repr(tr.start_time()).c_str(), - opentime_python_repr(tr.duration()).c_str()); - }) - ; + return string_printf( + "otio.opentime.TimeRange(start_time=%s, duration=%s)", + opentime_python_repr(tr.start_time()).c_str(), + opentime_python_repr(tr.duration()).c_str()); + }); } diff --git a/src/py-opentimelineio/opentime-bindings/opentime_timeTransform.cpp b/src/py-opentimelineio/opentime-bindings/opentime_timeTransform.cpp index 26a05b2453..ba71b9a3ee 100644 --- a/src/py-opentimelineio/opentime-bindings/opentime_timeTransform.cpp +++ b/src/py-opentimelineio/opentime-bindings/opentime_timeTransform.cpp @@ -1,47 +1,68 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright Contributors to the OpenTimelineIO project -#include #include +#include -#include "opentime_bindings.h" #include "opentime/timeTransform.h" +#include "opentime_bindings.h" #include "opentimelineio/stringUtils.h" namespace py = pybind11; using namespace pybind11::literals; using namespace opentime; - -void opentime_timeTransform_bindings(py::module m) { - py::class_(m, "TimeTransform", R"docstring(1D transform for :class:`~RationalTime`. Has offset and scale.)docstring") - .def(py::init(), - "offset"_a = RationalTime(), "scale"_a = 1, "rate"_a = -1) +void +opentime_timeTransform_bindings(py::module m) +{ + py::class_( + m, + "TimeTransform", + R"docstring(1D transform for :class:`~RationalTime`. Has offset and scale.)docstring") + .def( + py::init(), + "offset"_a = RationalTime(), + "scale"_a = 1, + "rate"_a = -1) .def_property_readonly("offset", &TimeTransform::offset) .def_property_readonly("scale", &TimeTransform::scale) .def_property_readonly("rate", &TimeTransform::rate) - .def("applied_to", (TimeRange (TimeTransform::*)(TimeRange) const) &TimeTransform::applied_to, "other"_a) - .def("applied_to", (TimeTransform (TimeTransform::*)(TimeTransform) const) &TimeTransform::applied_to, "other"_a) - .def("applied_to", (RationalTime (TimeTransform::*)(RationalTime) const) &TimeTransform::applied_to, "other"_a) - .def("__copy__", [](TimeTransform const& tt) { - return tt; - }) - .def("__deepcopy__", [](TimeTransform const& tt, py::dict memo) { - return tt; - }, "memo"_a) + .def( + "applied_to", + (TimeRange (TimeTransform::*)(TimeRange) const) + & TimeTransform::applied_to, + "other"_a) + .def( + "applied_to", + (TimeTransform (TimeTransform::*)(TimeTransform) const) + & TimeTransform::applied_to, + "other"_a) + .def( + "applied_to", + (RationalTime (TimeTransform::*)(RationalTime) const) + & TimeTransform::applied_to, + "other"_a) + .def("__copy__", [](TimeTransform const& tt) { return tt; }) + .def( + "__deepcopy__", + [](TimeTransform const& tt, py::dict memo) { return tt; }, + "memo"_a) .def(py::self == py::self) .def(py::self != py::self) - .def("__str__", [](TimeTransform tt) { - return string_printf("TimeTransform(%s, %g, %g)", - opentime_python_str(tt.offset()).c_str(), - tt.scale(), tt.rate()); - + .def( + "__str__", + [](TimeTransform tt) { + return string_printf( + "TimeTransform(%s, %g, %g)", + opentime_python_str(tt.offset()).c_str(), + tt.scale(), + tt.rate()); }) .def("__repr__", [](TimeTransform tt) { - return string_printf("otio.opentime.TimeTransform(offset=%s, scale=%g, rate=%g)", - opentime_python_repr(tt.offset()).c_str(), tt.scale(), tt.rate()); - }) - ; + return string_printf( + "otio.opentime.TimeTransform(offset=%s, scale=%g, rate=%g)", + opentime_python_repr(tt.offset()).c_str(), + tt.scale(), + tt.rate()); + }); } - - diff --git a/src/py-opentimelineio/opentimelineio-bindings/otio_anyDictionary.cpp b/src/py-opentimelineio/opentimelineio-bindings/otio_anyDictionary.cpp index 385fd70db7..1c42656bda 100644 --- a/src/py-opentimelineio/opentimelineio-bindings/otio_anyDictionary.cpp +++ b/src/py-opentimelineio/opentimelineio-bindings/otio_anyDictionary.cpp @@ -1,22 +1,24 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright Contributors to the OpenTimelineIO project -#include #include +#include namespace py = pybind11; using namespace pybind11::literals; -#include "otio_bindings.h" -#include "otio_anyDictionary.h" -#include "otio_anyVector.h" #include "opentime/rationalTime.h" #include "opentime/timeRange.h" #include "opentime/timeTransform.h" #include "opentimelineio/serializableObject.h" #include "opentimelineio/stringUtils.h" +#include "otio_anyDictionary.h" +#include "otio_anyVector.h" +#include "otio_bindings.h" -void otio_any_dictionary_bindings(py::module m) { +void +otio_any_dictionary_bindings(py::module m) +{ py::class_(m, "AnyDictionaryIterator") .def("__iter__", &AnyDictionaryProxy::Iterator::iter) .def("__next__", &AnyDictionaryProxy::Iterator::next); @@ -24,8 +26,15 @@ void otio_any_dictionary_bindings(py::module m) { py::class_(m, "AnyDictionary") .def(py::init<>()) .def("__getitem__", &AnyDictionaryProxy::get_item, "key"_a) - .def("__internal_setitem__", &AnyDictionaryProxy::set_item, "key"_a, "item"_a) + .def( + "__internal_setitem__", + &AnyDictionaryProxy::set_item, + "key"_a, + "item"_a) .def("__delitem__", &AnyDictionaryProxy::del_item, "key"_a) .def("__len__", &AnyDictionaryProxy::len) - .def("__iter__", &AnyDictionaryProxy::iter, py::return_value_policy::reference_internal); + .def( + "__iter__", + &AnyDictionaryProxy::iter, + py::return_value_policy::reference_internal); } diff --git a/src/py-opentimelineio/opentimelineio-bindings/otio_anyDictionary.h b/src/py-opentimelineio/opentimelineio-bindings/otio_anyDictionary.h index c49ebe8876..2a2cf08ea6 100644 --- a/src/py-opentimelineio/opentimelineio-bindings/otio_anyDictionary.h +++ b/src/py-opentimelineio/opentimelineio-bindings/otio_anyDictionary.h @@ -3,46 +3,51 @@ #pragma once -#include #include "otio_utils.h" +#include #include "opentimelineio/anyDictionary.h" namespace py = pybind11; -struct AnyDictionaryProxy : public AnyDictionary::MutationStamp { - ~AnyDictionaryProxy() { - } - +struct AnyDictionaryProxy : public AnyDictionary::MutationStamp +{ + ~AnyDictionaryProxy() {} + using MutationStamp = AnyDictionary::MutationStamp; - static void throw_dictionary_was_deleted() { - throw py::value_error("Underlying C++ AnyDictionary has been destroyed"); + static void throw_dictionary_was_deleted() + { + throw py::value_error( + "Underlying C++ AnyDictionary has been destroyed"); } - struct Iterator { + struct Iterator + { Iterator(MutationStamp& s) - : mutation_stamp(s), - it(s.any_dictionary->begin()), - starting_stamp { s.stamp } { - } + : mutation_stamp(s) + , it(s.any_dictionary->begin()) + , starting_stamp{ s.stamp } + {} - MutationStamp& mutation_stamp; + MutationStamp& mutation_stamp; AnyDictionary::iterator it; - int64_t starting_stamp; - - Iterator* iter() { - return this; - } - - pybind11::object next() { - if (!mutation_stamp.any_dictionary) { + int64_t starting_stamp; + + Iterator* iter() { return this; } + + pybind11::object next() + { + if (!mutation_stamp.any_dictionary) + { throw_dictionary_was_deleted(); } - else if (mutation_stamp.stamp != starting_stamp) { + else if (mutation_stamp.stamp != starting_stamp) + { throw py::value_error("container mutated during iteration"); } - else if (it == mutation_stamp.any_dictionary->end()) { + else if (it == mutation_stamp.any_dictionary->end()) + { throw py::stop_iteration(); } @@ -52,50 +57,57 @@ struct AnyDictionaryProxy : public AnyDictionary::MutationStamp { } }; - py::object get_item(std::string const& key) { + py::object get_item(std::string const& key) + { AnyDictionary& m = fetch_any_dictionary(); auto e = m.find(key); - if (e == m.end()) { + if (e == m.end()) + { throw py::key_error(key); } return any_to_py(e->second); } - void set_item(std::string const& key, PyAny* pyAny) { - AnyDictionary& m = fetch_any_dictionary(); - auto it = m.find(key); - if (it != m.end()) { + void set_item(std::string const& key, PyAny* pyAny) + { + AnyDictionary& m = fetch_any_dictionary(); + auto it = m.find(key); + if (it != m.end()) + { std::swap(it->second, pyAny->a); } - else { + else + { m.emplace(key, std::move(pyAny->a)); } } - - void del_item(std::string const& key) { - AnyDictionary& m = fetch_any_dictionary(); - auto e = m.find(key); - if (e == m.end()) { + + void del_item(std::string const& key) + { + AnyDictionary& m = fetch_any_dictionary(); + auto e = m.find(key); + if (e == m.end()) + { throw py::key_error(key); } m.erase(e); } - int len() { - return int(fetch_any_dictionary().size()); - } - - Iterator* iter() { + int len() { return int(fetch_any_dictionary().size()); } + + Iterator* iter() + { (void) fetch_any_dictionary(); return new Iterator(*this); } - AnyDictionary& fetch_any_dictionary() const { - if (!any_dictionary) { + AnyDictionary& fetch_any_dictionary() const + { + if (!any_dictionary) + { throw_dictionary_was_deleted(); } return *any_dictionary; } }; - diff --git a/src/py-opentimelineio/opentimelineio-bindings/otio_anyVector.cpp b/src/py-opentimelineio/opentimelineio-bindings/otio_anyVector.cpp index 4d974383b2..afe2f80930 100644 --- a/src/py-opentimelineio/opentimelineio-bindings/otio_anyVector.cpp +++ b/src/py-opentimelineio/opentimelineio-bindings/otio_anyVector.cpp @@ -1,32 +1,37 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright Contributors to the OpenTimelineIO project -#include #include +#include namespace py = pybind11; using namespace pybind11::literals; -#include "otio_utils.h" -#include "otio_anyVector.h" #include "opentime/rationalTime.h" #include "opentimelineio/stringUtils.h" +#include "otio_anyVector.h" +#include "otio_utils.h" -void otio_any_vector_bindings(py::module m) { +void +otio_any_vector_bindings(py::module m) +{ py::class_(m, "AnyVectorIterator") .def("__iter__", &AnyVectorProxy::Iterator::iter) .def("__next__", &AnyVectorProxy::Iterator::next); - + py::class_(m, "AnyVector") .def(py::init<>()) .def("__internal_getitem__", &AnyVectorProxy::get_item, "index"_a) - .def("__internal_setitem__", &AnyVectorProxy::set_item, "index"_a, "item"_a) + .def( + "__internal_setitem__", + &AnyVectorProxy::set_item, + "index"_a, + "item"_a) .def("__internal_delitem__", &AnyVectorProxy::del_item, "index"_a) .def("__len__", &AnyVectorProxy::len) .def("__internal_insert", &AnyVectorProxy::insert) - .def("__iter__", &AnyVectorProxy::iter, py::return_value_policy::reference_internal); + .def( + "__iter__", + &AnyVectorProxy::iter, + py::return_value_policy::reference_internal); } - - - - diff --git a/src/py-opentimelineio/opentimelineio-bindings/otio_anyVector.h b/src/py-opentimelineio/opentimelineio-bindings/otio_anyVector.h index ed43e5dec1..0ebeae8385 100644 --- a/src/py-opentimelineio/opentimelineio-bindings/otio_anyVector.h +++ b/src/py-opentimelineio/opentimelineio-bindings/otio_anyVector.h @@ -2,39 +2,44 @@ // Copyright Contributors to the OpenTimelineIO project #pragma once -#include #include "opentimelineio/anyVector.h" #include "opentimelineio/vectorIndexing.h" #include "otio_bindings.h" #include "otio_utils.h" +#include namespace py = pybind11; -struct AnyVectorProxy : public AnyVector::MutationStamp { +struct AnyVectorProxy : public AnyVector::MutationStamp +{ using MutationStamp = AnyVector::MutationStamp; - static void throw_array_was_deleted() { - throw py::value_error("Underlying C++ AnyVector object has been destroyed"); + static void throw_array_was_deleted() + { + throw py::value_error( + "Underlying C++ AnyVector object has been destroyed"); } - struct Iterator { + struct Iterator + { Iterator(MutationStamp& s) - : mutation_stamp(s), - it(0) { - } + : mutation_stamp(s) + , it(0) + {} MutationStamp& mutation_stamp; - size_t it; - - Iterator* iter() { - return this; - } - - py::object next() { - if (!mutation_stamp.any_vector) { + size_t it; + + Iterator* iter() { return this; } + + py::object next() + { + if (!mutation_stamp.any_vector) + { throw_array_was_deleted(); } - else if (it == mutation_stamp.any_vector->size()) { + else if (it == mutation_stamp.any_vector->size()) + { throw py::stop_iteration(); } @@ -42,66 +47,77 @@ struct AnyVectorProxy : public AnyVector::MutationStamp { } }; - py::object get_item(int index) { + py::object get_item(int index) + { AnyVector& v = fetch_any_vector(); - index = adjusted_vector_index(index, v); - if (index < 0 || index >= int(v.size())) { + index = adjusted_vector_index(index, v); + if (index < 0 || index >= int(v.size())) + { throw py::index_error("list index out of range"); } return any_to_py(v[index]); } - void set_item(int index, PyAny* pyAny) { + void set_item(int index, PyAny* pyAny) + { AnyVector& v = fetch_any_vector(); - index = adjusted_vector_index(index, v); - if (index < 0 || index >= int(v.size())) { + index = adjusted_vector_index(index, v); + if (index < 0 || index >= int(v.size())) + { throw py::index_error("list assignment index out of range"); } std::swap(v[index], pyAny->a); } - - void insert(int index, PyAny* pyAny) { + + void insert(int index, PyAny* pyAny) + { AnyVector& v = fetch_any_vector(); - index = adjusted_vector_index(index, v); + index = adjusted_vector_index(index, v); - if (size_t(index) >= v.size()) { + if (size_t(index) >= v.size()) + { v.emplace_back(std::move(pyAny->a)); } - else { + else + { v.insert(v.begin() + std::max(index, 0), std::move(pyAny->a)); } } - void del_item(int index) { + void del_item(int index) + { AnyVector& v = fetch_any_vector(); - if (v.empty()) { + if (v.empty()) + { throw py::index_error("list index out of range"); } index = adjusted_vector_index(index, v); - if (size_t(index) >= v.size()) { + if (size_t(index) >= v.size()) + { v.pop_back(); } - else { + else + { v.erase(v.begin() + std::max(index, 0)); } } - int len() { - return int(fetch_any_vector().size()); - } + int len() { return int(fetch_any_vector().size()); } - Iterator* iter() { + Iterator* iter() + { (void) fetch_any_vector(); return new Iterator(*this); } - AnyVector& fetch_any_vector() { - if (!any_vector) { + AnyVector& fetch_any_vector() + { + if (!any_vector) + { throw_array_was_deleted(); } return *any_vector; } }; - diff --git a/src/py-opentimelineio/opentimelineio-bindings/otio_bindings.cpp b/src/py-opentimelineio/opentimelineio-bindings/otio_bindings.cpp index c714888b4e..f8f8bb6c34 100644 --- a/src/py-opentimelineio/opentimelineio-bindings/otio_bindings.cpp +++ b/src/py-opentimelineio/opentimelineio-bindings/otio_bindings.cpp @@ -1,18 +1,18 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright Contributors to the OpenTimelineIO project -#include -#include -#include "otio_anyDictionary.h" -#include "otio_anyVector.h" #include "otio_bindings.h" -#include "otio_utils.h" -#include "otio_errorStatusHandler.h" -#include "opentimelineio/serialization.h" #include "opentimelineio/deserialization.h" #include "opentimelineio/serializableObject.h" -#include "opentimelineio/typeRegistry.h" +#include "opentimelineio/serialization.h" #include "opentimelineio/stackAlgorithm.h" +#include "opentimelineio/typeRegistry.h" +#include "otio_anyDictionary.h" +#include "otio_anyVector.h" +#include "otio_errorStatusHandler.h" +#include "otio_utils.h" +#include +#include #include @@ -22,27 +22,29 @@ using namespace pybind11::literals; // temporarily disabling this feature while I chew on it const static bool EXCEPTION_ON_DOUBLE_REGISTER = false; -static void register_python_type(py::object class_object, - std::string schema_name, - int schema_version) { - std::function create = - [class_object]() { - py::gil_scoped_acquire acquire; +static void +register_python_type( + py::object class_object, + std::string schema_name, + int schema_version) +{ + std::function create = [class_object]() { + py::gil_scoped_acquire acquire; - py::object python_so = class_object(); - SerializableObject::Retainer<> r(py::cast(python_so)); + py::object python_so = class_object(); + SerializableObject::Retainer<> r( + py::cast(python_so)); - // we need to dispose of the reference to python_so now, - // while r exists to keep the object we just created alive. - // (If we let python_so be destroyed when we leave the function, - // then the C++ object we just created would be immediately - // destroyed then.) + // we need to dispose of the reference to python_so now, + // while r exists to keep the object we just created alive. + // (If we let python_so be destroyed when we leave the function, + // then the C++ object we just created would be immediately + // destroyed then.) - python_so = py::object(); - return r.take_value(); + python_so = py::object(); + return r.take_value(); }; - // @TODO: further discussion required about preventing double registering #if 0 if ( @@ -63,25 +65,28 @@ static void register_python_type(py::object class_object, } #else TypeRegistry::instance().register_type( - schema_name, - schema_version, - nullptr, - create, - schema_name - ); + schema_name, + schema_version, + nullptr, + create, + schema_name); #endif } -static bool register_upgrade_function(std::string const& schema_name, - int version_to_upgrade_to, - std::function const& upgrade_function_obj) { - std::function upgrade_function = [upgrade_function_obj](AnyDictionary* d) { - py::gil_scoped_acquire acquire; - - auto ptr = d->get_or_create_mutation_stamp(); - upgrade_function_obj((AnyDictionaryProxy*)ptr); - }; - +static bool +register_upgrade_function( + std::string const& schema_name, + int version_to_upgrade_to, + std::function const& upgrade_function_obj) +{ + std::function upgrade_function = + [upgrade_function_obj](AnyDictionary* d) { + py::gil_scoped_acquire acquire; + + auto ptr = d->get_or_create_mutation_stamp(); + upgrade_function_obj((AnyDictionaryProxy*) ptr); + }; + // further discussion required about preventing double registering #if 0 if ( @@ -103,28 +108,25 @@ static bool register_upgrade_function(std::string const& schema_name, return true; #else return TypeRegistry::instance().register_upgrade_function( - schema_name, - version_to_upgrade_to, - upgrade_function - ); + schema_name, + version_to_upgrade_to, + upgrade_function); #endif } -static bool +static bool register_downgrade_function( - std::string const& schema_name, - int version_to_downgrade_from, - std::function const& downgrade_function_obj) + std::string const& schema_name, + int version_to_downgrade_from, + std::function const& downgrade_function_obj) { - std::function downgrade_function = ( - [downgrade_function_obj](AnyDictionary* d) - { - py::gil_scoped_acquire acquire; + std::function downgrade_function = + ([downgrade_function_obj](AnyDictionary* d) { + py::gil_scoped_acquire acquire; - auto ptr = d->get_or_create_mutation_stamp(); - downgrade_function_obj((AnyDictionaryProxy*)ptr); - } - ); + auto ptr = d->get_or_create_mutation_stamp(); + downgrade_function_obj((AnyDictionaryProxy*) ptr); + }); // further discussion required about preventing double registering #if 0 @@ -146,27 +148,38 @@ register_downgrade_function( return true; #else return TypeRegistry::instance().register_downgrade_function( - schema_name, - version_to_downgrade_from, - downgrade_function - ) ; + schema_name, + version_to_downgrade_from, + downgrade_function); #endif - } -static void set_type_record(SerializableObject* so, std::string schema_name) { - TypeRegistry::instance().set_type_record(so, schema_name, ErrorStatusHandler()); +static void +set_type_record(SerializableObject* so, std::string schema_name) +{ + TypeRegistry::instance().set_type_record( + so, + schema_name, + ErrorStatusHandler()); } -static SerializableObject* instance_from_schema(std::string schema_name, - int schema_version, py::object data) { +static SerializableObject* +instance_from_schema( + std::string schema_name, + int schema_version, + py::object data) +{ AnyDictionary object_data = py_to_any_dictionary(data); - auto result = TypeRegistry::instance().instance_from_schema(schema_name, schema_version, - object_data, ErrorStatusHandler()); + auto result = TypeRegistry::instance().instance_from_schema( + schema_name, + schema_version, + object_data, + ErrorStatusHandler()); return result; } -PYBIND11_MODULE(_otio, m) { +PYBIND11_MODULE(_otio, m) +{ // Import _opentime before actually creating the bindings // for _otio. This allows the import of _otio without // manually importing _opentime before. For example: python -c 'import opentimelineio._otio' @@ -182,52 +195,50 @@ PYBIND11_MODULE(_otio, m) { otio_tests_bindings(m); m.def( - "_serialize_json_to_string", - []( - PyAny* pyAny, - const schema_version_map& schema_version_targets, - int indent - ) - { - auto result = serialize_json_to_string( - pyAny->a, - &schema_version_targets, - ErrorStatusHandler(), - indent - ); - - return result; + "_serialize_json_to_string", + [](PyAny* pyAny, + const schema_version_map& schema_version_targets, + int indent) { + auto result = serialize_json_to_string( + pyAny->a, + &schema_version_targets, + ErrorStatusHandler(), + indent); + + return result; + }, + "value"_a, + "schema_version_targets"_a, + "indent"_a) + .def( + "_serialize_json_to_file", + [](PyAny* pyAny, + std::string filename, + const schema_version_map& schema_version_targets, + int indent) { + return serialize_json_to_file( + pyAny->a, + filename, + &schema_version_targets, + ErrorStatusHandler(), + indent); }, "value"_a, + "filename"_a, "schema_version_targets"_a, - "indent"_a - ) - .def("_serialize_json_to_file", - []( - PyAny* pyAny, - std::string filename, - const schema_version_map& schema_version_targets, - int indent - ) { - return serialize_json_to_file( - pyAny->a, - filename, - &schema_version_targets, - ErrorStatusHandler(), - indent - ); - }, - "value"_a, - "filename"_a, - "schema_version_targets"_a, - "indent"_a) - .def("deserialize_json_from_string", - [](std::string input) { - std::any result; - deserialize_json_from_string(input, &result, ErrorStatusHandler()); - return any_to_py(result, true /*top_level*/); - }, "input"_a, - R"docstring(Deserialize json string to in-memory objects. + "indent"_a) + .def( + "deserialize_json_from_string", + [](std::string input) { + std::any result; + deserialize_json_from_string( + input, + &result, + ErrorStatusHandler()); + return any_to_py(result, true /*top_level*/); + }, + "input"_a, + R"docstring(Deserialize json string to in-memory objects. :param str input: json string to deserialize @@ -235,14 +246,18 @@ PYBIND11_MODULE(_otio, m) { :rtype: SerializableObject )docstring") - .def("deserialize_json_from_file", - [](std::string filename) { - std::any result; - deserialize_json_from_file(filename, &result, ErrorStatusHandler()); - return any_to_py(result, true /*top_level*/); - }, - "filename"_a, - R"docstring(Deserialize json file to in-memory objects. + .def( + "deserialize_json_from_file", + [](std::string filename) { + std::any result; + deserialize_json_from_file( + filename, + &result, + ErrorStatusHandler()); + return any_to_py(result, true /*top_level*/); + }, + "filename"_a, + R"docstring(Deserialize json file to in-memory objects. :param str filename: path to json file to read @@ -254,18 +269,18 @@ PYBIND11_MODULE(_otio, m) { py::class_(m, "PyAny") // explicitly map python bool, int and double classes so that they // do NOT accidentally cast in valid values - .def(py::init([](py::bool_ b) { - bool result = b.cast(); - return new PyAny(result); - })) - .def(py::init([](py::int_ i) { - int64_t result = i.cast(); - return new PyAny(result); - })) - .def(py::init([](py::float_ d) { - double result = d.cast(); - return new PyAny(result); - })) + .def(py::init([](py::bool_ b) { + bool result = b.cast(); + return new PyAny(result); + })) + .def(py::init([](py::int_ i) { + int64_t result = i.cast(); + return new PyAny(result); + })) + .def(py::init([](py::float_ d) { + double result = d.cast(); + return new PyAny(result); + })) .def(py::init([](std::string s) { return new PyAny(s); })) .def(py::init([](py::none) { return new PyAny(); })) .def(py::init([](SerializableObject* s) { return new PyAny(s); })) @@ -274,57 +289,85 @@ PYBIND11_MODULE(_otio, m) { .def(py::init([](TimeTransform tt) { return new PyAny(tt); })) .def(py::init([](Color c) { return new PyAny(c); })) .def(py::init([](IMATH_NAMESPACE::V2d v2d) { return new PyAny(v2d); })) - .def(py::init([](IMATH_NAMESPACE::Box2d box2d) { return new PyAny(box2d); })) - .def(py::init([](AnyVectorProxy* p) { return new PyAny(p->fetch_any_vector()); })) - .def(py::init([](AnyDictionaryProxy* p) { return new PyAny(p->fetch_any_dictionary()); })) - ; - - m.def("register_serializable_object_type", ®ister_python_type, - "class_object"_a, "schema_name"_a, "schema_version"_a); - m.def("set_type_record", &set_type_record, "serializable_obejct"_a, "schema_name"_a); - m.def("install_external_keepalive_monitor", &install_external_keepalive_monitor, - "so"_a, "apply_now"_a); - m.def("instance_from_schema", &instance_from_schema, - "schema_name"_a, "schema_version"_a, "data"_a, R"docstring( + .def(py::init([](IMATH_NAMESPACE::Box2d box2d) { + return new PyAny(box2d); + })) + .def(py::init([](AnyVectorProxy* p) { + return new PyAny(p->fetch_any_vector()); + })) + .def(py::init([](AnyDictionaryProxy* p) { + return new PyAny(p->fetch_any_dictionary()); + })); + + m.def( + "register_serializable_object_type", + ®ister_python_type, + "class_object"_a, + "schema_name"_a, + "schema_version"_a); + m.def( + "set_type_record", + &set_type_record, + "serializable_obejct"_a, + "schema_name"_a); + m.def( + "install_external_keepalive_monitor", + &install_external_keepalive_monitor, + "so"_a, + "apply_now"_a); + m.def( + "instance_from_schema", + &instance_from_schema, + "schema_name"_a, + "schema_version"_a, + "data"_a, + R"docstring( Return an instance of the schema from data in the data_dict. :raises UnsupportedSchemaError: when the requested schema version is greater than the registered schema version. )docstring"); - m.def("type_version_map", - []() { - schema_version_map tmp; - TypeRegistry::instance().type_version_map(tmp); - return tmp; - }, - R"docstring(Fetch the currently registered schemas and their versions. + m.def( + "type_version_map", + []() { + schema_version_map tmp; + TypeRegistry::instance().type_version_map(tmp); + return tmp; + }, + R"docstring(Fetch the currently registered schemas and their versions. :returns: Map of all registered schema names to their current versions. -:rtype: dict[str, int])docstring" - ); - m.def("register_upgrade_function", ®ister_upgrade_function, - "schema_name"_a, - "version_to_upgrade_to"_a, - "upgrade_function"_a); - m.def("register_downgrade_function", ®ister_downgrade_function, - "schema_name"_a, - "version_to_downgrade_from"_a, - "downgrade_function"_a); +:rtype: dict[str, int])docstring"); + m.def( + "register_upgrade_function", + ®ister_upgrade_function, + "schema_name"_a, + "version_to_upgrade_to"_a, + "upgrade_function"_a); + m.def( + "register_downgrade_function", + ®ister_downgrade_function, + "schema_name"_a, + "version_to_downgrade_from"_a, + "downgrade_function"_a); m.def( - "release_to_schema_version_map", - [](){ return label_to_schema_version_map(CORE_VERSION_MAP);}, - R"docstring(Fetch the compiled in CORE_VERSION_MAP. + "release_to_schema_version_map", + []() { return label_to_schema_version_map(CORE_VERSION_MAP); }, + R"docstring(Fetch the compiled in CORE_VERSION_MAP. The CORE_VERSION_MAP maps OTIO release versions to maps of schema name to schema version and is autogenerated by the OpenTimelineIO build and release system. For example: `{"0.15.0": {"Clip": 2, ...}}` :returns: dictionary mapping core version label to schema_version_map -:rtype: dict[str, dict[str, int]])docstring" - ); - m.def("flatten_stack", [](Stack* s) { - return flatten_stack(s, ErrorStatusHandler()); - }, "in_stack"_a); - m.def("flatten_stack", [](std::vector tracks) { +:rtype: dict[str, dict[str, int]])docstring"); + m.def( + "flatten_stack", + [](Stack* s) { return flatten_stack(s, ErrorStatusHandler()); }, + "in_stack"_a); + m.def( + "flatten_stack", + [](std::vector tracks) { return flatten_stack(tracks, ErrorStatusHandler()); - }, "tracks"_a); + }, + "tracks"_a); void _build_any_to_py_dispatch_table(); _build_any_to_py_dispatch_table(); diff --git a/src/py-opentimelineio/opentimelineio-bindings/otio_errorStatusHandler.cpp b/src/py-opentimelineio/opentimelineio-bindings/otio_errorStatusHandler.cpp index 506a5db686..a6e9895741 100644 --- a/src/py-opentimelineio/opentimelineio-bindings/otio_errorStatusHandler.cpp +++ b/src/py-opentimelineio/opentimelineio-bindings/otio_errorStatusHandler.cpp @@ -2,101 +2,139 @@ // Copyright Contributors to the OpenTimelineIO project #include "otio_errorStatusHandler.h" -#include "opentimelineio/stringUtils.h" #include "opentimelineio/serializableObject.h" +#include "opentimelineio/stringUtils.h" namespace pybind11 { - PYBIND11_RUNTIME_EXCEPTION(not_implemented_error, PyExc_NotImplementedError) +PYBIND11_RUNTIME_EXCEPTION(not_implemented_error, PyExc_NotImplementedError) } namespace py = pybind11; -struct OTIOException : public std::runtime_error { +struct OTIOException : public std::runtime_error +{ using std::runtime_error::runtime_error; }; -struct _NotAChildException : public OTIOException { - using OTIOException::OTIOException; +struct _NotAChildException : public OTIOException +{ + using OTIOException::OTIOException; }; -struct _UnsupportedSchemaException : public OTIOException { - using OTIOException::OTIOException; +struct _UnsupportedSchemaException : public OTIOException +{ + using OTIOException::OTIOException; }; -struct _CannotComputeAvailableRangeException : public OTIOException { - using OTIOException::OTIOException; +struct _CannotComputeAvailableRangeException : public OTIOException +{ + using OTIOException::OTIOException; }; -ErrorStatusHandler::~ErrorStatusHandler() noexcept(false) { - if (!is_error(error_status)) { +ErrorStatusHandler::~ErrorStatusHandler() noexcept(false) +{ + if (!is_error(error_status)) + { return; } - switch(error_status.outcome) { - case ErrorStatus::NOT_IMPLEMENTED: - throw py::not_implemented_error(error_status.details); - case ErrorStatus::ILLEGAL_INDEX: - throw py::index_error(error_status.details); - case ErrorStatus::KEY_NOT_FOUND: - throw py::key_error(error_status.details); - case ErrorStatus::INTERNAL_ERROR: - throw py::value_error(std::string("Internal error (aka \"this is a bug\"):" ) + details()); - case ErrorStatus::UNRESOLVED_OBJECT_REFERENCE: - throw py::value_error("Unresolved object reference while reading: " + details()); - case ErrorStatus::DUPLICATE_OBJECT_REFERENCE: - throw py::value_error("Duplicated object reference while reading: " + details()); - case ErrorStatus::MALFORMED_SCHEMA: - throw py::value_error("Illegal/malformed schema: " + details()); - case ErrorStatus::JSON_PARSE_ERROR: - throw py::value_error("JSON parse error while reading: " + details()); - case ErrorStatus::FILE_OPEN_FAILED: - PyErr_SetFromErrnoWithFilename(PyExc_OSError, details().c_str()); - throw py::error_already_set(); - case ErrorStatus::FILE_WRITE_FAILED: - PyErr_SetFromErrnoWithFilename(PyExc_OSError, details().c_str()); - throw py::error_already_set(); - case ErrorStatus::SCHEMA_VERSION_UNSUPPORTED: - throw _UnsupportedSchemaException(full_details()); - case ErrorStatus::NOT_A_CHILD_OF: - case ErrorStatus::NOT_A_CHILD: - case ErrorStatus::NOT_DESCENDED_FROM: - throw _NotAChildException(full_details()); - case ErrorStatus::CANNOT_COMPUTE_AVAILABLE_RANGE: - throw _CannotComputeAvailableRangeException(full_details()); - case ErrorStatus::OBJECT_CYCLE: - throw py::value_error("Detected SerializableObject cycle while copying/serializing: " + details()); - case ErrorStatus::MEDIA_REFERENCES_DO_NOT_CONTAIN_ACTIVE_KEY: - throw py::value_error("The media references do not contain the active key"); - case ErrorStatus::MEDIA_REFERENCES_CONTAIN_EMPTY_KEY: - throw py::value_error("The media references contain an empty key"); - default: - throw py::value_error(full_details()); + switch (error_status.outcome) + { + case ErrorStatus::NOT_IMPLEMENTED: + throw py::not_implemented_error(error_status.details); + case ErrorStatus::ILLEGAL_INDEX: + throw py::index_error(error_status.details); + case ErrorStatus::KEY_NOT_FOUND: + throw py::key_error(error_status.details); + case ErrorStatus::INTERNAL_ERROR: + throw py::value_error( + std::string("Internal error (aka \"this is a bug\"):") + + details()); + case ErrorStatus::UNRESOLVED_OBJECT_REFERENCE: + throw py::value_error( + "Unresolved object reference while reading: " + details()); + case ErrorStatus::DUPLICATE_OBJECT_REFERENCE: + throw py::value_error( + "Duplicated object reference while reading: " + details()); + case ErrorStatus::MALFORMED_SCHEMA: + throw py::value_error("Illegal/malformed schema: " + details()); + case ErrorStatus::JSON_PARSE_ERROR: + throw py::value_error( + "JSON parse error while reading: " + details()); + case ErrorStatus::FILE_OPEN_FAILED: + PyErr_SetFromErrnoWithFilename(PyExc_OSError, details().c_str()); + throw py::error_already_set(); + case ErrorStatus::FILE_WRITE_FAILED: + PyErr_SetFromErrnoWithFilename(PyExc_OSError, details().c_str()); + throw py::error_already_set(); + case ErrorStatus::SCHEMA_VERSION_UNSUPPORTED: + throw _UnsupportedSchemaException(full_details()); + case ErrorStatus::NOT_A_CHILD_OF: + case ErrorStatus::NOT_A_CHILD: + case ErrorStatus::NOT_DESCENDED_FROM: + throw _NotAChildException(full_details()); + case ErrorStatus::CANNOT_COMPUTE_AVAILABLE_RANGE: + throw _CannotComputeAvailableRangeException(full_details()); + case ErrorStatus::OBJECT_CYCLE: + throw py::value_error( + "Detected SerializableObject cycle while copying/serializing: " + + details()); + case ErrorStatus::MEDIA_REFERENCES_DO_NOT_CONTAIN_ACTIVE_KEY: + throw py::value_error( + "The media references do not contain the active key"); + case ErrorStatus::MEDIA_REFERENCES_CONTAIN_EMPTY_KEY: + throw py::value_error("The media references contain an empty key"); + default: + throw py::value_error(full_details()); } } -std::string ErrorStatusHandler::details() { - if (!error_status.object_details) { +std::string +ErrorStatusHandler::details() +{ + if (!error_status.object_details) + { return error_status.details; } - std::string object_str = py::cast(py::str(py::cast(error_status.object_details))); - return string_printf("%s: %s", error_status.details.c_str(), - object_str.c_str()); + std::string object_str = + py::cast(py::str(py::cast(error_status.object_details))); + return string_printf( + "%s: %s", + error_status.details.c_str(), + object_str.c_str()); } -std::string ErrorStatusHandler::full_details() { - if (!error_status.object_details) { +std::string +ErrorStatusHandler::full_details() +{ + if (!error_status.object_details) + { return error_status.full_description; } - std::string object_str = py::cast(py::str(py::cast(error_status.object_details))); - return string_printf("%s: %s", error_status.full_description.c_str(), - object_str.c_str()); + std::string object_str = + py::cast(py::str(py::cast(error_status.object_details))); + return string_printf( + "%s: %s", + error_status.full_description.c_str(), + object_str.c_str()); } -void otio_exception_bindings(py::module m) { +void +otio_exception_bindings(py::module m) +{ auto otio_exception = py::register_exception(m, "OTIOError"); - py::register_exception<_NotAChildException>(m, "NotAChildError", otio_exception.ptr()); - py::register_exception<_UnsupportedSchemaException>(m, "UnsupportedSchemaError", otio_exception.ptr()); - py::register_exception<_CannotComputeAvailableRangeException>(m, "CannotComputeAvailableRangeError", otio_exception.ptr()); + py::register_exception<_NotAChildException>( + m, + "NotAChildError", + otio_exception.ptr()); + py::register_exception<_UnsupportedSchemaException>( + m, + "UnsupportedSchemaError", + otio_exception.ptr()); + py::register_exception<_CannotComputeAvailableRangeException>( + m, + "CannotComputeAvailableRangeError", + otio_exception.ptr()); } diff --git a/src/py-opentimelineio/opentimelineio-bindings/otio_errorStatusHandler.h b/src/py-opentimelineio/opentimelineio-bindings/otio_errorStatusHandler.h index bf1ea198b7..3359b85d8b 100644 --- a/src/py-opentimelineio/opentimelineio-bindings/otio_errorStatusHandler.h +++ b/src/py-opentimelineio/opentimelineio-bindings/otio_errorStatusHandler.h @@ -3,16 +3,15 @@ #pragma once -#include #include "opentimelineio/errorStatus.h" +#include using namespace opentimelineio::OPENTIMELINEIO_VERSION_NS; -struct ErrorStatusHandler { - operator ErrorStatus* () { - return &error_status; - } - +struct ErrorStatusHandler +{ + operator ErrorStatus*() { return &error_status; } + ~ErrorStatusHandler() noexcept(false); std::string details(); diff --git a/src/py-opentimelineio/opentimelineio-bindings/otio_imath.cpp b/src/py-opentimelineio/opentimelineio-bindings/otio_imath.cpp index 07d6bbaff4..6a75c64935 100644 --- a/src/py-opentimelineio/opentimelineio-bindings/otio_imath.cpp +++ b/src/py-opentimelineio/opentimelineio-bindings/otio_imath.cpp @@ -1,8 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright Contributors to the OpenTimelineIO project -#include #include +#include #include "otio_utils.h" @@ -12,18 +12,29 @@ namespace py = pybind11; template -CLASS _type_checked(py::object const& rhs, char const* op) { - try { +CLASS +_type_checked(py::object const& rhs, char const* op) +{ + try + { return py::cast(rhs); } - catch (...) { - std::string rhs_type = py::cast(rhs.get_type().attr("__name__")); - throw py::type_error(string_printf("Unsupported operand type(s) for %s: " - "%s and %s", typeid(CLASS).name(), op, rhs_type.c_str())); + catch (...) + { + std::string rhs_type = + py::cast(rhs.get_type().attr("__name__")); + throw py::type_error(string_printf( + "Unsupported operand type(s) for %s: " + "%s and %s", + typeid(CLASS).name(), + op, + rhs_type.c_str())); } } -static void define_imath_2d(py::module m) { +static void +define_imath_2d(py::module m) +{ // Note that module_local is used to avoid issues when // Imath classes are binded with Pybind11 more than once. // Using module_local will avoid conflicts in such cases. @@ -33,47 +44,71 @@ static void define_imath_2d(py::module m) { .def(py::init()) .def_readwrite("x", &IMATH_NAMESPACE::V2d::x) .def_readwrite("y", &IMATH_NAMESPACE::V2d::y) - .def("__getitem__", [](IMATH_NAMESPACE::V2d const &v, size_t i) { - return v[i]; - }) - .def("__eq__", [](IMATH_NAMESPACE::V2d lhs, py::object const& rhs) { + .def( + "__getitem__", + [](IMATH_NAMESPACE::V2d const& v, size_t i) { return v[i]; }) + .def( + "__eq__", + [](IMATH_NAMESPACE::V2d lhs, py::object const& rhs) { return lhs == _type_checked(rhs, "=="); }) - .def("__ne__", [](IMATH_NAMESPACE::V2d lhs, py::object const& rhs) { + .def( + "__ne__", + [](IMATH_NAMESPACE::V2d lhs, py::object const& rhs) { return lhs != _type_checked(rhs, "!="); }) - .def("__xor__", [](IMATH_NAMESPACE::V2d lhs, py::object const& rhs) { + .def( + "__xor__", + [](IMATH_NAMESPACE::V2d lhs, py::object const& rhs) { return lhs ^ _type_checked(rhs, "^"); }) - .def("__mod__", [](IMATH_NAMESPACE::V2d lhs, py::object const& rhs) { + .def( + "__mod__", + [](IMATH_NAMESPACE::V2d lhs, py::object const& rhs) { return lhs % _type_checked(rhs, "%"); }) - .def("__iadd__", [](IMATH_NAMESPACE::V2d lhs, IMATH_NAMESPACE::V2d rhs) { + .def( + "__iadd__", + [](IMATH_NAMESPACE::V2d lhs, IMATH_NAMESPACE::V2d rhs) { return lhs += rhs; }) - .def("__isub__", [](IMATH_NAMESPACE::V2d lhs, IMATH_NAMESPACE::V2d rhs) { + .def( + "__isub__", + [](IMATH_NAMESPACE::V2d lhs, IMATH_NAMESPACE::V2d rhs) { return lhs -= rhs; }) - .def("__imul__", [](IMATH_NAMESPACE::V2d lhs, IMATH_NAMESPACE::V2d rhs) { + .def( + "__imul__", + [](IMATH_NAMESPACE::V2d lhs, IMATH_NAMESPACE::V2d rhs) { return lhs *= rhs; }) - .def("__idiv__", [](IMATH_NAMESPACE::V2d lhs, IMATH_NAMESPACE::V2d rhs) { + .def( + "__idiv__", + [](IMATH_NAMESPACE::V2d lhs, IMATH_NAMESPACE::V2d rhs) { return lhs /= rhs; }) .def(py::self - py::self) .def(py::self + py::self) .def(py::self * py::self) .def(py::self / py::self) - .def("equalWithAbsError", [](IMATH_NAMESPACE::V2d* v, IMATH_NAMESPACE::V2d const & v2, double e) { - return v->equalWithAbsError(v2, e); - }) - .def("equalWithRelError", [](IMATH_NAMESPACE::V2d* v, IMATH_NAMESPACE::V2d const & v2, double e) { - return v->equalWithRelError(v2, e); - }) - .def("dot", [](IMATH_NAMESPACE::V2d* v, IMATH_NAMESPACE::V2d const & v2) { + .def( + "equalWithAbsError", + [](IMATH_NAMESPACE::V2d* v, + IMATH_NAMESPACE::V2d const& v2, + double e) { return v->equalWithAbsError(v2, e); }) + .def( + "equalWithRelError", + [](IMATH_NAMESPACE::V2d* v, + IMATH_NAMESPACE::V2d const& v2, + double e) { return v->equalWithRelError(v2, e); }) + .def( + "dot", + [](IMATH_NAMESPACE::V2d* v, IMATH_NAMESPACE::V2d const& v2) { return v->dot(v2); }) - .def("cross", [](IMATH_NAMESPACE::V2d* v, IMATH_NAMESPACE::V2d const & v2) { + .def( + "cross", + [](IMATH_NAMESPACE::V2d* v, IMATH_NAMESPACE::V2d const& v2) { return v->cross(v2); }) .def("length", &IMATH_NAMESPACE::V2d::length) @@ -84,49 +119,65 @@ static void define_imath_2d(py::module m) { .def("normalized", &IMATH_NAMESPACE::V2d::normalized) .def("normalizedExc", &IMATH_NAMESPACE::V2d::normalizedExc) .def("normalizedNonNull", &IMATH_NAMESPACE::V2d::normalizedNonNull) - .def_static("baseTypeLowest", []() { - return IMATH_NAMESPACE::V2d::baseTypeLowest(); - }) - .def_static("baseTypeMax", []() { - return IMATH_NAMESPACE::V2d::baseTypeMax(); - }) - .def_static("baseTypeSmallest", []() { - return IMATH_NAMESPACE::V2d::baseTypeSmallest(); - }) - .def_static("baseTypeEpsilon", []() { - return IMATH_NAMESPACE::V2d::baseTypeEpsilon(); - }) + .def_static( + "baseTypeLowest", + []() { return IMATH_NAMESPACE::V2d::baseTypeLowest(); }) + .def_static( + "baseTypeMax", + []() { return IMATH_NAMESPACE::V2d::baseTypeMax(); }) + .def_static( + "baseTypeSmallest", + []() { return IMATH_NAMESPACE::V2d::baseTypeSmallest(); }) + .def_static( + "baseTypeEpsilon", + []() { return IMATH_NAMESPACE::V2d::baseTypeEpsilon(); }) .def_static("dimensions", []() { - return IMATH_NAMESPACE::V2d::dimensions(); - }); + return IMATH_NAMESPACE::V2d::dimensions(); + }); py::class_(m, "Box2d", py::module_local()) - .def(py::init<>([]() { return IMATH_NAMESPACE::Box2d(IMATH_NAMESPACE::V2d(0.0, 0.0)); })) + .def(py::init<>([]() { + return IMATH_NAMESPACE::Box2d(IMATH_NAMESPACE::V2d(0.0, 0.0)); + })) .def(py::init()) .def(py::init()) .def_readwrite("min", &IMATH_NAMESPACE::Box2d::min) .def_readwrite("max", &IMATH_NAMESPACE::Box2d::max) - .def("__eq__", [](IMATH_NAMESPACE::Box2d lhs, py::object const& rhs) { - return lhs == _type_checked(rhs, "=="); - }) - .def("__ne__", [](IMATH_NAMESPACE::Box2d lhs, py::object const& rhs) { - return lhs != _type_checked(rhs, "!="); - }) + .def( + "__eq__", + [](IMATH_NAMESPACE::Box2d lhs, py::object const& rhs) { + return lhs == _type_checked(rhs, "=="); + }) + .def( + "__ne__", + [](IMATH_NAMESPACE::Box2d lhs, py::object const& rhs) { + return lhs != _type_checked(rhs, "!="); + }) .def("center", &IMATH_NAMESPACE::Box2d::center) - .def("extendBy", [](IMATH_NAMESPACE::Box2d* box, IMATH_NAMESPACE::V2d const& point ) { - return box->extendBy(point); - }) - .def("extendBy", [](IMATH_NAMESPACE::Box2d* box, IMATH_NAMESPACE::Box2d const& rhs ) { - return box->extendBy(rhs); - }) - .def("intersects", [](IMATH_NAMESPACE::Box2d* box, IMATH_NAMESPACE::V2d const& point ) { - return box->intersects(point); - }) - .def("intersects", [](IMATH_NAMESPACE::Box2d* box, IMATH_NAMESPACE::Box2d const& rhs ) { - return box->intersects(rhs); - }); + .def( + "extendBy", + [](IMATH_NAMESPACE::Box2d* box, IMATH_NAMESPACE::V2d const& point) { + return box->extendBy(point); + }) + .def( + "extendBy", + [](IMATH_NAMESPACE::Box2d* box, IMATH_NAMESPACE::Box2d const& rhs) { + return box->extendBy(rhs); + }) + .def( + "intersects", + [](IMATH_NAMESPACE::Box2d* box, IMATH_NAMESPACE::V2d const& point) { + return box->intersects(point); + }) + .def( + "intersects", + [](IMATH_NAMESPACE::Box2d* box, IMATH_NAMESPACE::Box2d const& rhs) { + return box->intersects(rhs); + }); } -void otio_imath_bindings(py::module m) { +void +otio_imath_bindings(py::module m) +{ define_imath_2d(m); } diff --git a/src/py-opentimelineio/opentimelineio-bindings/otio_serializableObjects.cpp b/src/py-opentimelineio/opentimelineio-bindings/otio_serializableObjects.cpp index e928336ad1..4268a4cf64 100644 --- a/src/py-opentimelineio/opentimelineio-bindings/otio_serializableObjects.cpp +++ b/src/py-opentimelineio/opentimelineio-bindings/otio_serializableObjects.cpp @@ -1,10 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright Contributors to the OpenTimelineIO project -#include +#include "otio_errorStatusHandler.h" #include +#include #include -#include "otio_errorStatusHandler.h" #include "opentimelineio/clip.h" #include "opentimelineio/color.h" @@ -21,86 +21,167 @@ #include "opentimelineio/marker.h" #include "opentimelineio/mediaReference.h" #include "opentimelineio/missingReference.h" +#include "opentimelineio/serializableCollection.h" #include "opentimelineio/stack.h" #include "opentimelineio/timeEffect.h" #include "opentimelineio/timeline.h" #include "opentimelineio/track.h" #include "opentimelineio/transition.h" -#include "opentimelineio/serializableCollection.h" -#include "opentimelineio/stack.h" #include "opentimelineio/unknownSchema.h" -#include "otio_utils.h" #include "otio_anyDictionary.h" +#include "otio_utils.h" #include "Imath/ImathBox.h" namespace py = pybind11; using namespace pybind11::literals; -using MarkerVectorProxy = - MutableSequencePyAPI>, Marker*>; +using MarkerVectorProxy = MutableSequencePyAPI< + std::vector>, + Marker*>; -using EffectVectorProxy = - MutableSequencePyAPI>, Effect*>; +using EffectVectorProxy = MutableSequencePyAPI< + std::vector>, + Effect*>; -using TrackVectorProxy = - MutableSequencePyAPI>, Track*>; +using TrackVectorProxy = MutableSequencePyAPI< + std::vector>, + Track*>; using SOWithMetadata = SerializableObjectWithMetadata; namespace { - template - std::vector vector_or_default(std::optional> item) { - if (item.has_value()) { - return item.value(); - } - - return std::vector(); +template +std::vector +vector_or_default(std::optional> item) +{ + if (item.has_value()) + { + return item.value(); } - template - bool find_children(T* t, py::object descended_from_type, std::optional const& search_range, bool shallow_search, std::vector& l) { - if (descended_from_type.is(py::type::handle_of())) + return std::vector(); +} + +template +bool +find_children( + T* t, + py::object descended_from_type, + std::optional const& search_range, + bool shallow_search, + std::vector& l) +{ + if (descended_from_type.is(py::type::handle_of())) + { + for (const auto& child: t->template find_children( + ErrorStatusHandler(), + search_range, + shallow_search)) { - for (const auto& child : t->template find_children(ErrorStatusHandler(), search_range, shallow_search)) { - l.push_back(child.value); - } - return true; + l.push_back(child.value); } - return false; + return true; } + return false; +} - template - std::vector find_children(T* t, py::object descended_from_type, std::optional const& search_range, bool shallow_search = false) { - std::vector l; - if (find_children(t, descended_from_type, search_range, shallow_search, l)) ; - else if (find_children(t, descended_from_type, search_range, shallow_search, l)) ; - else if (find_children(t, descended_from_type, search_range, shallow_search, l)) ; - else if (find_children(t, descended_from_type, search_range, shallow_search, l)) ; - else if (find_children(t, descended_from_type, search_range, shallow_search, l)) ; - else if (find_children(t, descended_from_type, search_range, shallow_search, l)) ; - else if (find_children(t, descended_from_type, search_range, shallow_search, l)) ; - else if (find_children(t, descended_from_type, search_range, shallow_search, l)) ; - else +template +std::vector +find_children( + T* t, + py::object descended_from_type, + std::optional const& search_range, + bool shallow_search = false) +{ + std::vector l; + if (find_children( + t, + descended_from_type, + search_range, + shallow_search, + l)) + ; + else if (find_children( + t, + descended_from_type, + search_range, + shallow_search, + l)) + ; + else if (find_children( + t, + descended_from_type, + search_range, + shallow_search, + l)) + ; + else if (find_children( + t, + descended_from_type, + search_range, + shallow_search, + l)) + ; + else if (find_children( + t, + descended_from_type, + search_range, + shallow_search, + l)) + ; + else if (find_children( + t, + descended_from_type, + search_range, + shallow_search, + l)) + ; + else if (find_children( + t, + descended_from_type, + search_range, + shallow_search, + l)) + ; + else if (find_children( + t, + descended_from_type, + search_range, + shallow_search, + l)) + ; + else + { + for (const auto& child: t->template find_children( + ErrorStatusHandler(), + search_range, + shallow_search)) { - for (const auto& child : t->template find_children(ErrorStatusHandler(), search_range, shallow_search)) { - l.push_back(child.value); - } + l.push_back(child.value); } - return l; } + return l; +} - template - std::vector find_clips(T* t, std::optional const& search_range, bool shallow_search = false) { - std::vector l; - for (const auto& clip : t->find_clips(ErrorStatusHandler(), search_range, shallow_search)) { - l.push_back(clip.value); - } - return l; +template +std::vector +find_clips( + T* t, + std::optional const& search_range, + bool shallow_search = false) +{ + std::vector l; + for (const auto& clip: + t->find_clips(ErrorStatusHandler(), search_range, shallow_search)) + { + l.push_back(clip.value); } + return l; } +} // namespace /* template static std::string repr(T const& value) { @@ -131,19 +212,20 @@ static std::string str(AnyDictionary& value) { */ template -class ContainerIterator { +class ContainerIterator +{ public: ContainerIterator(CONTAINER* container) - : _container(container), - _it(0) { - } + : _container(container) + , _it(0) + {} - ContainerIterator* iter() { - return this; - } + ContainerIterator* iter() { return this; } - ITEM next() { - if (_it == _container->children().size()) { + ITEM next() + { + if (_it == _container->children().size()) + { throw pybind11::stop_iteration(); } @@ -152,63 +234,126 @@ class ContainerIterator { private: CONTAINER* _container; - size_t _it; + size_t _it; }; -static void define_bases1(py::module m) { - py::class_>(m, "SerializableObject", py::dynamic_attr(), "Superclass for all classes whose instances can be serialized.") +static void +define_bases1(py::module m) +{ + py::class_>( + m, + "SerializableObject", + py::dynamic_attr(), + "Superclass for all classes whose instances can be serialized.") .def(py::init<>()) - .def_property_readonly("_dynamic_fields", [](SerializableObject* s) { + .def_property_readonly( + "_dynamic_fields", + [](SerializableObject* s) { auto ptr = s->dynamic_fields().get_or_create_mutation_stamp(); - return (AnyDictionaryProxy*)(ptr); }, py::return_value_policy::take_ownership) - .def("is_equivalent_to", &SerializableObject::is_equivalent_to, "other"_a.none(false)) - .def("clone", [](SerializableObject* so) { - return so->clone(ErrorStatusHandler()); }) - .def("to_json_string", [](SerializableObject* so, int indent) { - return so->to_json_string(ErrorStatusHandler(), {}, indent); }, + return (AnyDictionaryProxy*) (ptr); + }, + py::return_value_policy::take_ownership) + .def( + "is_equivalent_to", + &SerializableObject::is_equivalent_to, + "other"_a.none(false)) + .def( + "clone", + [](SerializableObject* so) { + return so->clone(ErrorStatusHandler()); + }) + .def( + "to_json_string", + [](SerializableObject* so, int indent) { + return so->to_json_string(ErrorStatusHandler(), {}, indent); + }, "indent"_a = 4) - .def("to_json_file", [](SerializableObject* so, std::string file_name, int indent) { - return so->to_json_file(file_name, ErrorStatusHandler(), {}, indent); }, + .def( + "to_json_file", + [](SerializableObject* so, std::string file_name, int indent) { + return so + ->to_json_file(file_name, ErrorStatusHandler(), {}, indent); + }, "file_name"_a, "indent"_a = 4) - .def_static("from_json_file", [](std::string file_name) { - return SerializableObject::from_json_file(file_name, ErrorStatusHandler()); }, + .def_static( + "from_json_file", + [](std::string file_name) { + return SerializableObject::from_json_file( + file_name, + ErrorStatusHandler()); + }, "file_name"_a) - .def_static("from_json_string", [](std::string input) { - return SerializableObject::from_json_string(input, ErrorStatusHandler()); + .def_static( + "from_json_string", + [](std::string input) { + return SerializableObject::from_json_string( + input, + ErrorStatusHandler()); }, "input"_a) .def("schema_name", &SerializableObject::schema_name) .def("schema_version", &SerializableObject::schema_version) - .def_property_readonly("is_unknown_schema", &SerializableObject::is_unknown_schema); - - py::class_>(m, "UnknownSchema") - .def_property_readonly("original_schema_name", &UnknownSchema::original_schema_name) - .def_property_readonly("original_schema_version", &UnknownSchema::original_schema_version); - - py::class_>(m, "SerializableObjectWithMetadata", py::dynamic_attr()) - .def(py::init([](std::string name, py::object metadata) { - return new SOWithMetadata(name, py_to_any_dictionary(metadata)); - }), + .def_property_readonly( + "is_unknown_schema", + &SerializableObject::is_unknown_schema); + + py::class_>( + m, + "UnknownSchema") + .def_property_readonly( + "original_schema_name", + &UnknownSchema::original_schema_name) + .def_property_readonly( + "original_schema_version", + &UnknownSchema::original_schema_version); + + py::class_< + SOWithMetadata, + SerializableObject, + managing_ptr>( + m, + "SerializableObjectWithMetadata", + py::dynamic_attr()) + .def( + py::init([](std::string name, py::object metadata) { + return new SOWithMetadata(name, py_to_any_dictionary(metadata)); + }), py::arg_v("name"_a = std::string()), py::arg_v("metadata"_a = py::none())) - .def_property_readonly("metadata", [](SOWithMetadata* s) { + .def_property_readonly( + "metadata", + [](SOWithMetadata* s) { auto ptr = s->metadata().get_or_create_mutation_stamp(); - return (AnyDictionaryProxy*)(ptr); }, py::return_value_policy::take_ownership) - .def_property("name", [](SOWithMetadata* so) { - return plain_string(so->name()); - }, &SOWithMetadata::set_name); + return (AnyDictionaryProxy*) (ptr); + }, + py::return_value_policy::take_ownership) + .def_property( + "name", + [](SOWithMetadata* so) { return plain_string(so->name()); }, + &SOWithMetadata::set_name); } -static void define_bases2(py::module m) { +static void +define_bases2(py::module m) +{ MarkerVectorProxy::define_py_class(m, "MarkerVector"); EffectVectorProxy::define_py_class(m, "EffectVector"); - py::class_(m, "Color", py::dynamic_attr(), R"docstring(:class:`Color` is a definition of red, green, blue, and alpha double floating point values, allowing conversion between different formats. To be considered interoperable, the sRGB transfer function encoded values, ranging between zero and one, are expected to be accurate to within 1/255 of the intended value. Round-trip conversions may not be guaranteed outside that. This Color class is meant for use in user interface elements, like marker or clip coloring, NOT for image pixel content.)docstring") - .def(py::init([](double r, double g, double b, double a, std::string name) { - return new Color(r, g, b, a, name); - }), "r"_a = 1.0, "g"_a = 1.0, "b"_a = 1.0, "a"_a = 1.0, + py::class_( + m, + "Color", + py::dynamic_attr(), + R"docstring(:class:`Color` is a definition of red, green, blue, and alpha double floating point values, allowing conversion between different formats. To be considered interoperable, the sRGB transfer function encoded values, ranging between zero and one, are expected to be accurate to within 1/255 of the intended value. Round-trip conversions may not be guaranteed outside that. This Color class is meant for use in user interface elements, like marker or clip coloring, NOT for image pixel content.)docstring") + .def( + py::init( + [](double r, double g, double b, double a, std::string name) { + return new Color(r, g, b, a, name); + }), + "r"_a = 1.0, + "g"_a = 1.0, + "b"_a = 1.0, + "a"_a = 1.0, py::arg_v("name"_a = std::string())) .def_property("r", &Color::r, &Color::set_r) .def_property("g", &Color::g, &Color::set_g) @@ -220,74 +365,157 @@ static void define_bases2(py::module m) { .def("to_rgba_int_list", &Color::to_rgba_int_list, py::arg("base") = 8) .def("to_agbr_integer", &Color::to_agbr_integer) .def("to_rgba_float_list", &Color::to_rgba_float_list) - - .def_static("from_hex", Color::from_hex) + + .def_static("from_hex", Color::from_hex) .def_static("from_float_list", &Color::from_float_list) .def_static("from_int_list", &Color::from_int_list) .def_static("from_agbr_int", &Color::from_agbr_int) - .def_property_readonly_static("PINK", [](py::object) { return new Color(Color::pink); }, py::return_value_policy::take_ownership) - .def_property_readonly_static("RED", [](py::object) { return new Color(Color::red); }, py::return_value_policy::take_ownership) - .def_property_readonly_static("ORANGE", [](py::object) { return new Color(Color::orange); }, py::return_value_policy::take_ownership) - .def_property_readonly_static("YELLOW", [](py::object) { return new Color(Color::yellow); }, py::return_value_policy::take_ownership) - .def_property_readonly_static("GREEN", [](py::object) { return new Color(Color::green); }, py::return_value_policy::take_ownership) - .def_property_readonly_static("CYAN", [](py::object) { return new Color(Color::cyan); }, py::return_value_policy::take_ownership) - .def_property_readonly_static("BLUE", [](py::object) { return new Color(Color::blue); }, py::return_value_policy::take_ownership) - .def_property_readonly_static("PURPLE", [](py::object) { return new Color(Color::purple); }, py::return_value_policy::take_ownership) - .def_property_readonly_static("MAGENTA", [](py::object) { return new Color(Color::magenta); }, py::return_value_policy::take_ownership) - .def_property_readonly_static("BLACK", [](py::object) { return new Color(Color::black); }, py::return_value_policy::take_ownership) - .def_property_readonly_static("WHITE", [](py::object) { return new Color(Color::white); }, py::return_value_policy::take_ownership) - .def_property_readonly_static("TRANSPARENT", [](py::object) { return new Color(Color::transparent); }, py::return_value_policy::take_ownership); + .def_property_readonly_static( + "PINK", + [](py::object) { return new Color(Color::pink); }, + py::return_value_policy::take_ownership) + .def_property_readonly_static( + "RED", + [](py::object) { return new Color(Color::red); }, + py::return_value_policy::take_ownership) + .def_property_readonly_static( + "ORANGE", + [](py::object) { return new Color(Color::orange); }, + py::return_value_policy::take_ownership) + .def_property_readonly_static( + "YELLOW", + [](py::object) { return new Color(Color::yellow); }, + py::return_value_policy::take_ownership) + .def_property_readonly_static( + "GREEN", + [](py::object) { return new Color(Color::green); }, + py::return_value_policy::take_ownership) + .def_property_readonly_static( + "CYAN", + [](py::object) { return new Color(Color::cyan); }, + py::return_value_policy::take_ownership) + .def_property_readonly_static( + "BLUE", + [](py::object) { return new Color(Color::blue); }, + py::return_value_policy::take_ownership) + .def_property_readonly_static( + "PURPLE", + [](py::object) { return new Color(Color::purple); }, + py::return_value_policy::take_ownership) + .def_property_readonly_static( + "MAGENTA", + [](py::object) { return new Color(Color::magenta); }, + py::return_value_policy::take_ownership) + .def_property_readonly_static( + "BLACK", + [](py::object) { return new Color(Color::black); }, + py::return_value_policy::take_ownership) + .def_property_readonly_static( + "WHITE", + [](py::object) { return new Color(Color::white); }, + py::return_value_policy::take_ownership) + .def_property_readonly_static( + "TRANSPARENT", + [](py::object) { return new Color(Color::transparent); }, + py::return_value_policy::take_ownership); auto marker_class = - py::class_>(m, "Marker", py::dynamic_attr(), R"docstring( + py::class_>( + m, + "Marker", + py::dynamic_attr(), + R"docstring( A marker indicates a marked range of time on an item in a timeline, usually with a name, color or other metadata. The marked range may have a zero duration. The marked range is in the owning item's time coordinate system. )docstring") - .def(py::init([]( - std::string name, - TimeRange marked_range, - std::string const& color, - py::object metadata, - std::string const& comment) { - return new Marker( - name, - marked_range, - color, - py_to_any_dictionary(metadata), - comment); - }), - py::arg_v("name"_a = std::string()), - "marked_range"_a = TimeRange(), - "color"_a = std::string(Marker::Color::red), - py::arg_v("metadata"_a = py::none()), - "comment"_a = std::string()) - .def_property("color", &Marker::color, &Marker::set_color, "Color string for this marker (for example: 'RED'), based on the :class:`~Color` enum.") - .def_property("marked_range", &Marker::marked_range, &Marker::set_marked_range, "Range this marker applies to, relative to the :class:`.Item` this marker is attached to (e.g. the :class:`.Clip` or :class:`.Track` that owns this marker).") - .def_property("comment", &Marker::comment, &Marker::set_comment, "Optional comment for this marker."); + .def( + py::init([](std::string name, + TimeRange marked_range, + std::string const& color, + py::object metadata, + std::string const& comment) { + return new Marker( + name, + marked_range, + color, + py_to_any_dictionary(metadata), + comment); + }), + py::arg_v("name"_a = std::string()), + "marked_range"_a = TimeRange(), + "color"_a = std::string(Marker::Color::red), + py::arg_v("metadata"_a = py::none()), + "comment"_a = std::string()) + .def_property( + "color", + &Marker::color, + &Marker::set_color, + "Color string for this marker (for example: 'RED'), based on the :class:`~Color` enum.") + .def_property( + "marked_range", + &Marker::marked_range, + &Marker::set_marked_range, + "Range this marker applies to, relative to the :class:`.Item` this marker is attached to (e.g. the :class:`.Clip` or :class:`.Track` that owns this marker).") + .def_property( + "comment", + &Marker::comment, + &Marker::set_comment, + "Optional comment for this marker."); py::class_(marker_class, "Color") - .def_property_readonly_static("PINK", [](py::object /* self */) { return Marker::Color::pink; }) - .def_property_readonly_static("RED", [](py::object /* self */) { return Marker::Color::red; }) - .def_property_readonly_static("ORANGE", [](py::object /* self */) { return Marker::Color::orange; }) - .def_property_readonly_static("YELLOW", [](py::object /* self */) { return Marker::Color::yellow; }) - .def_property_readonly_static("GREEN", [](py::object /* self */) { return Marker::Color::green; }) - .def_property_readonly_static("CYAN", [](py::object /* self */) { return Marker::Color::cyan; }) - .def_property_readonly_static("BLUE", [](py::object /* self */) { return Marker::Color::blue; }) - .def_property_readonly_static("PURPLE", [](py::object /* self */) { return Marker::Color::purple; }) - .def_property_readonly_static("MAGENTA", [](py::object /* self */) { return Marker::Color::magenta; }) - .def_property_readonly_static("BLACK", [](py::object /* self */) { return Marker::Color::black; }) - .def_property_readonly_static("WHITE", [](py::object /* self */) { return Marker::Color::white; }); - - - using SerializableCollectionIterator = ContainerIterator; - py::class_(m, "SerializableCollectionIterator", py::dynamic_attr()) + .def_property_readonly_static( + "PINK", + [](py::object /* self */) { return Marker::Color::pink; }) + .def_property_readonly_static( + "RED", + [](py::object /* self */) { return Marker::Color::red; }) + .def_property_readonly_static( + "ORANGE", + [](py::object /* self */) { return Marker::Color::orange; }) + .def_property_readonly_static( + "YELLOW", + [](py::object /* self */) { return Marker::Color::yellow; }) + .def_property_readonly_static( + "GREEN", + [](py::object /* self */) { return Marker::Color::green; }) + .def_property_readonly_static( + "CYAN", + [](py::object /* self */) { return Marker::Color::cyan; }) + .def_property_readonly_static( + "BLUE", + [](py::object /* self */) { return Marker::Color::blue; }) + .def_property_readonly_static( + "PURPLE", + [](py::object /* self */) { return Marker::Color::purple; }) + .def_property_readonly_static( + "MAGENTA", + [](py::object /* self */) { return Marker::Color::magenta; }) + .def_property_readonly_static( + "BLACK", + [](py::object /* self */) { return Marker::Color::black; }) + .def_property_readonly_static("WHITE", [](py::object /* self */) { + return Marker::Color::white; + }); + + using SerializableCollectionIterator = + ContainerIterator; + py::class_( + m, + "SerializableCollectionIterator", + py::dynamic_attr()) .def("__iter__", &SerializableCollectionIterator::iter) .def("__next__", &SerializableCollectionIterator::next); - py::class_>(m, "SerializableCollection", py::dynamic_attr(), R"docstring( + py::class_< + SerializableCollection, + SOWithMetadata, + managing_ptr>( + m, + "SerializableCollection", + py::dynamic_attr(), + R"docstring( A container which can hold an ordered list of any serializable objects. Note that this is not a :class:`.Composition` nor is it :class:`.Composable`. This container approximates the concept of a bin - a collection of :class:`.SerializableObject`\s that do @@ -296,447 +524,788 @@ a named collection. A :class:`~SerializableCollection` is useful for serializing multiple timelines, clips, or media references to a single file. )docstring") - .def(py::init([](std::string const& name, std::optional> children, - py::object metadata) { - return new SerializableCollection(name, - vector_or_default(children), - py_to_any_dictionary(metadata)); }), - py::arg_v("name"_a = std::string()), - "children"_a = py::none(), - py::arg_v("metadata"_a = py::none())) - .def("__internal_getitem__", [](SerializableCollection* c, int index) { + .def( + py::init( + [](std::string const& name, + std::optional> children, + py::object metadata) { + return new SerializableCollection( + name, + vector_or_default(children), + py_to_any_dictionary(metadata)); + }), + py::arg_v("name"_a = std::string()), + "children"_a = py::none(), + py::arg_v("metadata"_a = py::none())) + .def( + "__internal_getitem__", + [](SerializableCollection* c, int index) { index = adjusted_vector_index(index, c->children()); - if (index < 0 || index >= int(c->children().size())) { + if (index < 0 || index >= int(c->children().size())) + { throw py::index_error(); } return c->children()[index].value; - }, "index"_a) - .def("__internal_setitem__", [](SerializableCollection* c, int index, SerializableObject* item) { + }, + "index"_a) + .def( + "__internal_setitem__", + [](SerializableCollection* c, int index, SerializableObject* item) { index = adjusted_vector_index(index, c->children()); c->set_child(index, item, ErrorStatusHandler()); - }, "index"_a, "item"_a) - .def("__internal_delitem__", [](SerializableCollection* c, int index) { + }, + "index"_a, + "item"_a) + .def( + "__internal_delitem__", + [](SerializableCollection* c, int index) { index = adjusted_vector_index(index, c->children()); c->remove_child(index, ErrorStatusHandler()); - }, "index"_a) - .def("__internal_insert", [](SerializableCollection* c, int index, SerializableObject* item) { + }, + "index"_a) + .def( + "__internal_insert", + [](SerializableCollection* c, int index, SerializableObject* item) { index = adjusted_vector_index(index, c->children()); c->insert_child(index, item); - }, "index"_a, "item"_a) - .def("__len__", [](SerializableCollection* c) { - return c->children().size(); - }) - .def("__iter__", [](SerializableCollection* c) { + }, + "index"_a, + "item"_a) + .def( + "__len__", + [](SerializableCollection* c) { return c->children().size(); }) + .def( + "__iter__", + [](SerializableCollection* c) { return new SerializableCollectionIterator(c); }) - .def("find_clips", [](SerializableCollection* c, std::optional const& search_range, bool shallow_search) { + .def( + "find_clips", + [](SerializableCollection* c, + std::optional const& search_range, + bool shallow_search) { return find_clips(c, search_range, shallow_search); - }, "search_range"_a = std::nullopt, "shallow_search"_a = false) - .def("find_children", [](SerializableCollection* c, py::object descended_from_type, std::optional const& search_range, bool shallow_search) { - return find_children(c, descended_from_type, search_range, shallow_search); - }, "descended_from_type"_a = py::none(), "search_range"_a = std::nullopt, "shallow_search"_a = false); - + }, + "search_range"_a = std::nullopt, + "shallow_search"_a = false) + .def( + "find_children", + [](SerializableCollection* c, + py::object descended_from_type, + std::optional const& search_range, + bool shallow_search) { + return find_children( + c, + descended_from_type, + search_range, + shallow_search); + }, + "descended_from_type"_a = py::none(), + "search_range"_a = std::nullopt, + "shallow_search"_a = false); } -static void define_items_and_compositions(py::module m) { - auto composable_class = py::class_>(m, "Composable", py::dynamic_attr(), R"docstring( +static void +define_items_and_compositions(py::module m) +{ + auto composable_class = + py::class_>( + m, + "Composable", + py::dynamic_attr(), + R"docstring( An object that can be composed within a :class:`~Composition` (such as :class:`~Track` or :class:`.Stack`). )docstring"); - py::class_>(m, "Item", py::dynamic_attr()) - .def(py::init([](std::string name, std::optional source_range, - std::optional> effects, std::optional> markers, py::bool_ enabled, std::optional color, py::object metadata) { - return new Item(name, source_range, - py_to_any_dictionary(metadata), - vector_or_default(effects), - vector_or_default(markers), - enabled, - color); }), - py::arg_v("name"_a = std::string()), - "source_range"_a = std::nullopt, - "effects"_a = py::none(), - "markers"_a = py::none(), - "enabled"_a = true, - "color"_a = std::nullopt, - py::arg_v("metadata"_a = py::none())) - .def_property("enabled", &Item::enabled, &Item::set_enabled, "If true, an Item contributes to compositions. For example, when an audio/video clip is ``enabled=false`` the clip is muted/hidden.") - .def_property("source_range", &Item::source_range, &Item::set_source_range) + py::class_>( + m, + "Item", + py::dynamic_attr()) + .def( + py::init([](std::string name, + std::optional source_range, + std::optional> effects, + std::optional> markers, + py::bool_ enabled, + std::optional color, + py::object metadata) { + return new Item( + name, + source_range, + py_to_any_dictionary(metadata), + vector_or_default(effects), + vector_or_default(markers), + enabled, + color); + }), + py::arg_v("name"_a = std::string()), + "source_range"_a = std::nullopt, + "effects"_a = py::none(), + "markers"_a = py::none(), + "enabled"_a = true, + "color"_a = std::nullopt, + py::arg_v("metadata"_a = py::none())) + .def_property( + "enabled", + &Item::enabled, + &Item::set_enabled, + "If true, an Item contributes to compositions. For example, when an audio/video clip is ``enabled=false`` the clip is muted/hidden.") + .def_property( + "source_range", + &Item::source_range, + &Item::set_source_range) .def_property("color", &Item::color, &Item::set_color) - .def("available_range", [](Item* item) { - return item->available_range(ErrorStatusHandler()); + .def( + "available_range", + [](Item* item) { + return item->available_range(ErrorStatusHandler()); }) - .def("trimmed_range", [](Item* item) { - return item->trimmed_range(ErrorStatusHandler()); - }) - .def_property_readonly("markers", [](Item* item) { - return ((MarkerVectorProxy*) &item->markers()); + .def( + "trimmed_range", + [](Item* item) { + return item->trimmed_range(ErrorStatusHandler()); }) - .def_property_readonly("effects", [](Item* item) { - return ((EffectVectorProxy*) &item->effects()); + .def_property_readonly( + "markers", + [](Item* item) { return ((MarkerVectorProxy*) &item->markers()); }) + .def_property_readonly( + "effects", + [](Item* item) { return ((EffectVectorProxy*) &item->effects()); }) + .def( + "duration", + [](Item* item) { return item->duration(ErrorStatusHandler()); }) + .def( + "visible_range", + [](Item* item) { + return item->visible_range(ErrorStatusHandler()); }) - .def("duration", [](Item* item) { - return item->duration(ErrorStatusHandler()); + .def( + "trimmed_range_in_parent", + [](Item* item) { + return item->trimmed_range_in_parent(ErrorStatusHandler()); }) - .def("visible_range", [](Item* item) { - return item->visible_range(ErrorStatusHandler()); + .def( + "range_in_parent", + [](Item* item) { + return item->range_in_parent(ErrorStatusHandler()); }) - .def("trimmed_range_in_parent", [](Item* item) { - return item->trimmed_range_in_parent(ErrorStatusHandler()); - }) - .def("range_in_parent", [](Item* item) { - return item->range_in_parent(ErrorStatusHandler()); - }) - .def("transformed_time", [](Item* item, RationalTime t, Item* to_item) { - return item->transformed_time(t, to_item, ErrorStatusHandler()); - }, "time"_a, "to_item"_a) - .def("transformed_time_range", [](Item* item, TimeRange time_range, Item* to_item) { - return item->transformed_time_range(time_range, to_item, ErrorStatusHandler()); - }, "time_range"_a, "to_item"_a) + .def( + "transformed_time", + [](Item* item, RationalTime t, Item* to_item) { + return item->transformed_time(t, to_item, ErrorStatusHandler()); + }, + "time"_a, + "to_item"_a) + .def( + "transformed_time_range", + [](Item* item, TimeRange time_range, Item* to_item) { + return item->transformed_time_range( + time_range, + to_item, + ErrorStatusHandler()); + }, + "time_range"_a, + "to_item"_a) .def_property_readonly("available_image_bounds", [](Item* item) { return item->available_image_bounds(ErrorStatusHandler()); - }); + }); auto transition_class = - py::class_>(m, "Transition", py::dynamic_attr(), "Represents a transition between the two adjacent items in a :class:`.Track`. For example, a cross dissolve or wipe.") - .def(py::init([](std::string const& name, std::string const& transition_type, - RationalTime in_offset, RationalTime out_offset, - py::object metadata) { - return new Transition(name, transition_type, - in_offset, out_offset, - py_to_any_dictionary(metadata)); }), - py::arg_v("name"_a = std::string()), - "transition_type"_a = std::string(), - "in_offset"_a = RationalTime(), - "out_offset"_a = RationalTime(), - py::arg_v("metadata"_a = py::none())) - .def_property("transition_type", &Transition::transition_type, &Transition::set_transition_type, "Kind of transition, as defined by the :class:`Type` enum.") - .def_property("in_offset", &Transition::in_offset, &Transition::set_in_offset, "Amount of the previous clip this transition overlaps, exclusive.") - .def_property("out_offset", &Transition::out_offset, &Transition::set_out_offset, "Amount of the next clip this transition overlaps, exclusive.") - .def("duration", [](Transition* t) { - return t->duration(ErrorStatusHandler()); - }) - .def("range_in_parent", [](Transition* t) { - return t->range_in_parent(ErrorStatusHandler()); - }, "Find and return the range of this item in the parent.") - .def("trimmed_range_in_parent", [](Transition* t) { - return t->trimmed_range_in_parent(ErrorStatusHandler()); - }, "Find and return the timmed range of this item in the parent."); + py::class_>( + m, + "Transition", + py::dynamic_attr(), + "Represents a transition between the two adjacent items in a :class:`.Track`. For example, a cross dissolve or wipe.") + .def( + py::init([](std::string const& name, + std::string const& transition_type, + RationalTime in_offset, + RationalTime out_offset, + py::object metadata) { + return new Transition( + name, + transition_type, + in_offset, + out_offset, + py_to_any_dictionary(metadata)); + }), + py::arg_v("name"_a = std::string()), + "transition_type"_a = std::string(), + "in_offset"_a = RationalTime(), + "out_offset"_a = RationalTime(), + py::arg_v("metadata"_a = py::none())) + .def_property( + "transition_type", + &Transition::transition_type, + &Transition::set_transition_type, + "Kind of transition, as defined by the :class:`Type` enum.") + .def_property( + "in_offset", + &Transition::in_offset, + &Transition::set_in_offset, + "Amount of the previous clip this transition overlaps, exclusive.") + .def_property( + "out_offset", + &Transition::out_offset, + &Transition::set_out_offset, + "Amount of the next clip this transition overlaps, exclusive.") + .def( + "duration", + [](Transition* t) { return t->duration(ErrorStatusHandler()); }) + .def( + "range_in_parent", + [](Transition* t) { + return t->range_in_parent(ErrorStatusHandler()); + }, + "Find and return the range of this item in the parent.") + .def( + "trimmed_range_in_parent", + [](Transition* t) { + return t->trimmed_range_in_parent(ErrorStatusHandler()); + }, + "Find and return the timmed range of this item in the parent."); py::class_(transition_class, "Type", R"docstring( Enum encoding types of transitions. Other effects are handled by the :class:`Effect` class. )docstring") - .def_property_readonly_static("SMPTE_Dissolve", [](py::object /* self */) { return Transition::Type::SMPTE_Dissolve; }) - .def_property_readonly_static("Custom", [](py::object /* self */) { return Transition::Type::Custom; }); - + .def_property_readonly_static( + "SMPTE_Dissolve", + [](py::object /* self */) { + return Transition::Type::SMPTE_Dissolve; + }) + .def_property_readonly_static("Custom", [](py::object /* self */) { + return Transition::Type::Custom; + }); py::class_>(m, "Gap", py::dynamic_attr()) - .def(py::init([](std::string name, TimeRange source_range, std::optional> effects, - std::optional> markers, py::object metadata) { - return new Gap(source_range, name, - vector_or_default(effects), - vector_or_default(markers), - py_to_any_dictionary(metadata)); }), - py::arg_v("name"_a = std::string()), - "source_range"_a = TimeRange(), - "effects"_a = py::none(), - "markers"_a = py::none(), - py::arg_v("metadata"_a = py::none())) - .def(py::init([](std::string name, RationalTime duration, std::optional> effects, - std::optional> markers, py::object metadata) { - return new Gap(duration, name, - vector_or_default(effects), - vector_or_default(markers), - py_to_any_dictionary(metadata)); }), - py::arg_v("name"_a = std::string()), - "duration"_a = RationalTime(), - "effects"_a = py::none(), - "markers"_a = py::none(), - py::arg_v("metadata"_a = py::none())); - - auto clip_class = py::class_>(m, "Clip", py::dynamic_attr(), R"docstring( + .def( + py::init([](std::string name, + TimeRange source_range, + std::optional> effects, + std::optional> markers, + py::object metadata) { + return new Gap( + source_range, + name, + vector_or_default(effects), + vector_or_default(markers), + py_to_any_dictionary(metadata)); + }), + py::arg_v("name"_a = std::string()), + "source_range"_a = TimeRange(), + "effects"_a = py::none(), + "markers"_a = py::none(), + py::arg_v("metadata"_a = py::none())) + .def( + py::init([](std::string name, + RationalTime duration, + std::optional> effects, + std::optional> markers, + py::object metadata) { + return new Gap( + duration, + name, + vector_or_default(effects), + vector_or_default(markers), + py_to_any_dictionary(metadata)); + }), + py::arg_v("name"_a = std::string()), + "duration"_a = RationalTime(), + "effects"_a = py::none(), + "markers"_a = py::none(), + py::arg_v("metadata"_a = py::none())); + + auto clip_class = + py::class_>( + m, + "Clip", + py::dynamic_attr(), + R"docstring( A :class:`~Clip` is a segment of editable media (usually audio or video). Contains a :class:`.MediaReference` and a trim on that media reference. )docstring") - .def(py::init([](std::string name, MediaReference* media_reference, - std::optional source_range, py::object metadata, - std::optional> effects, - std::optional> markers, - const std::string& active_media_reference, - std::optional color) { - return new Clip(name, media_reference, source_range, py_to_any_dictionary(metadata), - vector_or_default(effects), - vector_or_default(markers), - active_media_reference, - color); - }), - py::arg_v("name"_a = std::string()), - "media_reference"_a = nullptr, - "source_range"_a = std::nullopt, - py::arg_v("metadata"_a = py::none()), - "effects"_a = py::none(), - "markers"_a = py::none(), - "active_media_reference"_a = std::string(Clip::default_media_key), - "color"_a = std::nullopt) - .def_property_readonly_static("DEFAULT_MEDIA_KEY",[](py::object /* self */) { - return Clip::default_media_key; - }) - .def_property("media_reference", &Clip::media_reference, &Clip::set_media_reference) - .def_property("active_media_reference_key", &Clip::active_media_reference_key, [](Clip* clip, std::string const& new_active_key) { - clip->set_active_media_reference_key(new_active_key, ErrorStatusHandler()); - }) - .def_property("color", &Clip::color, &Clip::set_color) - .def("media_references", &Clip::media_references) - .def("set_media_references", [](Clip* clip, Clip::MediaReferences const& media_references, std::string const& new_active_key) { - clip->set_media_references(media_references, new_active_key, ErrorStatusHandler()); - }); + .def( + py::init([](std::string name, + MediaReference* media_reference, + std::optional source_range, + py::object metadata, + std::optional> effects, + std::optional> markers, + const std::string& active_media_reference, + std::optional color) { + return new Clip( + name, + media_reference, + source_range, + py_to_any_dictionary(metadata), + vector_or_default(effects), + vector_or_default(markers), + active_media_reference, + color); + }), + py::arg_v("name"_a = std::string()), + "media_reference"_a = nullptr, + "source_range"_a = std::nullopt, + py::arg_v("metadata"_a = py::none()), + "effects"_a = py::none(), + "markers"_a = py::none(), + "active_media_reference"_a = + std::string(Clip::default_media_key), + "color"_a = std::nullopt) + .def_property_readonly_static( + "DEFAULT_MEDIA_KEY", + [](py::object /* self */) { return Clip::default_media_key; }) + .def_property( + "media_reference", + &Clip::media_reference, + &Clip::set_media_reference) + .def_property( + "active_media_reference_key", + &Clip::active_media_reference_key, + [](Clip* clip, std::string const& new_active_key) { + clip->set_active_media_reference_key( + new_active_key, + ErrorStatusHandler()); + }) + .def_property("color", &Clip::color, &Clip::set_color) + .def("media_references", &Clip::media_references) + .def( + "set_media_references", + [](Clip* clip, + Clip::MediaReferences const& media_references, + std::string const& new_active_key) { + clip->set_media_references( + media_references, + new_active_key, + ErrorStatusHandler()); + }); using CompositionIterator = ContainerIterator; py::class_(m, "CompositionIterator") .def("__iter__", &CompositionIterator::iter) .def("__next__", &CompositionIterator::next); - py::class_>(m, "Composition", py::dynamic_attr(), R"docstring( + py::class_>( + m, + "Composition", + py::dynamic_attr(), + R"docstring( Base class for an :class:`~Item` that contains :class:`~Composable`\s. Should be subclassed (for example by :class:`.Track` and :class:`.Stack`), not used directly. )docstring") - .def(py::init([](std::string name, - std::optional> children, - std::optional source_range, py::object metadata) { - Composition* c = new Composition(name, source_range, - py_to_any_dictionary(metadata)); - c->set_children(vector_or_default(children), ErrorStatusHandler()); - return c; - }), - py::arg_v("name"_a = std::string()), - "children"_a = py::none(), - "source_range"_a = std::nullopt, - py::arg_v("metadata"_a = py::none())) - .def_property_readonly("composition_kind", &Composition::composition_kind) + .def( + py::init([](std::string name, + std::optional> children, + std::optional source_range, + py::object metadata) { + Composition* c = new Composition( + name, + source_range, + py_to_any_dictionary(metadata)); + c->set_children( + vector_or_default(children), + ErrorStatusHandler()); + return c; + }), + py::arg_v("name"_a = std::string()), + "children"_a = py::none(), + "source_range"_a = std::nullopt, + py::arg_v("metadata"_a = py::none())) + .def_property_readonly( + "composition_kind", + &Composition::composition_kind) .def("is_parent_of", &Composition::is_parent_of, "other"_a) - .def("range_of_child_at_index", [](Composition* c, int index) { - return c->range_of_child_at_index(index, ErrorStatusHandler()); - }, "index"_a) - .def("trimmed_range_of_child_at_index", [](Composition* c, int index) { - return c->trimmed_range_of_child_at_index(index, ErrorStatusHandler()); - }, "index"_a) - .def("range_of_child", [](Composition* c, Composable* child, Composable* /* ignored */) { - return c->range_of_child(child, ErrorStatusHandler()); - }, "child"_a, "reference_space"_a = nullptr) - .def("trimmed_range_of_child", [](Composition* c, Composable* child, Composable* /* ignored */) { - return c->trimmed_range_of_child(child, ErrorStatusHandler()); - }, "child"_a, "reference_space"_a = nullptr) - .def("trimmed_child_range", &Composition::trim_child_range, - "child_range"_a) - .def("trim_child_range", &Composition::trim_child_range, - "child_range"_a) - .def("range_of_all_children", [](Composition* t) { + .def( + "range_of_child_at_index", + [](Composition* c, int index) { + return c->range_of_child_at_index(index, ErrorStatusHandler()); + }, + "index"_a) + .def( + "trimmed_range_of_child_at_index", + [](Composition* c, int index) { + return c->trimmed_range_of_child_at_index( + index, + ErrorStatusHandler()); + }, + "index"_a) + .def( + "range_of_child", + [](Composition* c, Composable* child, Composable* /* ignored */) { + return c->range_of_child(child, ErrorStatusHandler()); + }, + "child"_a, + "reference_space"_a = nullptr) + .def( + "trimmed_range_of_child", + [](Composition* c, Composable* child, Composable* /* ignored */) { + return c->trimmed_range_of_child(child, ErrorStatusHandler()); + }, + "child"_a, + "reference_space"_a = nullptr) + .def( + "trimmed_child_range", + &Composition::trim_child_range, + "child_range"_a) + .def( + "trim_child_range", + &Composition::trim_child_range, + "child_range"_a) + .def( + "range_of_all_children", + [](Composition* t) { py::dict d; - for (auto e: t->range_of_all_children(ErrorStatusHandler())) { + for (auto e: t->range_of_all_children(ErrorStatusHandler())) + { d[py::cast(e.first)] = py::cast(e.second); } return d; }) - .def("child_at_time", [](Composition* t, RationalTime const& search_time, bool shallow_search) { - auto result = t->child_at_time(search_time, ErrorStatusHandler(), shallow_search); + .def( + "child_at_time", + [](Composition* t, + RationalTime const& search_time, + bool shallow_search) { + auto result = t->child_at_time( + search_time, + ErrorStatusHandler(), + shallow_search); return result.value; - }, "search_time"_a, "shallow_search"_a = false) - .def("children_in_range", [](Composition* t, TimeRange const& search_range) { + }, + "search_time"_a, + "shallow_search"_a = false) + .def( + "children_in_range", + [](Composition* t, TimeRange const& search_range) { std::vector l; - for (const auto& child : t->children_in_range(search_range, ErrorStatusHandler())) { + for (const auto& child: + t->children_in_range(search_range, ErrorStatusHandler())) + { l.push_back(child.value); } return l; - }, "search_range"_a) - .def("find_children", [](Composition* c, py::object descended_from_type, std::optional const& search_range, bool shallow_search) { - return find_children(c, descended_from_type, search_range, shallow_search); - }, "descended_from_type"_a = py::none(), "search_range"_a = std::nullopt, "shallow_search"_a = false) - .def("find_clips", [](Composition* c, std::optional const& search_range, bool shallow_search) { + }, + "search_range"_a) + .def( + "find_children", + [](Composition* c, + py::object descended_from_type, + std::optional const& search_range, + bool shallow_search) { + return find_children( + c, + descended_from_type, + search_range, + shallow_search); + }, + "descended_from_type"_a = py::none(), + "search_range"_a = std::nullopt, + "shallow_search"_a = false) + .def( + "find_clips", + [](Composition* c, + std::optional const& search_range, + bool shallow_search) { return find_clips(c, search_range, shallow_search); - }, "search_range"_a = std::nullopt, "shallow_search"_a = false) - .def("handles_of_child", [](Composition* c, Composable* child) { + }, + "search_range"_a = std::nullopt, + "shallow_search"_a = false) + .def( + "handles_of_child", + [](Composition* c, Composable* child) { auto result = c->handles_of_child(child, ErrorStatusHandler()); - return py::make_tuple(py::cast(result.first), py::cast(result.second)); - }, "child"_a) + return py::make_tuple( + py::cast(result.first), + py::cast(result.second)); + }, + "child"_a) .def("has_clips", &Composition::has_clips) - .def("__internal_getitem__", [](Composition* c, int index) { + .def( + "__internal_getitem__", + [](Composition* c, int index) { index = adjusted_vector_index(index, c->children()); - if (index < 0 || index >= int(c->children().size())) { + if (index < 0 || index >= int(c->children().size())) + { throw py::index_error(); } return c->children()[index].value; - }, "index"_a) - .def("__internal_setitem__", [](Composition* c, int index, Composable* composable) { + }, + "index"_a) + .def( + "__internal_setitem__", + [](Composition* c, int index, Composable* composable) { index = adjusted_vector_index(index, c->children()); c->set_child(index, composable, ErrorStatusHandler()); - }, "index"_a, "item"_a) - .def("__internal_delitem__", [](Composition* c, int index) { + }, + "index"_a, + "item"_a) + .def( + "__internal_delitem__", + [](Composition* c, int index) { index = adjusted_vector_index(index, c->children()); c->remove_child(index, ErrorStatusHandler()); - }, "index"_a) - .def("__internal_insert", [](Composition* c, int index, Composable &composable) { + }, + "index"_a) + .def( + "__internal_insert", + [](Composition* c, int index, Composable& composable) { index = adjusted_vector_index(index, c->children()); c->insert_child(index, &composable, ErrorStatusHandler()); - }, "index"_a, "item"_a) + }, + "index"_a, + "item"_a) .def("__contains__", &Composition::has_child, "composable"_a) - .def("__len__", [](Composition* c) { - return c->children().size(); - }) + .def("__len__", [](Composition* c) { return c->children().size(); }) .def("__iter__", [](Composition* c) { - return new CompositionIterator(c); - }); + return new CompositionIterator(c); + }); composable_class - .def(py::init([](std::string const& name, - py::object metadata) { - return new Composable(name, py_to_any_dictionary(metadata)); - }), - py::arg_v("name"_a = std::string()), - py::arg_v("metadata"_a = py::none())) + .def( + py::init([](std::string const& name, py::object metadata) { + return new Composable(name, py_to_any_dictionary(metadata)); + }), + py::arg_v("name"_a = std::string()), + py::arg_v("metadata"_a = py::none())) .def("parent", &Composable::parent) .def("visible", &Composable::visible) .def("overlapping", &Composable::overlapping); - auto track_class = py::class_>(m, "Track", py::dynamic_attr()); + auto track_class = py::class_>( + m, + "Track", + py::dynamic_attr()); py::enum_(track_class, "NeighborGapPolicy") - .value("around_transitions", Track::NeighborGapPolicy::around_transitions) + .value( + "around_transitions", + Track::NeighborGapPolicy::around_transitions) .value("never", Track::NeighborGapPolicy::never); track_class - .def(py::init([](std::string name, std::optional> children, - std::optional const& source_range, - std::string const& kind, py::object metadata, - std::optional color) { - auto composable_children = vector_or_default(children); - Track* t = new Track( - name, - source_range, - kind, - py_to_any_dictionary(metadata), - color - ); - if (!composable_children.empty()) - t->set_children(composable_children, ErrorStatusHandler()); - return t; - }), - py::arg_v("name"_a = std::string()), - "children"_a = py::none(), - "source_range"_a = std::nullopt, - "kind"_a = std::string(Track::Kind::video), - py::arg_v("metadata"_a = py::none()), - "color"_a = std::nullopt) + .def( + py::init([](std::string name, + std::optional> children, + std::optional const& source_range, + std::string const& kind, + py::object metadata, + std::optional color) { + auto composable_children = + vector_or_default(children); + Track* t = new Track( + name, + source_range, + kind, + py_to_any_dictionary(metadata), + color); + if (!composable_children.empty()) + t->set_children(composable_children, ErrorStatusHandler()); + return t; + }), + py::arg_v("name"_a = std::string()), + "children"_a = py::none(), + "source_range"_a = std::nullopt, + "kind"_a = std::string(Track::Kind::video), + py::arg_v("metadata"_a = py::none()), + "color"_a = std::nullopt) .def_property("kind", &Track::kind, &Track::set_kind) .def_property("color", &Track::color, &Track::set_color) - .def("neighbors_of", [](Track* t, Composable* item, Track::NeighborGapPolicy policy) { - auto result = t->neighbors_of(item, ErrorStatusHandler(), policy); - return py::make_tuple(py::cast(result.first.take_value()), py::cast(result.second.take_value())); - }, "item"_a, "policy"_a = Track::NeighborGapPolicy::never); + .def( + "neighbors_of", + [](Track* t, Composable* item, Track::NeighborGapPolicy policy) { + auto result = + t->neighbors_of(item, ErrorStatusHandler(), policy); + return py::make_tuple( + py::cast(result.first.take_value()), + py::cast(result.second.take_value())); + }, + "item"_a, + "policy"_a = Track::NeighborGapPolicy::never); py::class_(track_class, "Kind") - .def_property_readonly_static("Audio", [](py::object /* self */) { return Track::Kind::audio; }) - .def_property_readonly_static("Video", [](py::object /* self */) { return Track::Kind::video; }); - - py::class_>(m, "Stack", py::dynamic_attr()) - .def(py::init([](std::string name, - std::optional> children, - std::optional const& source_range, - std::optional> markers, - std::optional> effects, - py::object metadata) { - auto composable_children = vector_or_default(children); - Stack* s = new Stack( - name, - source_range, - py_to_any_dictionary(metadata), - vector_or_default(effects), - vector_or_default(markers) - ); - if (!composable_children.empty()) { - s->set_children(composable_children, ErrorStatusHandler()); - } - return s; - }), - py::arg_v("name"_a = std::string()), - "children"_a = py::none(), - "source_range"_a = std::nullopt, - "markers"_a = py::none(), - "effects"_a = py::none(), - py::arg_v("metadata"_a = py::none())); - - py::class_>(m, "Timeline", py::dynamic_attr()) - .def(py::init([](std::string name, - std::optional> children, - std::optional global_start_time, - py::object metadata) { - auto composable_children = vector_or_default(children); - Timeline* t = new Timeline(name, global_start_time, - py_to_any_dictionary(metadata)); - if (!composable_children.empty()) - t->tracks()->set_children(composable_children, ErrorStatusHandler()); - return t; - }), - py::arg_v("name"_a = std::string()), - "tracks"_a = py::none(), - "global_start_time"_a = std::nullopt, - py::arg_v("metadata"_a = py::none())) - .def_property("global_start_time", &Timeline::global_start_time, &Timeline::set_global_start_time) + .def_property_readonly_static( + "Audio", + [](py::object /* self */) { return Track::Kind::audio; }) + .def_property_readonly_static("Video", [](py::object /* self */) { + return Track::Kind::video; + }); + + py::class_>( + m, + "Stack", + py::dynamic_attr()) + .def( + py::init([](std::string name, + std::optional> children, + std::optional const& source_range, + std::optional> markers, + std::optional> effects, + py::object metadata) { + auto composable_children = + vector_or_default(children); + Stack* s = new Stack( + name, + source_range, + py_to_any_dictionary(metadata), + vector_or_default(effects), + vector_or_default(markers)); + if (!composable_children.empty()) + { + s->set_children(composable_children, ErrorStatusHandler()); + } + return s; + }), + py::arg_v("name"_a = std::string()), + "children"_a = py::none(), + "source_range"_a = std::nullopt, + "markers"_a = py::none(), + "effects"_a = py::none(), + py::arg_v("metadata"_a = py::none())); + + py::class_< + Timeline, + SerializableObjectWithMetadata, + managing_ptr>(m, "Timeline", py::dynamic_attr()) + .def( + py::init([](std::string name, + std::optional> children, + std::optional global_start_time, + py::object metadata) { + auto composable_children = + vector_or_default(children); + Timeline* t = new Timeline( + name, + global_start_time, + py_to_any_dictionary(metadata)); + if (!composable_children.empty()) + t->tracks()->set_children( + composable_children, + ErrorStatusHandler()); + return t; + }), + py::arg_v("name"_a = std::string()), + "tracks"_a = py::none(), + "global_start_time"_a = std::nullopt, + py::arg_v("metadata"_a = py::none())) + .def_property( + "global_start_time", + &Timeline::global_start_time, + &Timeline::set_global_start_time) .def_property("tracks", &Timeline::tracks, &Timeline::set_tracks) - .def("duration", [](Timeline* t) { - return t->duration(ErrorStatusHandler()); - }) - .def("range_of_child", [](Timeline* t, Composable* child) { + .def( + "duration", + [](Timeline* t) { return t->duration(ErrorStatusHandler()); }) + .def( + "range_of_child", + [](Timeline* t, Composable* child) { return t->range_of_child(child, ErrorStatusHandler()); }) .def("video_tracks", &Timeline::video_tracks) .def("audio_tracks", &Timeline::audio_tracks) - .def("find_clips", [](Timeline* t, std::optional const& search_range, bool shallow_search) { + .def( + "find_clips", + [](Timeline* t, + std::optional const& search_range, + bool shallow_search) { return find_clips(t, search_range, shallow_search); - }, "search_range"_a = std::nullopt, "shallow_search"_a = false) - .def("find_children", [](Timeline* t, py::object descended_from_type, std::optional const& search_range, bool shallow_search) { - return find_children(t, descended_from_type, search_range, shallow_search); - }, "descended_from_type"_a = py::none(), "search_range"_a = std::nullopt, "shallow_search"_a = false); + }, + "search_range"_a = std::nullopt, + "shallow_search"_a = false) + .def( + "find_children", + [](Timeline* t, + py::object descended_from_type, + std::optional const& search_range, + bool shallow_search) { + return find_children( + t, + descended_from_type, + search_range, + shallow_search); + }, + "descended_from_type"_a = py::none(), + "search_range"_a = std::nullopt, + "shallow_search"_a = false); } -static void define_effects(py::module m) { - py::class_>(m, "Effect", py::dynamic_attr()) - .def(py::init([](std::string name, - std::string effect_name, - py::object metadata, - py::bool_ enabled) { - return new Effect(name, effect_name, py_to_any_dictionary(metadata), enabled); }), - py::arg_v("name"_a = std::string()), - "effect_name"_a = std::string(), - py::arg_v("metadata"_a = py::none()), - "enabled"_a = true) - .def_property("effect_name", &Effect::effect_name, &Effect::set_effect_name) - .def_property("enabled", &Effect::enabled, &Effect::set_enabled, "If true, the Effect is applied. If false, the Effect is omitted."); - - py::class_>(m, "TimeEffect", py::dynamic_attr(), "Base class for all effects that alter the timing of an item.") - .def(py::init([](std::string name, - std::string effect_name, - py::object metadata) { - return new TimeEffect(name, effect_name, py_to_any_dictionary(metadata)); }), - py::arg_v("name"_a = std::string()), - "effect_name"_a = std::string(), - py::arg_v("metadata"_a = py::none())); - - py::class_>(m, "LinearTimeWarp", py::dynamic_attr(), R"docstring( +static void +define_effects(py::module m) +{ + py::class_>( + m, + "Effect", + py::dynamic_attr()) + .def( + py::init([](std::string name, + std::string effect_name, + py::object metadata, + py::bool_ enabled) { + return new Effect( + name, + effect_name, + py_to_any_dictionary(metadata), + enabled); + }), + py::arg_v("name"_a = std::string()), + "effect_name"_a = std::string(), + py::arg_v("metadata"_a = py::none()), + "enabled"_a = true) + .def_property( + "effect_name", + &Effect::effect_name, + &Effect::set_effect_name) + .def_property( + "enabled", + &Effect::enabled, + &Effect::set_enabled, + "If true, the Effect is applied. If false, the Effect is omitted."); + + py::class_>( + m, + "TimeEffect", + py::dynamic_attr(), + "Base class for all effects that alter the timing of an item.") + .def( + py::init([](std::string name, + std::string effect_name, + py::object metadata) { + return new TimeEffect( + name, + effect_name, + py_to_any_dictionary(metadata)); + }), + py::arg_v("name"_a = std::string()), + "effect_name"_a = std::string(), + py::arg_v("metadata"_a = py::none())); + + py::class_>( + m, + "LinearTimeWarp", + py::dynamic_attr(), + R"docstring( A time warp that applies a linear speed up or slow down across the entire clip. )docstring") - .def(py::init([](std::string name, - double time_scalar, - py::object metadata) { - return new LinearTimeWarp(name, "LinearTimeWarp", time_scalar, - py_to_any_dictionary(metadata)); }), - py::arg_v("name"_a = std::string()), - "time_scalar"_a = 1.0, - py::arg_v("metadata"_a = py::none())) - .def_property("time_scalar", &LinearTimeWarp::time_scalar, &LinearTimeWarp::set_time_scalar, R"docstring( + .def( + py::init( + [](std::string name, double time_scalar, py::object metadata) { + return new LinearTimeWarp( + name, + "LinearTimeWarp", + time_scalar, + py_to_any_dictionary(metadata)); + }), + py::arg_v("name"_a = std::string()), + "time_scalar"_a = 1.0, + py::arg_v("metadata"_a = py::none())) + .def_property( + "time_scalar", + &LinearTimeWarp::time_scalar, + &LinearTimeWarp::set_time_scalar, + R"docstring( Linear time scalar applied to clip. 2.0 means the clip occupies half the time in the parent item, i.e. plays at double speed, 0.5 means the clip occupies twice the time in the parent item, i.e. plays at half speed. @@ -744,94 +1313,161 @@ Note that adjusting the time_scalar of a :class:`~LinearTimeWarp` does not affec Instead it affects the speed of the media displayed within that item. )docstring"); - py::class_>(m, "FreezeFrame", py::dynamic_attr(), "Hold the first frame of the clip for the duration of the clip.") - .def(py::init([](std::string name, py::object metadata) { - return new FreezeFrame(name, py_to_any_dictionary(metadata)); }), + py::class_>( + m, + "FreezeFrame", + py::dynamic_attr(), + "Hold the first frame of the clip for the duration of the clip.") + .def( + py::init([](std::string name, py::object metadata) { + return new FreezeFrame(name, py_to_any_dictionary(metadata)); + }), py::arg_v("name"_a = std::string()), py::arg_v("metadata"_a = py::none())); } -static void define_media_references(py::module m) { - py::class_>(m, "MediaReference", py::dynamic_attr()) - .def(py::init([](std::string name, - std::optional available_range, - py::object metadata, - std::optional const& available_image_bounds) { - return new MediaReference(name, available_range, py_to_any_dictionary(metadata), available_image_bounds); }), - py::arg_v("name"_a = std::string()), - "available_range"_a = std::nullopt, - py::arg_v("metadata"_a = py::none()), - "available_image_bounds"_a = std::nullopt) - - .def_property("available_range", &MediaReference::available_range, &MediaReference::set_available_range) - .def_property("available_image_bounds", &MediaReference::available_image_bounds, &MediaReference::set_available_image_bounds) - .def_property_readonly("is_missing_reference", &MediaReference::is_missing_reference); - - py::class_>(m, "GeneratorReference", py::dynamic_attr()) - .def(py::init([](std::string name, std::string generator_kind, - std::optional const& available_range, - py::object parameters, py::object metadata, - std::optional const& available_image_bounds) { - return new GeneratorReference(name, generator_kind, - available_range, - py_to_any_dictionary(parameters), - py_to_any_dictionary(metadata), - available_image_bounds); }), - py::arg_v("name"_a = std::string()), - "generator_kind"_a = std::string(), - "available_range"_a = std::nullopt, - "parameters"_a = py::none(), - py::arg_v("metadata"_a = py::none()), - "available_image_bounds"_a = std::nullopt) - .def_property("generator_kind", &GeneratorReference::generator_kind, &GeneratorReference::set_generator_kind) - .def_property_readonly("parameters", [](GeneratorReference* g) { +static void +define_media_references(py::module m) +{ + py::class_>( + m, + "MediaReference", + py::dynamic_attr()) + .def( + py::init([](std::string name, + std::optional available_range, + py::object metadata, + std::optional const& + available_image_bounds) { + return new MediaReference( + name, + available_range, + py_to_any_dictionary(metadata), + available_image_bounds); + }), + py::arg_v("name"_a = std::string()), + "available_range"_a = std::nullopt, + py::arg_v("metadata"_a = py::none()), + "available_image_bounds"_a = std::nullopt) + + .def_property( + "available_range", + &MediaReference::available_range, + &MediaReference::set_available_range) + .def_property( + "available_image_bounds", + &MediaReference::available_image_bounds, + &MediaReference::set_available_image_bounds) + .def_property_readonly( + "is_missing_reference", + &MediaReference::is_missing_reference); + + py::class_< + GeneratorReference, + MediaReference, + managing_ptr>( + m, + "GeneratorReference", + py::dynamic_attr()) + .def( + py::init([](std::string name, + std::string generator_kind, + std::optional const& available_range, + py::object parameters, + py::object metadata, + std::optional const& + available_image_bounds) { + return new GeneratorReference( + name, + generator_kind, + available_range, + py_to_any_dictionary(parameters), + py_to_any_dictionary(metadata), + available_image_bounds); + }), + py::arg_v("name"_a = std::string()), + "generator_kind"_a = std::string(), + "available_range"_a = std::nullopt, + "parameters"_a = py::none(), + py::arg_v("metadata"_a = py::none()), + "available_image_bounds"_a = std::nullopt) + .def_property( + "generator_kind", + &GeneratorReference::generator_kind, + &GeneratorReference::set_generator_kind) + .def_property_readonly( + "parameters", + [](GeneratorReference* g) { auto ptr = g->parameters().get_or_create_mutation_stamp(); - return (AnyDictionaryProxy*)(ptr); }, py::return_value_policy::take_ownership); - - - py::class_>(m, "MissingReference", py::dynamic_attr(), R"docstring( + return (AnyDictionaryProxy*) (ptr); + }, + py::return_value_policy::take_ownership); + + py::class_< + MissingReference, + MediaReference, + managing_ptr>( + m, + "MissingReference", + py::dynamic_attr(), + R"docstring( Represents media for which a concrete reference is missing. Note that a :class:`~MissingReference` may have useful metadata, even if the location of the media is not known. )docstring") - .def(py::init([]( - std::string name, + .def( + py::init([](std::string name, std::optional available_range, - py::object metadata, - std::optional const& available_image_bounds) { - return new MissingReference( - name, - available_range, - py_to_any_dictionary(metadata), - available_image_bounds); - }), - py::arg_v("name"_a = std::string()), - "available_range"_a = std::nullopt, - py::arg_v("metadata"_a = py::none()), - "available_image_bounds"_a = std::nullopt); - - - py::class_>(m, "ExternalReference", py::dynamic_attr()) - .def(py::init([](std::string target_url, - std::optional const& available_range, - py::object metadata, - std::optional const& available_image_bounds) { - return new ExternalReference(target_url, - available_range, - py_to_any_dictionary(metadata), - available_image_bounds); }), - "target_url"_a = std::string(), - "available_range"_a = std::nullopt, - py::arg_v("metadata"_a = py::none()), - "available_image_bounds"_a = std::nullopt) - .def_property("target_url", &ExternalReference::target_url, &ExternalReference::set_target_url); - - auto imagesequencereference_class = py:: class_>(m, "ImageSequenceReference", py::dynamic_attr(), R"docstring( + py::object metadata, + std::optional const& + available_image_bounds) { + return new MissingReference( + name, + available_range, + py_to_any_dictionary(metadata), + available_image_bounds); + }), + py::arg_v("name"_a = std::string()), + "available_range"_a = std::nullopt, + py::arg_v("metadata"_a = py::none()), + "available_image_bounds"_a = std::nullopt); + + py::class_< + ExternalReference, + MediaReference, + managing_ptr>( + m, + "ExternalReference", + py::dynamic_attr()) + .def( + py::init([](std::string target_url, + std::optional const& available_range, + py::object metadata, + std::optional const& + available_image_bounds) { + return new ExternalReference( + target_url, + available_range, + py_to_any_dictionary(metadata), + available_image_bounds); + }), + "target_url"_a = std::string(), + "available_range"_a = std::nullopt, + py::arg_v("metadata"_a = py::none()), + "available_image_bounds"_a = std::nullopt) + .def_property( + "target_url", + &ExternalReference::target_url, + &ExternalReference::set_target_url); + + auto imagesequencereference_class = py::class_< + ImageSequenceReference, + MediaReference, + managing_ptr>( + m, + "ImageSequenceReference", + py::dynamic_attr(), + R"docstring( An ImageSequenceReference refers to a numbered series of single-frame image files. Each file can be referred to by a URL generated by the :class:`~ImageSequenceReference`. Image sequences can have URLs with discontinuous frame numbers, for instance if you've only rendered every other frame in a sequence, your frame numbers may be 1, 3, 5, etc. This is configured using the ``frame_step`` attribute. In this case, the 0th image in the sequence is frame 1 and the 1st image in the sequence is frame 3. Because of this there are two numbering concepts in the image sequence, the image number and the frame number. @@ -899,64 +1535,127 @@ Negative ``start_frame`` is also handled. The above example with a ``start_frame - ``file:///show/sequence/shot/sample_image_sequence.0001.exr`` )docstring"); - py::enum_(imagesequencereference_class, "MissingFramePolicy", "Behavior that should be used by applications when an image file in the sequence can't be found on disk.") - .value("error", ImageSequenceReference::MissingFramePolicy::error, "Application should stop and raise an error.") - .value("hold", ImageSequenceReference::MissingFramePolicy::hold, "Application should hold the last available frame before the missing frame.") - .value("black", ImageSequenceReference::MissingFramePolicy::black, "Application should use a black frame in place of the missing frame"); + py::enum_( + imagesequencereference_class, + "MissingFramePolicy", + "Behavior that should be used by applications when an image file in the sequence can't be found on disk.") + .value( + "error", + ImageSequenceReference::MissingFramePolicy::error, + "Application should stop and raise an error.") + .value( + "hold", + ImageSequenceReference::MissingFramePolicy::hold, + "Application should hold the last available frame before the missing frame.") + .value( + "black", + ImageSequenceReference::MissingFramePolicy::black, + "Application should use a black frame in place of the missing frame"); imagesequencereference_class - .def(py::init([](std::string target_url_base, - std::string name_prefix, - std::string name_suffix, - int start_frame, - int frame_step, - double const rate, - int frame_zero_padding, - ImageSequenceReference::MissingFramePolicy const missing_frame_policy, - std::optional const& available_range, - py::object metadata, - std::optional const& available_image_bounds) { - return new ImageSequenceReference(target_url_base, - name_prefix, - name_suffix, - start_frame, - frame_step, - rate, - frame_zero_padding, - missing_frame_policy, - available_range, - py_to_any_dictionary(metadata), - available_image_bounds); }), - "target_url_base"_a = std::string(), - "name_prefix"_a = std::string(), - "name_suffix"_a = std::string(), - "start_frame"_a = 1L, - "frame_step"_a = 1L, - "rate"_a = 1, - "frame_zero_padding"_a = 0, - "missing_frame_policy"_a = ImageSequenceReference::MissingFramePolicy::error, - "available_range"_a = std::nullopt, - py::arg_v("metadata"_a = py::none()), - "available_image_bounds"_a = std::nullopt) - .def_property("target_url_base", &ImageSequenceReference::target_url_base, &ImageSequenceReference::set_target_url_base, "Everything leading up to the file name in the ``target_url``.") - .def_property("name_prefix", &ImageSequenceReference::name_prefix, &ImageSequenceReference::set_name_prefix, "Everything in the file name leading up to the frame number.") - .def_property("name_suffix", &ImageSequenceReference::name_suffix, &ImageSequenceReference::set_name_suffix, "Everything after the frame number in the file name.") - .def_property("start_frame", &ImageSequenceReference::start_frame, &ImageSequenceReference::set_start_frame, "The first frame number used in file names.") - .def_property("frame_step", &ImageSequenceReference::frame_step, &ImageSequenceReference::set_frame_step, "Step between frame numbers in file names.") - .def_property("rate", &ImageSequenceReference::rate, &ImageSequenceReference::set_rate, "Frame rate if every frame in the sequence were played back.") - .def_property("frame_zero_padding", &ImageSequenceReference::frame_zero_padding, &ImageSequenceReference::set_frame_zero_padding, "Number of digits to pad zeros out to in frame numbers.") - .def_property("missing_frame_policy", &ImageSequenceReference::missing_frame_policy, &ImageSequenceReference::set_missing_frame_policy, "Directive for how frames in sequence not found during playback or rendering should be handled.") - .def("end_frame", &ImageSequenceReference::end_frame, "Last frame number in the sequence based on the :attr:`rate` and :attr:`.available_range`.") - .def("number_of_images_in_sequence", &ImageSequenceReference::number_of_images_in_sequence, "Returns the number of images based on the :attr:`rate` and :attr:`.available_range`.") - .def("frame_for_time", [](ImageSequenceReference *seq_ref, RationalTime time) { + .def( + py::init([](std::string target_url_base, + std::string name_prefix, + std::string name_suffix, + int start_frame, + int frame_step, + double const rate, + int frame_zero_padding, + ImageSequenceReference::MissingFramePolicy const + missing_frame_policy, + std::optional const& available_range, + py::object metadata, + std::optional const& + available_image_bounds) { + return new ImageSequenceReference( + target_url_base, + name_prefix, + name_suffix, + start_frame, + frame_step, + rate, + frame_zero_padding, + missing_frame_policy, + available_range, + py_to_any_dictionary(metadata), + available_image_bounds); + }), + "target_url_base"_a = std::string(), + "name_prefix"_a = std::string(), + "name_suffix"_a = std::string(), + "start_frame"_a = 1L, + "frame_step"_a = 1L, + "rate"_a = 1, + "frame_zero_padding"_a = 0, + "missing_frame_policy"_a = + ImageSequenceReference::MissingFramePolicy::error, + "available_range"_a = std::nullopt, + py::arg_v("metadata"_a = py::none()), + "available_image_bounds"_a = std::nullopt) + .def_property( + "target_url_base", + &ImageSequenceReference::target_url_base, + &ImageSequenceReference::set_target_url_base, + "Everything leading up to the file name in the ``target_url``.") + .def_property( + "name_prefix", + &ImageSequenceReference::name_prefix, + &ImageSequenceReference::set_name_prefix, + "Everything in the file name leading up to the frame number.") + .def_property( + "name_suffix", + &ImageSequenceReference::name_suffix, + &ImageSequenceReference::set_name_suffix, + "Everything after the frame number in the file name.") + .def_property( + "start_frame", + &ImageSequenceReference::start_frame, + &ImageSequenceReference::set_start_frame, + "The first frame number used in file names.") + .def_property( + "frame_step", + &ImageSequenceReference::frame_step, + &ImageSequenceReference::set_frame_step, + "Step between frame numbers in file names.") + .def_property( + "rate", + &ImageSequenceReference::rate, + &ImageSequenceReference::set_rate, + "Frame rate if every frame in the sequence were played back.") + .def_property( + "frame_zero_padding", + &ImageSequenceReference::frame_zero_padding, + &ImageSequenceReference::set_frame_zero_padding, + "Number of digits to pad zeros out to in frame numbers.") + .def_property( + "missing_frame_policy", + &ImageSequenceReference::missing_frame_policy, + &ImageSequenceReference::set_missing_frame_policy, + "Directive for how frames in sequence not found during playback or rendering should be handled.") + .def( + "end_frame", + &ImageSequenceReference::end_frame, + "Last frame number in the sequence based on the :attr:`rate` and :attr:`.available_range`.") + .def( + "number_of_images_in_sequence", + &ImageSequenceReference::number_of_images_in_sequence, + "Returns the number of images based on the :attr:`rate` and :attr:`.available_range`.") + .def( + "frame_for_time", + [](ImageSequenceReference* seq_ref, RationalTime time) { return seq_ref->frame_for_time(time, ErrorStatusHandler()); - }, "time"_a, "Given a :class:`.RationalTime` within the available range, returns the frame number.") - .def("target_url_for_image_number", [](ImageSequenceReference *seq_ref, int image_number) { + }, + "time"_a, + "Given a :class:`.RationalTime` within the available range, returns the frame number.") + .def( + "target_url_for_image_number", + [](ImageSequenceReference* seq_ref, int image_number) { return seq_ref->target_url_for_image_number( - image_number, - ErrorStatusHandler() - ); - }, "image_number"_a, R"docstring(Given an image number, returns the ``target_url`` for that image. + image_number, + ErrorStatusHandler()); + }, + "image_number"_a, + R"docstring(Given an image number, returns the ``target_url`` for that image. This is roughly equivalent to: @@ -965,20 +1664,23 @@ This is roughly equivalent to: f"{target_url_prefix}{(start_frame + (image_number * frame_step)):0{value_zero_padding}}{target_url_postfix}" )docstring") - .def("presentation_time_for_image_number", [](ImageSequenceReference *seq_ref, int image_number) { + .def( + "presentation_time_for_image_number", + [](ImageSequenceReference* seq_ref, int image_number) { return seq_ref->presentation_time_for_image_number( - image_number, - ErrorStatusHandler() - ); - }, "image_number"_a, "Given an image number, returns the :class:`.RationalTime` at which that image should be shown in the space of :attr:`.available_range`."); - + image_number, + ErrorStatusHandler()); + }, + "image_number"_a, + "Given an image number, returns the :class:`.RationalTime` at which that image should be shown in the space of :attr:`.available_range`."); } -void otio_serializable_object_bindings(py::module m) { +void +otio_serializable_object_bindings(py::module m) +{ define_bases1(m); define_bases2(m); define_effects(m); define_media_references(m); define_items_and_compositions(m); } - diff --git a/src/py-opentimelineio/opentimelineio-bindings/otio_tests.cpp b/src/py-opentimelineio/opentimelineio-bindings/otio_tests.cpp index ff44c1fb9b..fae389138e 100644 --- a/src/py-opentimelineio/opentimelineio-bindings/otio_tests.cpp +++ b/src/py-opentimelineio/opentimelineio-bindings/otio_tests.cpp @@ -1,94 +1,110 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright Contributors to the OpenTimelineIO project -#include #include +#include +#include "opentimelineio/serializableCollection.h" #include "opentimelineio/serializableObject.h" #include "opentimelineio/serializableObjectWithMetadata.h" -#include "opentimelineio/serializableCollection.h" #include "opentimelineio/timeline.h" -#include "otio_utils.h" #include "otio_anyDictionary.h" #include "otio_anyVector.h" +#include "otio_utils.h" namespace py = pybind11; using namespace pybind11::literals; -class TestObject : public SerializableObjectWithMetadata { +class TestObject : public SerializableObjectWithMetadata +{ public: - struct Schema { - static auto constexpr name = "Test"; + struct Schema + { + static auto constexpr name = "Test"; static int constexpr version = 1; }; using Parent = SerializableObjectWithMetadata; - + TestObject(std::string const& name = "") : SerializableObjectWithMetadata(name) { printf("Created test object named '%s' at %p\n", name.c_str(), this); } - SerializableObject* lookup(std::string key) { + SerializableObject* lookup(std::string key) + { std::any a = metadata()[key]; - if (a.type() == typeid(Retainer<>)) { + if (a.type() == typeid(Retainer<>)) + { return std::any_cast>(a).value; } return nullptr; } - bool read_from(Reader& reader) { - return Parent::read_from(reader); - } - - void write_to(Writer& writer) const { - Parent::write_to(writer); - } + bool read_from(Reader& reader) { return Parent::read_from(reader); } - void add_key(std::string key, int value) { - metadata()[key] = value; - } - - std::string repr() const { - return string_printf("", name().c_str(), this); + void write_to(Writer& writer) const { Parent::write_to(writer); } + + void add_key(std::string key, int value) { metadata()[key] = value; } + + std::string repr() const + { + return string_printf( + "", + name().c_str(), + this); } - + private: - ~TestObject() { - printf("Test object '%s' at %p being destroyed\n", name().c_str(), this); + ~TestObject() + { + printf( + "Test object '%s' at %p being destroyed\n", + name().c_str(), + this); } }; -static void test_takeme(SerializableObject* so) { +static void +test_takeme(SerializableObject* so) +{ SerializableObject::Retainer<> r(so); } -static int test_bash_retainers1(SerializableCollection* sc) { +static int +test_bash_retainers1(SerializableCollection* sc) +{ py::gil_scoped_release release; - SerializableObject* so = sc->children()[0]; + SerializableObject* so = sc->children()[0]; int total = 0; - for (size_t i = 0; i < 1024 * 10; i++) { + for (size_t i = 0; i < 1024 * 10; i++) + { SerializableObject::Retainer<> r(so); - if (r.value) { + if (r.value) + { total++; } } - + return total; } -py::object test_bash_retainers2(SerializableCollection* sc, py::object materialize_obj) { - SerializableObject* so = sc->children()[0]; - int total = 0; +py::object +test_bash_retainers2(SerializableCollection* sc, py::object materialize_obj) +{ + SerializableObject* so = sc->children()[0]; + int total = 0; { py::gil_scoped_release release; - for (size_t i = 0; i < 1024 * 10; i++) { + for (size_t i = 0; i < 1024 * 10; i++) + { SerializableObject::Retainer<> r(so); - if (r.value) { + if (r.value) + { total++; } } @@ -98,9 +114,11 @@ py::object test_bash_retainers2(SerializableCollection* sc, py::object materiali { py::gil_scoped_release release; - for (size_t i = 0; i < 1024 * 10; i++) { + for (size_t i = 0; i < 1024 * 10; i++) + { SerializableObject::Retainer<> r(so); - if (r.value) { + if (r.value) + { total++; } } @@ -109,15 +127,25 @@ py::object test_bash_retainers2(SerializableCollection* sc, py::object materiali return total > 0 ? py::cast(so) : py::none(); } -void test_gil_scoping() { +void +test_gil_scoping() +{ { - { py::gil_scoped_release release; } - { py::gil_scoped_acquire acquire; } + { + py::gil_scoped_release release; + } + { + py::gil_scoped_acquire acquire; + } } { - { py::gil_scoped_acquire acquire; } - { py::gil_scoped_release release; } + { + py::gil_scoped_acquire acquire; + } + { + py::gil_scoped_release release; + } } { @@ -131,15 +159,19 @@ void test_gil_scoping() { } } -void otio_xyzzy(std::string msg) { +void +otio_xyzzy(std::string msg) +{ printf("XYZZY: %s\n", msg.c_str()); /* used as a debugger breakpoint */ } /// test the behavior of big integers in OTIO -bool test_big_uint() { - int64_t some_int = 4; - uint64_t number_base = INT64_MAX; +bool +test_big_uint() +{ + int64_t some_int = 4; + uint64_t number_base = INT64_MAX; uint64_t giant_number = number_base + some_int; SerializableObjectWithMetadata* so = new SerializableObjectWithMetadata(); @@ -148,7 +180,8 @@ bool test_big_uint() { bool result = true; - if (std::any_cast(so->metadata()["giant_number"]) != giant_number) { + if (std::any_cast(so->metadata()["giant_number"]) != giant_number) + { return false; } @@ -156,26 +189,34 @@ bool test_big_uint() { return true; } - -void test_AnyDictionary_destroy(AnyDictionaryProxy* d) { +void +test_AnyDictionary_destroy(AnyDictionaryProxy* d) +{ delete d->any_dictionary; } -void test_AnyVector_destroy(AnyVectorProxy* v) { +void +test_AnyVector_destroy(AnyVectorProxy* v) +{ delete v->any_vector; } -void otio_tests_bindings(py::module m) { +void +otio_tests_bindings(py::module m) +{ TypeRegistry& r = TypeRegistry::instance(); r.register_type(); - - py::class_>(m, "TestObject", py::dynamic_attr()) + + py::class_< + TestObject, + SerializableObjectWithMetadata, + managing_ptr>(m, "TestObject", py::dynamic_attr()) .def(py::init(), "name"_a) .def("lookup", &TestObject::lookup, "key"_a) .def("__repr__", &TestObject::repr); - py::module test = m.def_submodule("_testing", "Module for OTIO regression testing"); + py::module test = + m.def_submodule("_testing", "Module for OTIO regression testing"); test.def("takeme", &test_takeme); test.def("bash_retainers1", &test_bash_retainers1); test.def("bash_retainers2", &test_bash_retainers2); diff --git a/src/py-opentimelineio/opentimelineio-bindings/otio_utils.cpp b/src/py-opentimelineio/opentimelineio-bindings/otio_utils.cpp index eaa74fc9fb..7dbad04f1c 100644 --- a/src/py-opentimelineio/opentimelineio-bindings/otio_utils.cpp +++ b/src/py-opentimelineio/opentimelineio-bindings/otio_utils.cpp @@ -2,178 +2,251 @@ // Copyright Contributors to the OpenTimelineIO project #include "otio_utils.h" -#include "otio_anyDictionary.h" -#include "otio_anyVector.h" #include "opentime/rationalTime.h" #include "opentime/timeRange.h" #include "opentime/timeTransform.h" -#include "opentimelineio/serializableObject.h" #include "opentimelineio/safely_typed_any.h" +#include "opentimelineio/serializableObject.h" #include "opentimelineio/stringUtils.h" +#include "otio_anyDictionary.h" +#include "otio_anyVector.h" #include -#include #include +#include namespace py = pybind11; -bool compare_typeids(std::type_info const& lhs, std::type_info const& rhs) { +bool +compare_typeids(std::type_info const& lhs, std::type_info const& rhs) +{ return lhs.name() == rhs.name() || !strcmp(lhs.name(), rhs.name()); } -static std::map> _py_cast_dispatch_table; -static std::map> _py_cast_dispatch_table_by_name; - -py::object plain_string(std::string const& s) { - #if PY_MAJOR_VERSION >= 3 - PyObject *p = PyUnicode_FromString(s.c_str()); - #else - PyObject *p = PyString_FromString(s.c_str()); - #endif +static std:: + map> + _py_cast_dispatch_table; +static std::map> + _py_cast_dispatch_table_by_name; + +py::object +plain_string(std::string const& s) +{ +#if PY_MAJOR_VERSION >= 3 + PyObject* p = PyUnicode_FromString(s.c_str()); +#else + PyObject* p = PyString_FromString(s.c_str()); +#endif return py::reinterpret_steal(p); } -py::object plain_int(int i) { - PyObject *p = PyLong_FromLong(i); +py::object +plain_int(int i) +{ + PyObject* p = PyLong_FromLong(i); return py::reinterpret_steal(p); } -py::object plain_int(int64_t i) { - PyObject *p = PyLong_FromLongLong(i); +py::object +plain_int(int64_t i) +{ + PyObject* p = PyLong_FromLongLong(i); return py::reinterpret_steal(p); } -py::object plain_uint(uint64_t i) { - PyObject *p = PyLong_FromUnsignedLongLong(i); +py::object +plain_uint(uint64_t i) +{ + PyObject* p = PyLong_FromUnsignedLongLong(i); return py::reinterpret_steal(p); } -void _build_any_to_py_dispatch_table() { +void +_build_any_to_py_dispatch_table() +{ auto& t = _py_cast_dispatch_table; t[&typeid(void)] = [](std::any const& /* a */, bool) { return py::none(); }; - t[&typeid(bool)] = [](std::any const& a, bool) { return py::cast(safely_cast_bool_any(a)); }; - t[&typeid(int)] = [](std::any const& a, bool) { return plain_int(safely_cast_int_any(a)); }; - t[&typeid(int64_t)] = [](std::any const& a, bool) { return plain_int(safely_cast_int64_any(a)); }; - t[&typeid(uint64_t)] = [](std::any const& a, bool) { return plain_uint(safely_cast_uint64_any(a)); }; - t[&typeid(double)] = [](std::any const& a, bool) { return py::cast(safely_cast_double_any(a)); }; - t[&typeid(std::string)] = [](std::any const& a, bool) { return py::cast(safely_cast_string_any(a)); }; - t[&typeid(RationalTime)] = [](std::any const& a, bool) { return py::cast(safely_cast_rational_time_any(a)); }; - t[&typeid(TimeRange)] = [](std::any const& a, bool) { return py::cast(safely_cast_time_range_any(a)); }; - t[&typeid(TimeTransform)] = [](std::any const& a, bool) { return py::cast(safely_cast_time_transform_any(a)); }; - t[&typeid(Color)] = [](std::any const& a, bool) { return py::cast(safely_cast_color_any(a)); }; - t[&typeid(IMATH_NAMESPACE::V2d)] = [](std::any const& a, bool) { return py::cast(safely_cast_point_any(a)); }; - t[&typeid(IMATH_NAMESPACE::Box2d)] = [](std::any const& a, bool) { return py::cast(safely_cast_box_any(a)); }; + t[&typeid(bool)] = [](std::any const& a, bool) { + return py::cast(safely_cast_bool_any(a)); + }; + t[&typeid(int)] = [](std::any const& a, bool) { + return plain_int(safely_cast_int_any(a)); + }; + t[&typeid(int64_t)] = [](std::any const& a, bool) { + return plain_int(safely_cast_int64_any(a)); + }; + t[&typeid(uint64_t)] = [](std::any const& a, bool) { + return plain_uint(safely_cast_uint64_any(a)); + }; + t[&typeid(double)] = [](std::any const& a, bool) { + return py::cast(safely_cast_double_any(a)); + }; + t[&typeid(std::string)] = [](std::any const& a, bool) { + return py::cast(safely_cast_string_any(a)); + }; + t[&typeid(RationalTime)] = [](std::any const& a, bool) { + return py::cast(safely_cast_rational_time_any(a)); + }; + t[&typeid(TimeRange)] = [](std::any const& a, bool) { + return py::cast(safely_cast_time_range_any(a)); + }; + t[&typeid(TimeTransform)] = [](std::any const& a, bool) { + return py::cast(safely_cast_time_transform_any(a)); + }; + t[&typeid(Color)] = [](std::any const& a, bool) { + return py::cast(safely_cast_color_any(a)); + }; + t[&typeid(IMATH_NAMESPACE::V2d)] = [](std::any const& a, bool) { + return py::cast(safely_cast_point_any(a)); + }; + t[&typeid(IMATH_NAMESPACE::Box2d)] = [](std::any const& a, bool) { + return py::cast(safely_cast_box_any(a)); + }; t[&typeid(SerializableObject::Retainer<>)] = [](std::any const& a, bool) { SerializableObject* so = safely_cast_retainer_any(a); - return py::cast(managing_ptr(so)); }; - t[&typeid(AnyDictionaryProxy*)] = [](std::any const& a, bool) { return py::cast(std::any_cast(a)); }; - t[&typeid(AnyVectorProxy*)] = [](std::any const& a, bool) { return py::cast(std::any_cast(a)); }; + return py::cast(managing_ptr(so)); + }; + t[&typeid(AnyDictionaryProxy*)] = [](std::any const& a, bool) { + return py::cast(std::any_cast(a)); + }; + t[&typeid(AnyVectorProxy*)] = [](std::any const& a, bool) { + return py::cast(std::any_cast(a)); + }; t[&typeid(AnyDictionary)] = [](std::any const& a, bool top_level) { AnyDictionary& d = temp_safely_cast_any_dictionary_any(a); - if (top_level) { + if (top_level) + { auto proxy = new AnyDictionaryProxy; proxy->fetch_any_dictionary().swap(d); return py::cast(proxy); } - else { - return py::cast((AnyDictionaryProxy*)d.get_or_create_mutation_stamp()); + else + { + return py::cast( + (AnyDictionaryProxy*) d.get_or_create_mutation_stamp()); } }; - + t[&typeid(AnyVector)] = [](std::any const& a, bool top_level) { AnyVector& v = temp_safely_cast_any_vector_any(a); - if (top_level) { + if (top_level) + { auto proxy = new AnyVectorProxy; proxy->fetch_any_vector().swap(v); return py::cast(proxy); } - return py::cast((AnyVectorProxy*)v.get_or_create_mutation_stamp()); + return py::cast((AnyVectorProxy*) v.get_or_create_mutation_stamp()); }; - for (auto e: t) { + for (auto e: t) + { _py_cast_dispatch_table_by_name[e.first->name()] = e.second; } } // Initialized lazily after the interpreter is ready. -// constructing py::none() at static init time triggers +// constructing py::none() at static init time triggers // pybind11 GIL assertions in Debug builds. static py::object _value_to_any; -static void py_to_any(py::object const& o, std::any* result) { - if (!_value_to_any || _value_to_any.is_none()) { +static void +py_to_any(py::object const& o, std::any* result) +{ + if (!_value_to_any || _value_to_any.is_none()) + { py::object core = py::module::import("opentimelineio.core"); - _value_to_any = core.attr("_value_to_any"); + _value_to_any = core.attr("_value_to_any"); } result->swap(_value_to_any(o).cast()->a); } -AnyDictionary py_to_any_dictionary(py::object const& o) { - if (o.is_none()) { +AnyDictionary +py_to_any_dictionary(py::object const& o) +{ + if (o.is_none()) + { return AnyDictionary(); } std::any a; py_to_any(o, &a); - if (!compare_typeids(a.type(), typeid(AnyDictionary))) { - throw py::type_error(string_printf("Expected an AnyDictionary (i.e. metadata); got %s instead", - type_name_for_error_message(a).c_str())); + if (!compare_typeids(a.type(), typeid(AnyDictionary))) + { + throw py::type_error(string_printf( + "Expected an AnyDictionary (i.e. metadata); got %s instead", + type_name_for_error_message(a).c_str())); } return safely_cast_any_dictionary_any(a); } -py::object any_to_py(std::any const& a, bool top_level) { +py::object +any_to_py(std::any const& a, bool top_level) +{ std::type_info const& tInfo = a.type(); - auto e = _py_cast_dispatch_table.find(&tInfo); + auto e = _py_cast_dispatch_table.find(&tInfo); - if (e == _py_cast_dispatch_table.end()) { + if (e == _py_cast_dispatch_table.end()) + { auto backup_e = _py_cast_dispatch_table_by_name.find(tInfo.name()); - if (backup_e != _py_cast_dispatch_table_by_name.end()) { + if (backup_e != _py_cast_dispatch_table_by_name.end()) + { _py_cast_dispatch_table[&tInfo] = backup_e->second; e = _py_cast_dispatch_table.find(&tInfo); } } - if (e == _py_cast_dispatch_table.end()) { - throw py::value_error(string_printf("Unable to cast any of type %s to python object", - type_name_for_error_message(tInfo).c_str())); + if (e == _py_cast_dispatch_table.end()) + { + throw py::value_error(string_printf( + "Unable to cast any of type %s to python object", + type_name_for_error_message(tInfo).c_str())); } return e->second(a, top_level); } -struct KeepaliveMonitor { +struct KeepaliveMonitor +{ SerializableObject* _so; - pybind11::object _keep_alive; - + pybind11::object _keep_alive; + KeepaliveMonitor(SerializableObject* so) - : _so(so) { - } - - void monitor() { + : _so(so) + {} + + void monitor() + { pybind11::gil_scoped_acquire acquire; - if (_so->current_ref_count() > 1) { - if (!_keep_alive) { + if (_so->current_ref_count() > 1) + { + if (!_keep_alive) + { _keep_alive = pybind11::cast(_so); } } - else { - if (_keep_alive) { - _keep_alive = pybind11::object(); // this could cause destruction + else + { + if (_keep_alive) + { + _keep_alive = + pybind11::object(); // this could cause destruction } } } }; -void install_external_keepalive_monitor(SerializableObject* so, bool apply_now) { - KeepaliveMonitor m { so }; +void +install_external_keepalive_monitor(SerializableObject* so, bool apply_now) +{ + KeepaliveMonitor m{ so }; using namespace std::placeholders; // printf("Install external keep alive for %p: apply now is %d\n", so, apply_now); - so->install_external_keepalive_monitor(std::bind(&KeepaliveMonitor::monitor, m), - apply_now); + so->install_external_keepalive_monitor( + std::bind(&KeepaliveMonitor::monitor, m), + apply_now); } diff --git a/src/py-opentimelineio/opentimelineio-bindings/otio_utils.h b/src/py-opentimelineio/opentimelineio-bindings/otio_utils.h index b51fc9ac56..002db690ee 100644 --- a/src/py-opentimelineio/opentimelineio-bindings/otio_utils.h +++ b/src/py-opentimelineio/opentimelineio-bindings/otio_utils.h @@ -3,49 +3,50 @@ #pragma once +#include "opentimelineio/safely_typed_any.h" +#include "opentimelineio/serializableObject.h" +#include "opentimelineio/stringUtils.h" +#include "opentimelineio/vectorIndexing.h" #include #include #include -#include "opentimelineio/stringUtils.h" -#include "opentimelineio/serializableObject.h" -#include "opentimelineio/vectorIndexing.h" -#include "opentimelineio/safely_typed_any.h" using namespace opentimelineio::OPENTIMELINEIO_VERSION_NS; void install_external_keepalive_monitor(SerializableObject* so, bool apply_now); - template -struct managing_ptr { +struct managing_ptr +{ managing_ptr(T* ptr) - : _retainer(ptr) { + : _retainer(ptr) + { install_external_keepalive_monitor(ptr, false); } - T* get() const { - return _retainer.value; - } - + T* get() const { return _retainer.value; } + SerializableObject::Retainer<> _retainer; }; PYBIND11_DECLARE_HOLDER_TYPE(T, managing_ptr); template -struct MutableSequencePyAPI : public V { - class Iterator { +struct MutableSequencePyAPI : public V +{ + class Iterator + { public: Iterator(V& v) - : _v(v), - _it(0) { - } - - Iterator* iter() { - return this; - } - - VALUE_TYPE next() { - if (_it == _v.size()) { + : _v(v) + , _it(0) + {} + + Iterator* iter() { return this; } + + VALUE_TYPE next() + { + if (_it == _v.size()) + { throw pybind11::stop_iteration(); } @@ -53,66 +54,73 @@ struct MutableSequencePyAPI : public V { } private: - V& _v; + V& _v; size_t _it; }; - VALUE_TYPE get_item(int index) { - V& v = static_cast(*this); + VALUE_TYPE get_item(int index) + { + V& v = static_cast(*this); index = adjusted_vector_index(index, v); - if (index < 0 || index >= int(v.size())) { + if (index < 0 || index >= int(v.size())) + { throw pybind11::index_error(); } return v[index]; } - void set_item(int index, VALUE_TYPE value) { - V& v = static_cast(*this); + void set_item(int index, VALUE_TYPE value) + { + V& v = static_cast(*this); index = adjusted_vector_index(index, v); - if (index < 0 || index >= int(v.size())) { + if (index < 0 || index >= int(v.size())) + { throw pybind11::index_error(); } v[index] = value; } - - void insert(int index, VALUE_TYPE value) { - V& v = static_cast(*this); + + void insert(int index, VALUE_TYPE value) + { + V& v = static_cast(*this); index = adjusted_vector_index(index, v); - if (size_t(index) >= v.size()) { + if (size_t(index) >= v.size()) + { v.emplace_back(std::move(value)); } - else { + else + { v.insert(v.begin() + std::max(index, 0), std::move(value)); } } - void del_item(int index) { + void del_item(int index) + { V& v = static_cast(*this); - if (v.empty()) { + if (v.empty()) + { throw pybind11::index_error(); } index = adjusted_vector_index(index, v); - if (size_t(index) >= v.size()) { + if (size_t(index) >= v.size()) + { v.pop_back(); } - else { + else + { v.erase(v.begin() + std::max(index, 0)); } } - int len() { - return static_cast(this->size()); - } + int len() { return static_cast(this->size()); } - Iterator* iter() { - return new Iterator(static_cast(*this)); + Iterator* iter() { return new Iterator(static_cast(*this)); } - } - - static void define_py_class(pybind11::module m, std::string name) { + static void define_py_class(pybind11::module m, std::string name) + { typedef MutableSequencePyAPI This; using namespace pybind11::literals; @@ -123,26 +131,37 @@ struct MutableSequencePyAPI : public V { pybind11::class_(m, name.c_str()) .def(pybind11::init<>()) .def("__internal_getitem__", &This::get_item, "index"_a) - .def("__internal_setitem__", &This::set_item, "index"_a, "item"_a.none(false)) + .def( + "__internal_setitem__", + &This::set_item, + "index"_a, + "item"_a.none(false)) .def("__internal_delitem__", &This::del_item, "index"_a) .def("__len__", &This::len) - .def("__internal_insert", &This::insert, "index"_a, "item"_a.none(false)) - .def("__iter__", &This::iter, pybind11::return_value_policy::reference_internal); + .def( + "__internal_insert", + &This::insert, + "index"_a, + "item"_a.none(false)) + .def( + "__iter__", + &This::iter, + pybind11::return_value_policy::reference_internal); } }; -struct PyAny { - PyAny() { - } - +struct PyAny +{ + PyAny() {} + template PyAny(T& value) - : a(create_safely_typed_any(std::move(value))) { - } + : a(create_safely_typed_any(std::move(value))) + {} PyAny(SerializableObject* value) - : a(create_safely_typed_any(value)) { - } + : a(create_safely_typed_any(value)) + {} std::any a; }; @@ -150,6 +169,6 @@ struct PyAny { pybind11::object any_to_py(std::any const& a, bool top_level = false); pybind11::object plain_string(std::string const& s); pybind11::object plain_int(int i); -AnyDictionary py_to_any_dictionary(pybind11::object const& o); +AnyDictionary py_to_any_dictionary(pybind11::object const& o); bool compare_typeids(std::type_info const& lhs, std::type_info const& rhs);