From 8bdb234968aab423f250fe5f0f50e647cfca0db2 Mon Sep 17 00:00:00 2001 From: Stephan Steinbach <61017+ssteinbach@users.noreply.github.com> Date: Tue, 10 Jun 2025 18:37:10 +0000 Subject: [PATCH] Add type hints and stubs --- MANIFEST.in | 1 + setup.py | 2 + .../opentimelineio/exceptions.py | 1 + src/py-opentimelineio/opentimelineio/hooks.py | 23 +- .../opentimelineio/media_linker.py | 27 +- .../opentimelineio/opentime.py | 16 +- .../opentimelineio/test_utils.py | 7 +- .../opentimelineio/url_utils.py | 5 +- .../opentimelineio/versioning.py | 5 +- stubs/opentimelineio/_otio.pyi | 539 ++++++++++++++++++ 10 files changed, 590 insertions(+), 36 deletions(-) create mode 100644 stubs/opentimelineio/_otio.pyi diff --git a/MANIFEST.in b/MANIFEST.in index 9afb117be6..13346129b9 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -24,6 +24,7 @@ exclude OTIO_VERSION.json global-exclude *.pyc global-exclude *.so global-exclude *.pyd +global-include *.pyi prune maintainers prune tsc diff --git a/setup.py b/setup.py index eb73f5fde8..81c9452954 100644 --- a/setup.py +++ b/setup.py @@ -332,6 +332,8 @@ def run(self): package_data={ 'opentimelineio': [ 'adapters/builtin_adapters.plugin_manifest.json', + '*.pyi', + '*/**/*.pyi', ], }, diff --git a/src/py-opentimelineio/opentimelineio/exceptions.py b/src/py-opentimelineio/opentimelineio/exceptions.py index 9647777561..a479c9484f 100644 --- a/src/py-opentimelineio/opentimelineio/exceptions.py +++ b/src/py-opentimelineio/opentimelineio/exceptions.py @@ -8,6 +8,7 @@ UnsupportedSchemaError, CannotComputeAvailableRangeError ) +from typing import Type __all__ = [ 'OTIOError', diff --git a/src/py-opentimelineio/opentimelineio/hooks.py b/src/py-opentimelineio/opentimelineio/hooks.py index af7836b752..a2329f88ec 100644 --- a/src/py-opentimelineio/opentimelineio/hooks.py +++ b/src/py-opentimelineio/opentimelineio/hooks.py @@ -5,6 +5,7 @@ plugins, core, ) +from typing import Any, Optional, Dict, List __doc__ = """ HookScripts are plugins that run at defined points ("Hooks"). @@ -82,14 +83,14 @@ class HookScript(plugins.PythonPlugin): def __init__( self, - name=None, - filepath=None, - ): + name: Optional[str] = None, + filepath: Optional[str] = None, + ) -> None: """HookScript plugin constructor.""" super().__init__(name, filepath) - def run(self, in_timeline, argument_map={}): + def run(self, in_timeline: Any, argument_map: Optional[Dict[str, Any]] = {}) -> Any: """Run the hook_function associated with this plugin.""" # @TODO: should in_timeline be passed in place? or should a copy be @@ -100,13 +101,13 @@ def run(self, in_timeline, argument_map={}): argument_map=argument_map ) - def __str__(self): + def __str__(self) -> str: return "HookScript({}, {})".format( repr(self.name), repr(self.filepath) ) - def __repr__(self): + def __repr__(self) -> str: return ( "otio.hooks.HookScript(" "name={}, " @@ -118,24 +119,24 @@ def __repr__(self): ) -def names(): +def names() -> List[str]: """Return a list of all the registered hooks.""" return plugins.ActiveManifest().hooks.keys() -def available_hookscript_names(): +def available_hookscript_names() -> List[str]: """Return the names of HookScripts that have been registered.""" return [hs.name for hs in plugins.ActiveManifest().hook_scripts] -def available_hookscripts(): +def available_hookscripts() -> List[Any]: """Return the HookScripts objects that have been registered.""" return plugins.ActiveManifest().hook_scripts -def scripts_attached_to(hook): +def scripts_attached_to(hook: str) -> List[str]: """Return an editable list of all the hook scripts that are attached to the specified hook, in execution order. Changing this list will change the order that scripts run in, and deleting a script will remove it from @@ -146,7 +147,7 @@ def scripts_attached_to(hook): return plugins.ActiveManifest().hooks[hook] -def run(hook, tl, extra_args=None): +def run(hook: str, tl: Any, extra_args: Optional[Dict[str, Any]] = None) -> Any: """Run all the scripts associated with hook, passing in tl and extra_args. Will return the return value of the last hook script. diff --git a/src/py-opentimelineio/opentimelineio/media_linker.py b/src/py-opentimelineio/opentimelineio/media_linker.py index 41ae876eef..081bf5cd5f 100644 --- a/src/py-opentimelineio/opentimelineio/media_linker.py +++ b/src/py-opentimelineio/opentimelineio/media_linker.py @@ -19,6 +19,7 @@ import os import inspect +from typing import Any, Optional, Dict from . import ( exceptions, @@ -64,7 +65,7 @@ def from_name(name): ) -def default_media_linker(): +def default_media_linker() -> str: try: return os.environ['OTIO_DEFAULT_MEDIA_LINKER'] except KeyError: @@ -74,10 +75,10 @@ def default_media_linker(): def linked_media_reference( - target_clip, - media_linker_name=MediaLinkingPolicy.ForceDefaultLinker, - media_linker_argument_map=None -): + target_clip: Any, + media_linker_name: Any = MediaLinkingPolicy.ForceDefaultLinker, + media_linker_argument_map: Optional[Dict[str, Any]] = None +) -> Any: media_linker = from_name(media_linker_name) if not media_linker: @@ -100,12 +101,12 @@ class MediaLinker(plugins.PythonPlugin): def __init__( self, - name=None, - filepath=None, - ): + name: Optional[str] = None, + filepath: Optional[str] = None, + ) -> None: super().__init__(name, filepath) - def link_media_reference(self, in_clip, media_linker_argument_map=None): + def link_media_reference(self, in_clip: Any, media_linker_argument_map: Optional[Dict[str, Any]] = None) -> Any: media_linker_argument_map = media_linker_argument_map or {} return self._execute_function( @@ -114,10 +115,10 @@ def link_media_reference(self, in_clip, media_linker_argument_map=None): media_linker_argument_map=media_linker_argument_map ) - def is_default_linker(self): + def is_default_linker(self) -> bool: return os.environ.get("OTIO_DEFAULT_MEDIA_LINKER", "") == self.name - def plugin_info_map(self): + def plugin_info_map(self) -> Dict[str, Any]: """Adds extra adapter-specific information to call to the parent fn.""" result = super().plugin_info_map() @@ -133,13 +134,13 @@ def plugin_info_map(self): return result - def __str__(self): + def __str__(self) -> str: return "MediaLinker({}, {})".format( repr(self.name), repr(self.filepath) ) - def __repr__(self): + def __repr__(self) -> str: return ( "otio.media_linker.MediaLinker(" "name={}, " diff --git a/src/py-opentimelineio/opentimelineio/opentime.py b/src/py-opentimelineio/opentimelineio/opentime.py index 509150a159..b066a929d7 100644 --- a/src/py-opentimelineio/opentimelineio/opentime.py +++ b/src/py-opentimelineio/opentimelineio/opentime.py @@ -38,8 +38,12 @@ RationalTime.duration_from_start_end_time_inclusive ) +from typing import Any, Optional -def to_timecode(rt, rate=None, drop_frame=None): + +def to_timecode( + rt: Any, rate: Optional[float] = None, drop_frame: Optional[bool] = None +) -> str: """Convert a :class:`~RationalTime` into a timecode string.""" return ( rt.to_timecode() @@ -48,7 +52,9 @@ def to_timecode(rt, rate=None, drop_frame=None): ) -def to_nearest_timecode(rt, rate=None, drop_frame=None): +def to_nearest_timecode( + rt: Any, rate: Optional[float] = None, drop_frame: Optional[bool] = None +) -> str: """Convert a :class:`~RationalTime` into a timecode string.""" return ( rt.to_nearest_timecode() @@ -57,17 +63,17 @@ def to_nearest_timecode(rt, rate=None, drop_frame=None): ) -def to_frames(rt, rate=None): +def to_frames(rt: Any, rate: Optional[float] = None) -> float: """Turn a :class:`~RationalTime` into a frame number.""" return rt.to_frames() if rate is None else rt.to_frames(rate) -def to_seconds(rt): +def to_seconds(rt: Any) -> float: """Convert a :class:`~RationalTime` into float seconds""" return rt.to_seconds() -def to_time_string(rt): +def to_time_string(rt: Any) -> str: """ Convert this timecode to time as used by ffmpeg, formatted as ``hh:mm:ss`` where ss is an integer or decimal number. diff --git a/src/py-opentimelineio/opentimelineio/test_utils.py b/src/py-opentimelineio/opentimelineio/test_utils.py index f4483fef58..5ee4b373ee 100644 --- a/src/py-opentimelineio/opentimelineio/test_utils.py +++ b/src/py-opentimelineio/opentimelineio/test_utils.py @@ -6,6 +6,7 @@ """Utility assertions for OTIO Unit tests.""" import re +from typing import Any from . import ( adapters @@ -13,14 +14,14 @@ class OTIOAssertions: - def assertJsonEqual(self, known, test_result): + def assertJsonEqual(self, known: Any, test_result: Any) -> None: """Convert to json and compare that (more readable).""" self.maxDiff = None known_str = adapters.write_to_string(known, 'otio_json') test_str = adapters.write_to_string(test_result, 'otio_json') - def strip_trailing_decimal_zero(s): + def strip_trailing_decimal_zero(s: str) -> str: return re.sub(r'"(value|rate)": (\d+)\.0', r'"\1": \2', s) self.assertMultiLineEqual( @@ -28,7 +29,7 @@ def strip_trailing_decimal_zero(s): strip_trailing_decimal_zero(test_str) ) - def assertIsOTIOEquivalentTo(self, known, test_result): + def assertIsOTIOEquivalentTo(self, known: Any, test_result: Any) -> None: """Test using the 'is equivalent to' method on SerializableObject""" self.assertTrue(known.is_equivalent_to(test_result)) diff --git a/src/py-opentimelineio/opentimelineio/url_utils.py b/src/py-opentimelineio/opentimelineio/url_utils.py index d99cc9ba90..cea3df4cc3 100644 --- a/src/py-opentimelineio/opentimelineio/url_utils.py +++ b/src/py-opentimelineio/opentimelineio/url_utils.py @@ -7,9 +7,10 @@ import urllib from urllib import request import pathlib +from typing import Union, Any -def url_from_filepath(fpath): +def url_from_filepath(fpath: Union[str, os.PathLike]) -> str: """Convert a filesystem path to an url in a portable way. ensures that `fpath` conforms to the following pattern: @@ -42,7 +43,7 @@ def url_from_filepath(fpath): ) -def filepath_from_url(urlstr): +def filepath_from_url(urlstr: str) -> str: """ Take an url and return a filepath. diff --git a/src/py-opentimelineio/opentimelineio/versioning.py b/src/py-opentimelineio/opentimelineio/versioning.py index 4fd0e9126c..f8d874030d 100644 --- a/src/py-opentimelineio/opentimelineio/versioning.py +++ b/src/py-opentimelineio/opentimelineio/versioning.py @@ -4,6 +4,7 @@ """Tools for fetching the family->label->schema:version maps""" import copy +from typing import Dict from . import ( core, @@ -11,7 +12,7 @@ ) -def full_map(): +def full_map() -> Dict[str, Dict[str, Dict[str, int]]]: """Return the full map of schema version sets, including core and plugins. Organized as follows: @@ -57,7 +58,7 @@ def full_map(): return result -def fetch_map(family, label): +def fetch_map(family: str, label: str) -> Dict[str, int]: """Fetch the version map for the given family and label. OpenTimelineIO includes a built in family called "OTIO_CORE", this is compiled into the C++ core and represents the core interchange schemas of OpenTimelineIO. diff --git a/stubs/opentimelineio/_otio.pyi b/stubs/opentimelineio/_otio.pyi new file mode 100644 index 0000000000..aeb24c2562 --- /dev/null +++ b/stubs/opentimelineio/_otio.pyi @@ -0,0 +1,539 @@ +import opentimelineio._opentime +import typing +from typing import Callable, ClassVar, overload + +class AnyDictionary: + clear: ClassVar[Callable] = ... + get: ClassVar[Callable] = ... + items: ClassVar[Callable] = ... + keys: ClassVar[Callable] = ... + pop: ClassVar[Callable] = ... + popitem: ClassVar[Callable] = ... + setdefault: ClassVar[Callable] = ... + update: ClassVar[Callable] = ... + values: ClassVar[Callable] = ... + __contains__: ClassVar[Callable] = ... + __copy__: ClassVar[Callable] = ... + __deepcopy__: ClassVar[Callable] = ... + __eq__: ClassVar[Callable] = ... + __setitem__: ClassVar[Callable] = ... + def __init__(self) -> None: ... + def __delitem__(self, key: str) -> None: ... + def __getitem__(self, key: str) -> object: ... + def __internal_setitem__(self, key: str, item: PyAny) -> None: ... + def __iter__(self) -> AnyDictionaryIterator: ... + def __len__(self) -> int: ... + +class AnyDictionaryIterator: + def __init__(self, *args, **kwargs) -> None: ... + def __iter__(self) -> AnyDictionaryIterator: ... + def __next__(self) -> object: ... + +class AnyVector: + append: ClassVar[Callable] = ... + clear: ClassVar[Callable] = ... + count: ClassVar[Callable] = ... + extend: ClassVar[Callable] = ... + index: ClassVar[Callable] = ... + insert: ClassVar[Callable] = ... + pop: ClassVar[Callable] = ... + remove: ClassVar[Callable] = ... + reverse: ClassVar[Callable] = ... + __add__: ClassVar[Callable] = ... + __contains__: ClassVar[Callable] = ... + __copy__: ClassVar[Callable] = ... + __deepcopy__: ClassVar[Callable] = ... + __delitem__: ClassVar[Callable] = ... + __getitem__: ClassVar[Callable] = ... + __iadd__: ClassVar[Callable] = ... + __radd__: ClassVar[Callable] = ... + __reversed__: ClassVar[Callable] = ... + __setitem__: ClassVar[Callable] = ... + def __init__(self) -> None: ... + def __internal_delitem__(self, index: int) -> None: ... + def __internal_getitem__(self, index: int) -> object: ... + def __internal_setitem__(self, index: int, item: PyAny) -> None: ... + def __iter__(self) -> AnyVectorIterator: ... + def __len__(self) -> int: ... + +class AnyVectorIterator: + def __init__(self, *args, **kwargs) -> None: ... + def __iter__(self) -> AnyVectorIterator: ... + def __next__(self) -> object: ... + +class Box2d: + max: V2d + min: V2d + @overload + def __init__(self) -> None: ... + @overload + def __init__(self, arg0: V2d) -> None: ... + @overload + def __init__(self, arg0: V2d, arg1: V2d) -> None: ... + def center(self) -> V2d: ... + @overload + def extendBy(self, arg0: V2d) -> None: ... + @overload + def extendBy(self, arg0: Box2d) -> None: ... + @overload + def intersects(self, arg0: V2d) -> bool: ... + @overload + def intersects(self, arg0: Box2d) -> bool: ... + def __eq__(self, arg0: object) -> bool: ... + def __ne__(self, arg0: object) -> bool: ... + +class CannotComputeAvailableRangeError(OTIOError): ... + +class Clip(Item): + DEFAULT_MEDIA_KEY: ClassVar[str] = ... # read-only + find_clips: ClassVar[Callable] = ... + active_media_reference_key: str + media_reference: MediaReference + def __init__(self, name: str = ..., media_reference: MediaReference = ..., source_range: opentimelineio._opentime.TimeRange | None = ..., metadata: object = ..., effects: list[Effect] | None = ..., markers: list[Marker] | None = ..., active_media_reference: str = ...) -> None: ... + def media_references(self) -> dict[str, MediaReference]: ... + def set_media_references(self, arg0: dict[str, MediaReference], arg1: str) -> None: ... + +class Composable(SerializableObjectWithMetadata): + def __init__(self, name: str = ..., metadata: object = ...) -> None: ... + def overlapping(self) -> bool: ... + def parent(self) -> Composition: ... + def visible(self) -> bool: ... + +class Composition(Item): + append: ClassVar[Callable] = ... + clear: ClassVar[Callable] = ... + count: ClassVar[Callable] = ... + extend: ClassVar[Callable] = ... + index: ClassVar[Callable] = ... + insert: ClassVar[Callable] = ... + pop: ClassVar[Callable] = ... + remove: ClassVar[Callable] = ... + reverse: ClassVar[Callable] = ... + __add__: ClassVar[Callable] = ... + __delitem__: ClassVar[Callable] = ... + __getitem__: ClassVar[Callable] = ... + __iadd__: ClassVar[Callable] = ... + __radd__: ClassVar[Callable] = ... + __reversed__: ClassVar[Callable] = ... + __setitem__: ClassVar[Callable] = ... + def __init__(self, name: str = ..., children: list[Composable] | None = ..., source_range: opentimelineio._opentime.TimeRange | None = ..., metadata: object = ...) -> None: ... + def child_at_time(self, search_time: opentimelineio._opentime.RationalTime, shallow_search: bool = ...) -> Composable: ... + def children_in_range(self, search_range: opentimelineio._opentime.TimeRange) -> list[SerializableObject]: ... + def find_children(self, descended_from_type: object = ..., search_range: opentimelineio._opentime.TimeRange | None = ..., shallow_search: bool = ...) -> list[SerializableObject]: ... + def handles_of_child(self, child: Composable) -> tuple: ... + def has_clips(self) -> bool: ... + def is_parent_of(self, other: Composable) -> bool: ... + def range_of_all_children(self) -> dict: ... + def range_of_child(self, child: Composable, reference_space: Composable = ...) -> opentimelineio._opentime.TimeRange: ... + def range_of_child_at_index(self, index: int) -> opentimelineio._opentime.TimeRange: ... + def trim_child_range(self, child_range: opentimelineio._opentime.TimeRange) -> opentimelineio._opentime.TimeRange | None: ... + def trimmed_child_range(self, child_range: opentimelineio._opentime.TimeRange) -> opentimelineio._opentime.TimeRange | None: ... + def trimmed_range_of_child(self, child: Composable, reference_space: Composable = ...) -> opentimelineio._opentime.TimeRange | None: ... + def trimmed_range_of_child_at_index(self, index: int) -> opentimelineio._opentime.TimeRange: ... + def __contains__(self, composable: Composable) -> bool: ... + def __internal_delitem__(self, index: int) -> None: ... + def __internal_getitem__(self, index: int) -> Composable: ... + def __internal_setitem__(self, index: int, item: Composable) -> None: ... + def __iter__(self) -> CompositionIterator: ... + def __len__(self) -> int: ... + @property + def composition_kind(self) -> str: ... + +class CompositionIterator: + def __init__(self, *args, **kwargs) -> None: ... + def __iter__(self) -> CompositionIterator: ... + def __next__(self) -> Composable: ... + +class Effect(SerializableObjectWithMetadata): + effect_name: str + enabled: bool + def __init__(self, name: str = ..., effect_name: str = ..., metadata: object = ..., enabled: bool = ...) -> None: ... + +class EffectVector: + append: ClassVar[Callable] = ... + clear: ClassVar[Callable] = ... + count: ClassVar[Callable] = ... + extend: ClassVar[Callable] = ... + index: ClassVar[Callable] = ... + insert: ClassVar[Callable] = ... + pop: ClassVar[Callable] = ... + remove: ClassVar[Callable] = ... + reverse: ClassVar[Callable] = ... + __add__: ClassVar[Callable] = ... + __contains__: ClassVar[Callable] = ... + __copy__: ClassVar[Callable] = ... + __deepcopy__: ClassVar[Callable] = ... + __delitem__: ClassVar[Callable] = ... + __getitem__: ClassVar[Callable] = ... + __iadd__: ClassVar[Callable] = ... + __radd__: ClassVar[Callable] = ... + __reversed__: ClassVar[Callable] = ... + __setitem__: ClassVar[Callable] = ... + def __init__(self) -> None: ... + def __internal_delitem__(self, index: int) -> None: ... + def __internal_getitem__(self, *args, **kwargs): ... + def __internal_setitem__(self, index: int, item) -> None: ... + def __iter__(self) -> EffectVectorIterator: ... + def __len__(self) -> int: ... + +class EffectVectorIterator: + def __init__(self, *args, **kwargs) -> None: ... + def __iter__(self) -> EffectVectorIterator: ... + def __next__(self): ... + +class ExternalReference(MediaReference): + target_url: str + def __init__(self, target_url: str = ..., available_range: opentimelineio._opentime.TimeRange | None = ..., metadata: object = ..., available_image_bounds: Box2d | None = ...) -> None: ... + +class FreezeFrame(LinearTimeWarp): + def __init__(self, name: str = ..., metadata: object = ...) -> None: ... + +class Gap(Item): + @overload + def __init__(self, name: str = ..., source_range: opentimelineio._opentime.TimeRange = ..., effects: list[Effect] | None = ..., markers: list[Marker] | None = ..., metadata: object = ...) -> None: ... + @overload + def __init__(self, name: str = ..., duration: opentimelineio._opentime.RationalTime = ..., effects: list[Effect] | None = ..., markers: list[Marker] | None = ..., metadata: object = ...) -> None: ... + +class GeneratorReference(MediaReference): + generator_kind: str + def __init__(self, name: str = ..., generator_kind: str = ..., available_range: opentimelineio._opentime.TimeRange | None = ..., parameters: object = ..., metadata: object = ..., available_image_bounds: Box2d | None = ...) -> None: ... + @property + def parameters(self) -> AnyDictionary: ... + +class ImageSequenceReference(MediaReference): + class MissingFramePolicy: + __members__: ClassVar[dict] = ... # read-only + __entries: ClassVar[dict] = ... + black: ClassVar[ImageSequenceReference.MissingFramePolicy] = ... + error: ClassVar[ImageSequenceReference.MissingFramePolicy] = ... + hold: ClassVar[ImageSequenceReference.MissingFramePolicy] = ... + def __init__(self, value: int) -> None: ... + def __eq__(self, other: object) -> bool: ... + def __hash__(self) -> int: ... + def __index__(self) -> int: ... + def __int__(self) -> int: ... + def __ne__(self, other: object) -> bool: ... + @property + def name(self) -> str: ... + @property + def value(self) -> int: ... + abstract_target_url: ClassVar[Callable] = ... + frame_range_for_time_range: ClassVar[Callable] = ... + frame_step: int + frame_zero_padding: int + missing_frame_policy: ImageSequenceReference.MissingFramePolicy + name_prefix: str + name_suffix: str + rate: float + start_frame: int + target_url_base: str + def __init__(self, target_url_base: str = ..., name_prefix: str = ..., name_suffix: str = ..., start_frame: int = ..., frame_step: int = ..., rate: float = ..., frame_zero_padding: int = ..., missing_frame_policy: ImageSequenceReference.MissingFramePolicy = ..., available_range: opentimelineio._opentime.TimeRange | None = ..., metadata: object = ..., available_image_bounds: Box2d | None = ...) -> None: ... + def end_frame(self) -> int: ... + def frame_for_time(self, time: opentimelineio._opentime.RationalTime) -> int: ... + def number_of_images_in_sequence(self) -> int: ... + def presentation_time_for_image_number(self, image_number: int) -> opentimelineio._opentime.RationalTime: ... + def target_url_for_image_number(self, image_number: int) -> str: ... + +class Item(Composable): + enabled: bool + source_range: opentimelineio._opentime.TimeRange | None + def __init__(self, name: str = ..., source_range: opentimelineio._opentime.TimeRange | None = ..., effects: list[Effect] | None = ..., markers: list[Marker] | None = ..., enabled: bool = ..., metadata: object = ...) -> None: ... + def available_range(self) -> opentimelineio._opentime.TimeRange: ... + def duration(self) -> opentimelineio._opentime.RationalTime: ... + def range_in_parent(self) -> opentimelineio._opentime.TimeRange: ... + def transformed_time(self, time: opentimelineio._opentime.RationalTime, to_item: Item) -> opentimelineio._opentime.RationalTime: ... + def transformed_time_range(self, time_range: opentimelineio._opentime.TimeRange, to_item: Item) -> opentimelineio._opentime.TimeRange: ... + def trimmed_range(self) -> opentimelineio._opentime.TimeRange: ... + def trimmed_range_in_parent(self) -> opentimelineio._opentime.TimeRange | None: ... + def visible_range(self) -> opentimelineio._opentime.TimeRange: ... + @property + def available_image_bounds(self) -> Box2d | None: ... + @property + def effects(self) -> EffectVector: ... + @property + def markers(self) -> MarkerVector: ... + +class LinearTimeWarp(TimeEffect): + time_scalar: float + def __init__(self, name: str = ..., time_scalar: float = ..., metadata: object = ...) -> None: ... + +class Marker(SerializableObjectWithMetadata): + class Color: + BLACK: ClassVar[str] = ... # read-only + BLUE: ClassVar[str] = ... # read-only + CYAN: ClassVar[str] = ... # read-only + GREEN: ClassVar[str] = ... # read-only + MAGENTA: ClassVar[str] = ... # read-only + ORANGE: ClassVar[str] = ... # read-only + PINK: ClassVar[str] = ... # read-only + PURPLE: ClassVar[str] = ... # read-only + RED: ClassVar[str] = ... # read-only + WHITE: ClassVar[str] = ... # read-only + YELLOW: ClassVar[str] = ... # read-only + def __init__(self, *args, **kwargs) -> None: ... + color: str + comment: str + marked_range: opentimelineio._opentime.TimeRange + def __init__(self, name: str = ..., marked_range: opentimelineio._opentime.TimeRange = ..., color: str = ..., metadata: object = ..., comment: str = ...) -> None: ... + +class MarkerVector: + append: ClassVar[Callable] = ... + clear: ClassVar[Callable] = ... + count: ClassVar[Callable] = ... + extend: ClassVar[Callable] = ... + index: ClassVar[Callable] = ... + insert: ClassVar[Callable] = ... + pop: ClassVar[Callable] = ... + remove: ClassVar[Callable] = ... + reverse: ClassVar[Callable] = ... + __add__: ClassVar[Callable] = ... + __contains__: ClassVar[Callable] = ... + __copy__: ClassVar[Callable] = ... + __deepcopy__: ClassVar[Callable] = ... + __delitem__: ClassVar[Callable] = ... + __getitem__: ClassVar[Callable] = ... + __iadd__: ClassVar[Callable] = ... + __radd__: ClassVar[Callable] = ... + __reversed__: ClassVar[Callable] = ... + __setitem__: ClassVar[Callable] = ... + def __init__(self) -> None: ... + def __internal_delitem__(self, index: int) -> None: ... + def __internal_getitem__(self, *args, **kwargs): ... + def __internal_setitem__(self, index: int, item) -> None: ... + def __iter__(self) -> MarkerVectorIterator: ... + def __len__(self) -> int: ... + +class MarkerVectorIterator: + def __init__(self, *args, **kwargs) -> None: ... + def __iter__(self) -> MarkerVectorIterator: ... + def __next__(self): ... + +class MediaReference(SerializableObjectWithMetadata): + available_image_bounds: Box2d | None + available_range: opentimelineio._opentime.TimeRange | None + def __init__(self, name: str = ..., available_range: opentimelineio._opentime.TimeRange | None = ..., metadata: object = ..., available_image_bounds: Box2d | None = ...) -> None: ... + @property + def is_missing_reference(self) -> bool: ... + +class MissingReference(MediaReference): + def __init__(self, name: str = ..., available_range: opentimelineio._opentime.TimeRange | None = ..., metadata: object = ..., available_image_bounds: Box2d | None = ...) -> None: ... + +class NotAChildError(OTIOError): ... + +class OTIOError(Exception): ... + +class PyAny: + @overload + def __init__(self, arg0: bool) -> None: ... + @overload + def __init__(self, arg0: int) -> None: ... + @overload + def __init__(self, arg0: float) -> None: ... + @overload + def __init__(self, arg0: str) -> None: ... + @overload + def __init__(self, arg0: None) -> None: ... + @overload + def __init__(self, arg0: SerializableObject) -> None: ... + @overload + def __init__(self, arg0: opentimelineio._opentime.RationalTime) -> None: ... + @overload + def __init__(self, arg0: opentimelineio._opentime.TimeRange) -> None: ... + @overload + def __init__(self, arg0: opentimelineio._opentime.TimeTransform) -> None: ... + @overload + def __init__(self, arg0: V2d) -> None: ... + @overload + def __init__(self, arg0: Box2d) -> None: ... + @overload + def __init__(self, arg0: AnyVector) -> None: ... + @overload + def __init__(self, arg0: AnyDictionary) -> None: ... + +class SerializableCollection(SerializableObjectWithMetadata): + append: ClassVar[Callable] = ... + clear: ClassVar[Callable] = ... + count: ClassVar[Callable] = ... + extend: ClassVar[Callable] = ... + index: ClassVar[Callable] = ... + insert: ClassVar[Callable] = ... + pop: ClassVar[Callable] = ... + remove: ClassVar[Callable] = ... + reverse: ClassVar[Callable] = ... + __add__: ClassVar[Callable] = ... + __contains__: ClassVar[Callable] = ... + __delitem__: ClassVar[Callable] = ... + __getitem__: ClassVar[Callable] = ... + __iadd__: ClassVar[Callable] = ... + __radd__: ClassVar[Callable] = ... + __reversed__: ClassVar[Callable] = ... + __setitem__: ClassVar[Callable] = ... + def __init__(self, name: str = ..., children: list[SerializableObject] | None = ..., metadata: object = ...) -> None: ... + def find_children(self, descended_from_type: object = ..., search_range: opentimelineio._opentime.TimeRange | None = ..., shallow_search: bool = ...) -> list[SerializableObject]: ... + def find_clips(self, search_range: opentimelineio._opentime.TimeRange | None = ..., shallow_search: bool = ...) -> list[SerializableObject]: ... + def __internal_delitem__(self, index: int) -> None: ... + def __internal_getitem__(self, index: int) -> SerializableObject: ... + def __internal_setitem__(self, index: int, item: SerializableObject) -> None: ... + def __iter__(self) -> SerializableCollectionIterator: ... + def __len__(self) -> int: ... + +class SerializableCollectionIterator: + def __init__(self, *args, **kwargs) -> None: ... + def __iter__(self) -> SerializableCollectionIterator: ... + def __next__(self) -> SerializableObject: ... + +class SerializableObject: + deepcopy: ClassVar[Callable] = ... + __copy__: ClassVar[Callable] = ... + __deepcopy__: ClassVar[Callable] = ... + __setattr__: ClassVar[Callable] = ... + def __init__(self) -> None: ... + def clone(self) -> SerializableObject: ... + @staticmethod + def from_json_file(file_name: str) -> SerializableObject: ... + @staticmethod + def from_json_string(input: str) -> SerializableObject: ... + def is_equivalent_to(self, other: SerializableObject) -> bool: ... + def schema_name(self) -> str: ... + def schema_version(self) -> int: ... + def to_json_file(self, file_name: str, indent: int = ...) -> bool: ... + def to_json_string(self, indent: int = ...) -> str: ... + @property + def is_unknown_schema(self) -> bool: ... + +class SerializableObjectWithMetadata(SerializableObject): + name: object + def __init__(self, name: str = ..., metadata: object = ...) -> None: ... + @property + def metadata(self) -> AnyDictionary: ... + +class Stack(Composition): + def __init__(self, name: str = ..., children: list[Composable] | None = ..., source_range: opentimelineio._opentime.TimeRange | None = ..., markers: list[Marker] | None = ..., effects: list[Effect] | None = ..., metadata: object = ...) -> None: ... + def find_clips(self, search_range: opentimelineio._opentime.TimeRange | None = ..., shallow_search: bool = ...) -> list[SerializableObject]: ... + +class TestObject(SerializableObjectWithMetadata): + def __init__(self, name: str) -> None: ... + def lookup(self, key: str) -> SerializableObject: ... + +class TimeEffect(Effect): + def __init__(self, name: str = ..., effect_name: str = ..., metadata: object = ...) -> None: ... + +class Timeline(SerializableObjectWithMetadata): + global_start_time: opentimelineio._opentime.RationalTime | None + tracks: Stack + def __init__(self, name: str = ..., tracks: list[Composable] | None = ..., global_start_time: opentimelineio._opentime.RationalTime | None = ..., metadata: object = ...) -> None: ... + def audio_tracks(self) -> list[Track]: ... + def duration(self) -> opentimelineio._opentime.RationalTime: ... + def find_children(self, descended_from_type: object = ..., search_range: opentimelineio._opentime.TimeRange | None = ..., shallow_search: bool = ...) -> list[SerializableObject]: ... + def find_clips(self, search_range: opentimelineio._opentime.TimeRange | None = ..., shallow_search: bool = ...) -> list[SerializableObject]: ... + def range_of_child(self, arg0: Composable) -> opentimelineio._opentime.TimeRange: ... + def video_tracks(self) -> list[Track]: ... + +class Track(Composition): + class Kind: + Audio: ClassVar[str] = ... # read-only + Video: ClassVar[str] = ... # read-only + def __init__(self, *args, **kwargs) -> None: ... + + class NeighborGapPolicy: + __members__: ClassVar[dict] = ... # read-only + __entries: ClassVar[dict] = ... + around_transitions: ClassVar[Track.NeighborGapPolicy] = ... + never: ClassVar[Track.NeighborGapPolicy] = ... + def __init__(self, value: int) -> None: ... + def __eq__(self, other: object) -> bool: ... + def __hash__(self) -> int: ... + def __index__(self) -> int: ... + def __int__(self) -> int: ... + def __ne__(self, other: object) -> bool: ... + @property + def name(self) -> str: ... + @property + def value(self) -> int: ... + kind: str + def __init__(self, name: str = ..., children: list[Composable] | None = ..., source_range: opentimelineio._opentime.TimeRange | None = ..., kind: str = ..., metadata: object = ...) -> None: ... + def find_clips(self, search_range: opentimelineio._opentime.TimeRange | None = ..., shallow_search: bool = ...) -> list[SerializableObject]: ... + def neighbors_of(self, item: Composable, policy: Track.NeighborGapPolicy = ...) -> tuple: ... + +class Transition(Composable): + class Type: + Custom: ClassVar[str] = ... # read-only + SMPTE_Dissolve: ClassVar[str] = ... # read-only + def __init__(self, *args, **kwargs) -> None: ... + in_offset: opentimelineio._opentime.RationalTime + out_offset: opentimelineio._opentime.RationalTime + transition_type: str + def __init__(self, name: str = ..., transition_type: str = ..., in_offset: opentimelineio._opentime.RationalTime = ..., out_offset: opentimelineio._opentime.RationalTime = ..., metadata: object = ...) -> None: ... + def duration(self) -> opentimelineio._opentime.RationalTime: ... + def range_in_parent(self) -> opentimelineio._opentime.TimeRange | None: ... + def trimmed_range_in_parent(self) -> opentimelineio._opentime.TimeRange | None: ... + +class UnknownSchema(SerializableObject): + def __init__(self, *args, **kwargs) -> None: ... + @property + def original_schema_name(self) -> str: ... + @property + def original_schema_version(self) -> int: ... + +class UnsupportedSchemaError(OTIOError): ... + +class V2d: + x: float + y: float + @overload + def __init__(self) -> None: ... + @overload + def __init__(self, arg0: float) -> None: ... + @overload + def __init__(self, arg0: float, arg1: float) -> None: ... + @staticmethod + def baseTypeEpsilon() -> float: ... + @staticmethod + def baseTypeLowest() -> float: ... + @staticmethod + def baseTypeMax() -> float: ... + @staticmethod + def baseTypeSmallest() -> float: ... + def cross(self, arg0: V2d) -> float: ... + @staticmethod + def dimensions() -> int: ... + def dot(self, arg0: V2d) -> float: ... + def equalWithAbsError(self, arg0: V2d, arg1: float) -> bool: ... + def equalWithRelError(self, arg0: V2d, arg1: float) -> bool: ... + def length(self) -> float: ... + def length2(self) -> float: ... + def normalize(self) -> V2d: ... + def normalizeExc(self) -> V2d: ... + def normalizeNonNull(self) -> V2d: ... + def normalized(self) -> V2d: ... + def normalizedExc(self) -> V2d: ... + def normalizedNonNull(self) -> V2d: ... + def __add__(self, arg0: V2d) -> V2d: ... + def __eq__(self, arg0: object) -> bool: ... + def __getitem__(self, arg0: int) -> float: ... + def __iter__(self) -> typing.Iterator[float]: ... + def __iadd__(self, arg0: V2d) -> V2d: ... + def __idiv__(self, arg0: V2d) -> V2d: ... + def __imul__(self, arg0: V2d) -> V2d: ... + def __isub__(self, arg0: V2d) -> V2d: ... + def __mod__(self, arg0: object) -> float: ... + def __mul__(self, arg0: V2d) -> V2d: ... + def __ne__(self, arg0: object) -> bool: ... + def __sub__(self, arg0: V2d) -> V2d: ... + def __truediv__(self, arg0: V2d) -> V2d: ... + def __xor__(self, arg0: object) -> float: ... + +def deserialize_json_from_file(filename: str) -> object: ... +def deserialize_json_from_string(input: str) -> object: ... +@overload +def flatten_stack(in_stack: Stack) -> Track: ... +@overload +def flatten_stack(tracks: list[Track]) -> Track: ... +def install_external_keepalive_monitor(so: SerializableObject, apply_now: bool) -> None: ... +def instance_from_schema(schema_name: str, schema_version: int, data: object) -> SerializableObject: ... +def register_downgrade_function(schema_name: str, version_to_downgrade_from: int, downgrade_function: Callable[[AnyDictionary], None]) -> bool: ... +def register_serializable_object_type(class_object: object, schema_name: str, schema_version: int) -> None: ... +def register_upgrade_function(schema_name: str, version_to_upgrade_to: int, upgrade_function: Callable[[AnyDictionary], None]) -> bool: ... +def release_to_schema_version_map() -> dict[str, dict[str, int]]: ... +def set_type_record(serializable_obejct: SerializableObject, schema_name: str) -> None: ... +def type_version_map() -> dict[str, int]: ...