Skip to content

Commit f7fe9c2

Browse files
Merge branch 'main' into MB_NewOTIOIntegration
* main: Add Python 3.10 to CI (AcademySoftwareFoundation#1256) Fix missing init metadata (AcademySoftwareFoundation#1251) Support OTIO_PLUGIN_MANIFEST_PATH being set to an emptry string (AcademySoftwareFoundation#1253) Add ALE adapter argument `ale_name_column_key` (AcademySoftwareFoundation#1248) AAF Adapter: Mob transcription heuristics (AcademySoftwareFoundation#1249) Bump src/deps/Imath from `bd6f74c` to `bd254da` (AcademySoftwareFoundation#1245) clang notices that constexpr can't be used on a mutating function (AcademySoftwareFoundation#1242)
2 parents e37ede9 + a1a69b9 commit f7fe9c2

File tree

10 files changed

+220
-127
lines changed

10 files changed

+220
-127
lines changed

.github/workflows/python-package.yml

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ jobs:
8383
strategy:
8484
matrix:
8585
os: [ubuntu-latest, windows-latest, macos-latest]
86-
python-version: ['2.7', '3.7', '3.8', '3.9']
86+
python-version: ['2.7', '3.7', '3.8', '3.9', '3.10']
8787

8888
env:
8989
OTIO_CXX_COVERAGE_BUILD: ON
@@ -133,7 +133,7 @@ jobs:
133133
strategy:
134134
matrix:
135135
os: [ubuntu-latest, windows-latest, macos-latest]
136-
python-build: [cp27*, cp37*, cp38*, cp39*]
136+
python-build: ['cp27*', 'cp37*', 'cp38*', 'cp39*', 'cp310*']
137137
steps:
138138
- uses: actions/checkout@v3
139139

@@ -153,13 +153,26 @@ jobs:
153153
echo "DISTUTILS_USE_SDK=1" >> $GITHUB_ENV
154154
echo "MSSdk=1" >> $GITHUB_ENV
155155
156-
- name: Build wheels
156+
- name: Build wheels (Python 2.7)
157+
if: matrix.python-build == 'cp27*'
158+
# cibuildwheel 1.12.0 is the last release that supported Python 2.7.
157159
uses: pypa/[email protected]
158160
with:
159161
output-dir: wheelhouse
160162
env:
161163
CIBW_BUILD: ${{ matrix.python-build }}
162164

165+
- name: Build wheels (Python 3)
166+
uses: pypa/[email protected]
167+
if: matrix.python-build != 'cp27*'
168+
with:
169+
output-dir: wheelhouse
170+
env:
171+
CIBW_BUILD: ${{ matrix.python-build }}
172+
CIBW_SKIP: '*musllinux*'
173+
CIBW_MANYLINUX_X86_64_IMAGE: manylinux2010
174+
CIBW_MANYLINUX_I686_IMAGE: manylinux2010
175+
163176
- uses: actions/upload-artifact@v2
164177
with:
165178
name: wheels

CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ project(OpenTimelineIO VERSION ${OTIO_VERSION} LANGUAGES C CXX)
2828
option(OTIO_CXX_INSTALL "Install the C++ bindings" ON)
2929
option(OTIO_PYTHON_INSTALL "Install the Python bindings" OFF)
3030
option(OTIO_DEPENDENCIES_INSTALL "Install OTIO's C++ header dependencies (any and nonstd)" ON)
31+
option(OTIO_INSTALL_PYTHON_MODULES "Install OTIO pure Python modules/files" ON)
3132
option(OTIO_INSTALL_COMMANDLINE_TOOLS "Install the OTIO command line tools" ON)
3233
option(OTIO_INSTALL_CONTRIB "Install the opentimelineio_contrib Python package" ON)
3334
set(OTIO_PYTHON_INSTALL_DIR "" CACHE STRING "Python installation dir (such as the site-packages dir)")
@@ -75,7 +76,7 @@ if(OTIO_PYTHON_INSTALL)
7576
message(STATUS "OTIO Defaulting Python install to ${OTIO_RESOLVED_PYTHON_INSTALL_DIR}")
7677
else()
7778
# either python_install or install_prefix have been set
78-
if(OTIO_PYTHON_INSTALL_DIR_INITIALIZED_TO_DEFAULT)
79+
if(NOT OTIO_PYTHON_INSTALL_DIR)
7980
# CMAKE_INSTALL_PREFIX was set, so install the python components there
8081
set(OTIO_RESOLVED_PYTHON_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/python")
8182

README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ OpenTimelineIO
44
==============
55

66
[![Supported VFX Platform Versions](https://img.shields.io/badge/vfx%20platform-2018--2021-lightgrey.svg)](http://www.vfxplatform.com/)
7-
![Supported Versions](https://img.shields.io/badge/python-2.7%2C%203.7%2C%203.8%2C%203.9-blue)
7+
![Supported Versions](https://img.shields.io/badge/python-2.7%2C%203.7%2C%203.8%2C%203.9%2C%203.10-blue)
88
[![Build Status](https://github.com/PixarAnimationStudios/OpenTimelineIO/actions/workflows/python-package.yml/badge.svg)](https://github.com/PixarAnimationStudios/OpenTimelineIO/actions/workflows/python-package.yml)
99
[![codecov](https://codecov.io/gh/PixarAnimationStudios/OpenTimelineIO/branch/main/graph/badge.svg)](https://codecov.io/gh/PixarAnimationStudios/OpenTimelineIO)
1010
[![docs](https://readthedocs.org/projects/opentimelineio/badge/?version=latest)](https://opentimelineio.readthedocs.io/en/latest/index.html)
@@ -52,8 +52,7 @@ Supported VFX Platforms
5252
-----------------
5353
The current release supports:
5454
- VFX platform 2021, 2020, 2019, 2018
55-
- Python 2.7 - 3.9
56-
- Notice that Python 2.7 is deprecated & we plan to drop it in OTIO release 0.15
55+
- Python 2.7 - 3.10
5756

5857
For more information on our vfxplatform support policy: [Contribution Guidelines Documentation Page](https://opentimelineio.readthedocs.io/en/latest/tutorials/contributing.html)
5958
For more information on the vfxplatform: [VFX Platform Homepage](https://vfxplatform.com)

contrib/opentimelineio_contrib/adapters/advanced_authoring_format.py

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1627,6 +1627,50 @@ def _contains_something_valuable(thing):
16271627
return True
16281628

16291629

1630+
def _get_mobs_for_transcription(storage):
1631+
"""
1632+
When we describe our AAF into OTIO space, we apply the following heuristic:
1633+
1634+
1) First look for top level mobs and if found use that to transcribe.
1635+
1636+
2) If we don't have top level mobs, look for composition mobs and use them to
1637+
transcribe.
1638+
1639+
3) Lastly if we don't have either, try to use master mobs to transcribe.
1640+
1641+
If we don't find any Mobs, just tell the user and do transcrption on an empty
1642+
list (to generate some 'empty-level' OTIO structure)
1643+
1644+
This heuristic is based on 'real-world' examples. There may still be some
1645+
corner cases / open questions (like could there be metadata on both
1646+
a composition mob and master mob? And if so, who would 'win'?)
1647+
1648+
In any way, this heuristic satisfies the current set of AAFs we are using
1649+
in our test-environment.
1650+
1651+
"""
1652+
1653+
top_level_mobs = list(storage.toplevel())
1654+
1655+
if len(top_level_mobs) > 0:
1656+
_transcribe_log("---\nTranscribing top level mobs\n---")
1657+
return top_level_mobs
1658+
1659+
composition_mobs = list(storage.compositionmobs())
1660+
if len(composition_mobs) > 0:
1661+
_transcribe_log("---\nTranscribing composition mobs\n---")
1662+
return composition_mobs
1663+
1664+
master_mobs = list(storage.mastermobs())
1665+
if len(master_mobs) > 0:
1666+
_transcribe_log("---\nTranscribing master mobs\n---")
1667+
return master_mobs
1668+
1669+
_transcribe_log("---\nNo mobs found to transcribe\n---")
1670+
1671+
return []
1672+
1673+
16301674
def read_from_file(
16311675
filepath,
16321676
simplify=True,
@@ -1657,25 +1701,20 @@ def read_from_file(
16571701
_BAKE_KEYFRAMED_PROPERTIES_VALUES = bake_keyframed_properties
16581702

16591703
with aaf2.open(filepath) as aaf_file:
1660-
1661-
storage = aaf_file.content
1662-
1663-
# Note: We're skipping: f.header
1704+
# Note: We're skipping: aaf_file.header
16641705
# Is there something valuable in there?
1665-
_transcribe_log("---\nTranscribing top level mobs\n---", 0)
16661706

1667-
# Get just the top-level MOBS from the AAF
1668-
top = list(storage.toplevel())
1707+
storage = aaf_file.content
1708+
mobs_to_transcribe = _get_mobs_for_transcription(storage)
16691709

1670-
# Transcribe just the top-level mobs
1671-
result = _transcribe(top, parents=list(), edit_rate=None)
1710+
result = _transcribe(mobs_to_transcribe, parents=list(), edit_rate=None)
16721711

16731712
# Attach marker to the appropriate clip, gap etc.
16741713
if attach_markers:
16751714
result = _attach_markers(result)
16761715

16771716
# AAF is typically more deeply nested than OTIO.
1678-
# Lets try to simplify the structure by collapsing or removing
1717+
# Let's try to simplify the structure by collapsing or removing
16791718
# unnecessary stuff.
16801719
if simplify:
16811720
result = _simplify(result)

contrib/opentimelineio_contrib/adapters/ale.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class ALEParseError(otio.exceptions.OTIOError):
5353
pass
5454

5555

56-
def _parse_data_line(line, columns, fps):
56+
def _parse_data_line(line, columns, fps, ale_name_column_key='Name'):
5757
row = line.split("\t")
5858

5959
if len(row) < len(columns):
@@ -71,7 +71,7 @@ def _parse_data_line(line, columns, fps):
7171
metadata = dict(zip(columns, row))
7272

7373
clip = otio.schema.Clip()
74-
clip.name = metadata.pop("Name", None)
74+
clip.name = metadata.get(ale_name_column_key, '')
7575

7676
# When looking for Start, Duration and End, they might be missing
7777
# or blank. Treat None and "" as the same via: get(k,"")!=""
@@ -204,7 +204,8 @@ def _video_format_from_metadata(clips):
204204
return AVID_VIDEO_FORMAT_FROM_WIDTH_HEIGHT(max_width, max_height)
205205

206206

207-
def read_from_string(input_str, fps=24):
207+
def read_from_string(input_str, fps=24, **adapter_argument_map):
208+
ale_name_column_key = adapter_argument_map.get('ale_name_column_key', 'Name')
208209

209210
collection = otio.schema.SerializableCollection()
210211
header = {}
@@ -255,7 +256,10 @@ def nextline(lines):
255256
if line.strip() == "":
256257
continue
257258

258-
clip = _parse_data_line(line, columns, fps)
259+
clip = _parse_data_line(line,
260+
columns,
261+
fps,
262+
ale_name_column_key=ale_name_column_key)
259263

260264
collection.append(clip)
261265

setup.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ def generate_cmake_arguments(self):
9191
'-DOTIO_SHARED_LIBS:BOOL=OFF',
9292
'-DCMAKE_BUILD_TYPE=' + self.build_config,
9393
'-DOTIO_PYTHON_INSTALL_DIR=' + install_dir,
94+
# turn off the C++ tests during a Python build
95+
'-DBUILD_TESTING:BOOL=OFF',
96+
# Python modules wil be installed by setuptools.
97+
'-DOTIO_INSTALL_PYTHON_MODULES:BOOL=OFF',
9498
]
9599

96100
if platform.system() == "Windows":
@@ -290,6 +294,7 @@ def test_otio():
290294
'Programming Language :: Python :: 3.7',
291295
'Programming Language :: Python :: 3.8',
292296
'Programming Language :: Python :: 3.9',
297+
'Programming Language :: Python :: 3.10',
293298
'Operating System :: OS Independent',
294299
'Natural Language :: English',
295300
],

src/opentime/rationalTime.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ class RationalTime
153153

154154
std::string to_time_string() const;
155155

156-
constexpr RationalTime const& operator+=(RationalTime other) noexcept
156+
RationalTime const& operator+=(RationalTime other) noexcept
157157
{
158158
if (_rate < other._rate)
159159
{
@@ -167,7 +167,7 @@ class RationalTime
167167
return *this;
168168
}
169169

170-
constexpr RationalTime const& operator-=(RationalTime other) noexcept
170+
RationalTime const& operator-=(RationalTime other) noexcept
171171
{
172172
if (_rate < other._rate)
173173
{

src/py-opentimelineio/CMakeLists.txt

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,20 @@
44
add_subdirectory(opentime-bindings)
55
add_subdirectory(opentimelineio-bindings)
66

7-
# Install pure-python OTIO packages to match PyPI wheel structure
8-
install(DIRECTORY "${PROJECT_SOURCE_DIR}/src/py-opentimelineio/opentimelineio/"
9-
DESTINATION "${OTIO_RESOLVED_PYTHON_INSTALL_DIR}/opentimelineio")
7+
if(OTIO_INSTALL_PYTHON_MODULES)
8+
# Install pure-python OTIO packages to match PyPI wheel structure
9+
install(DIRECTORY "${PROJECT_SOURCE_DIR}/src/py-opentimelineio/opentimelineio/"
10+
DESTINATION "${OTIO_RESOLVED_PYTHON_INSTALL_DIR}/opentimelineio")
1011

11-
if(OTIO_INSTALL_COMMANDLINE_TOOLS)
12-
install(DIRECTORY "${PROJECT_SOURCE_DIR}/src/opentimelineview"
13-
DESTINATION "${OTIO_RESOLVED_PYTHON_INSTALL_DIR}")
14-
endif()
12+
if(OTIO_INSTALL_COMMANDLINE_TOOLS)
13+
install(DIRECTORY "${PROJECT_SOURCE_DIR}/src/opentimelineview"
14+
DESTINATION "${OTIO_RESOLVED_PYTHON_INSTALL_DIR}")
15+
endif()
1516

16-
if(OTIO_INSTALL_CONTRIB)
17-
install(DIRECTORY "${PROJECT_SOURCE_DIR}/contrib/opentimelineio_contrib"
18-
DESTINATION "${OTIO_RESOLVED_PYTHON_INSTALL_DIR}"
19-
PATTERN "tests" EXCLUDE
20-
PATTERN "Makefile" EXCLUDE)
17+
if(OTIO_INSTALL_CONTRIB)
18+
install(DIRECTORY "${PROJECT_SOURCE_DIR}/contrib/opentimelineio_contrib"
19+
DESTINATION "${OTIO_RESOLVED_PYTHON_INSTALL_DIR}"
20+
PATTERN "tests" EXCLUDE
21+
PATTERN "Makefile" EXCLUDE)
22+
endif()
2123
endif()

src/py-opentimelineio/opentimelineio/plugins/manifest.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,9 +232,10 @@ def load_manifest():
232232

233233
# Read plugin manifests defined on the $OTIO_PLUGIN_MANIFEST_PATH
234234
# environment variable. This variable is an os.pathsep separated list of
235-
# file paths to manifest json files.
235+
# file paths to manifest json files. Can be set to "" to indicate no
236+
# local custom manifest path.
236237
_local_manifest_path = os.environ.get("OTIO_PLUGIN_MANIFEST_PATH", None)
237-
if _local_manifest_path is not None:
238+
if _local_manifest_path:
238239
for src_json_path in _local_manifest_path.split(os.pathsep):
239240
json_path = os.path.abspath(src_json_path)
240241
if (

0 commit comments

Comments
 (0)