Skip to content

Commit

Permalink
Remove python2.7 support (#1423)
Browse files Browse the repository at this point in the history
* Sets VFX platform supported years as 2022, 2021, and 2020
* Removes Python2.7 support from the library
* Removes Python2.7 build matrix lines from CI/github actions
* updates setup.py project metadata to drop 2.7 from versions
* modernizes to python3 patterns by running pyupgrade --py37-plus

Signed-off-by: Stephan Steinbach <[email protected]>
Co-authored-by: ssteinbach <[email protected]>
Co-authored-by: Jean-Christophe Morin <[email protected]>
  • Loading branch information
3 people authored Sep 29, 2022
1 parent 238e64c commit 41ceb58
Show file tree
Hide file tree
Showing 91 changed files with 1,005 additions and 1,163 deletions.
21 changes: 1 addition & 20 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ['2.7', '3.7', '3.8', '3.9', '3.10']
python-version: ['3.7', '3.8', '3.9', '3.10']
include:
- { os: ubuntu-latest, shell: bash }
- { os: macos-latest, shell: bash }
Expand Down Expand Up @@ -130,9 +130,6 @@ jobs:
- name: Install python build dependencies
run: |
python -m pip install --upgrade pip setuptools wheel "flake8>=3.5" check-manifest
- name: install mock for python 2.7 tests only
if: matrix.python-version == 2.7
run: python -m pip install --upgrade mock
- name: Run check-manifest and lint check
run: make ci-prebuild
- name: Build and Install
Expand Down Expand Up @@ -172,22 +169,6 @@ jobs:
# by CMake. CMake is able to find the right toolchain, thanks to
# the -A argument that we specify in the setup.py to set the
# target platform (x86, x64, etc).
- name: Set Windows Python 2.7 environment variables
if: matrix.python-build == 'cp27*' && runner.os == 'Windows'
shell: bash
run: |
echo "DISTUTILS_USE_SDK=1" >> $GITHUB_ENV
echo "MSSdk=1" >> $GITHUB_ENV
- name: Build wheels (Python 2.7)
if: matrix.python-build == 'cp27*'
# cibuildwheel 1.12.0 is the last release that supported Python 2.7.
uses: pypa/[email protected]
with:
output-dir: wheelhouse
env:
CIBW_BUILD: ${{ matrix.python-build }}

- name: Build wheels (Python 3)
uses: pypa/[email protected]
if: matrix.python-build != 'cp27*'
Expand Down
12 changes: 0 additions & 12 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -114,18 +114,6 @@ else()
# Note that this has no effect on Windows.
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)

if(MSVC AND Python_VERSION_MAJOR VERSION_LESS 3)
# Statically link run-time library (vcruntime and msvcp)
# See https://docs.microsoft.com/en-us/cpp/build/reference/md-mt-ld-use-run-time-library?view=msvc-160
# This allows us to compile OTIO bindings with a newer MSVC version
# than the one used by the interpreter where OTIO will be installed.
# This is only required for Python < 3 because only these are
# compiled with an older compiler (9.0). CPython 3.5+ uses at least
# Visual C++ 14.X.
# See https://wiki.python.org/moin/WindowsCompilers#Which_Microsoft_Visual_C.2B-.2B-_compiler_to_use_with_a_specific_Python_version_.3F
add_compile_options(/MT)
endif()
endif()
endif()

Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ OpenTimelineIO
[![OpenTimelineIO](docs/_static/[email protected])](http://opentimeline.io)
==============

[![Supported VFX Platform Versions](https://img.shields.io/badge/vfx%20platform-2019--2022-lightgrey.svg)](http://www.vfxplatform.com/)
![Supported Versions](https://img.shields.io/badge/python-2.7%2C%203.7%2C%203.8%2C%203.9%2C%203.10-blue)
[![Supported VFX Platform Versions](https://img.shields.io/badge/vfx%20platform-2020--2023-lightgrey.svg)](http://www.vfxplatform.com/)
![Supported Versions](https://img.shields.io/badge/python-3.7%2C%203.8%2C%203.9%2C%203.10-blue)
[![Build Status](https://github.com/AcademySoftwareFoundation/OpenTimelineIO/actions/workflows/python-package.yml/badge.svg)](https://github.com/AcademySoftwareFoundation/OpenTimelineIO/actions/workflows/python-package.yml)
[![codecov](https://codecov.io/gh/AcademySoftwareFoundation/OpenTimelineIO/branch/main/graph/badge.svg)](https://codecov.io/gh/AcademySoftwareFoundation/OpenTimelineIO)
[![docs](https://readthedocs.org/projects/opentimelineio/badge/?version=latest)](https://opentimelineio.readthedocs.io/en/latest/index.html)
Expand Down Expand Up @@ -54,8 +54,8 @@ Documentation, including quick start, architecture, use cases, API docs, and muc
Supported VFX Platforms
-----------------
The current release supports:
- VFX platform 2022, 2021, 2020, 2019
- Python 2.7 - 3.10
- VFX platform 2023, 2022, 2021, 2020
- Python 3.7 - 3.10

For more information on our vfxplatform support policy: [Contribution Guidelines Documentation Page](https://opentimelineio.readthedocs.io/en/latest/tutorials/contributing.html)
For more information on the vfxplatform: [VFX Platform Homepage](https://vfxplatform.com)
Expand Down Expand Up @@ -155,8 +155,8 @@ You can also install the PySide2 dependency with `python -m pip install .[view]`

You may need to escape the `[` depending on your shell, `\[view\]` .

Currently the code base is written against python 2.7, 3.7, 3.8 and 3.9,
in keeping with the pep8 style. We ask that before developers submit pull
Currently the code base is written against python 3.7, 3.8, 3.9, and 3.10, in
keeping with the pep8 style. We ask that before developers submit pull
request, they:

- run `make test` -- to ensure that none of the unit tests were broken
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class AAFValidationError(AAFAdapterError):
pass


class AAFFileTranscriber(object):
class AAFFileTranscriber:
"""
AAFFileTranscriber
Expand Down Expand Up @@ -137,7 +137,7 @@ def track_transcriber(self, otio_track):
transcriber = AudioTrackTranscriber(self, otio_track)
else:
raise otio.exceptions.NotSupportedError(
"Unsupported track kind: {}".format(otio_track.kind))
f"Unsupported track kind: {otio_track.kind}")
return transcriber


Expand Down Expand Up @@ -236,7 +236,7 @@ def _generate_empty_mobid(clip):
clip_mob_ids[otio_clip] = mob_id
break
else:
raise AAFAdapterError("Cannot find mob ID for clip {}".format(otio_clip))
raise AAFAdapterError(f"Cannot find mob ID for clip {otio_clip}")

return clip_mob_ids

Expand All @@ -260,7 +260,7 @@ def _stackify_nested_groups(timeline):
return copied


class _TrackTranscriber(object):
class _TrackTranscriber:
"""
_TrackTranscriber is the base class for the conversion of a given otio track.
Expand Down Expand Up @@ -305,7 +305,7 @@ def transcribe(self, otio_child):
return operation_group
else:
raise otio.exceptions.NotSupportedError(
"Unsupported otio child type: {}".format(type(otio_child)))
f"Unsupported otio child type: {type(otio_child)}")

@property
@abc.abstractmethod
Expand Down Expand Up @@ -662,11 +662,11 @@ def aaf_sourceclip(self, otio_clip):
length = int(otio_clip.duration().value)
c1 = self.aaf_file.create.ControlPoint()
c1["ControlPointSource"].value = 2
c1["Time"].value = aaf2.rational.AAFRational("0/{}".format(length))
c1["Time"].value = aaf2.rational.AAFRational(f"0/{length}")
c1["Value"].value = 0
c2 = self.aaf_file.create.ControlPoint()
c2["ControlPointSource"].value = 2
c2["Time"].value = aaf2.rational.AAFRational("{}/{}".format(length - 1, length))
c2["Time"].value = aaf2.rational.AAFRational(f"{length - 1}/{length}")
c2["Value"].value = 0
varying_value = self.aaf_file.create.VaryingValue()
varying_value.parameterdef = param_def
Expand All @@ -675,7 +675,7 @@ def aaf_sourceclip(self, otio_clip):
opgroup = self.timeline_mobslot.segment
opgroup.parameters.append(varying_value)

return super(AudioTrackTranscriber, self).aaf_sourceclip(otio_clip)
return super().aaf_sourceclip(otio_clip)

def _create_timeline_mobslot(self):
"""
Expand Down Expand Up @@ -738,7 +738,7 @@ def _transition_parameters(self):
return [param_def_level], level


class __check(object):
class __check:
"""
__check is a private helper class that safely gets values given to check
for existence and equality
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,7 @@
import os
import sys

try:
# Python 2
text_type = unicode
except NameError:
# Python 3
text_type = str

try:
# Python 3.3+
import collections.abc as collections_abc
except ImportError:
import collections as collections_abc
import collections
import fractions
import opentimelineio as otio

Expand Down Expand Up @@ -66,7 +55,7 @@ class AAFAdapterError(otio.exceptions.OTIOError):


def _get_parameter(item, parameter_name):
values = dict((value.name, value) for value in item.parameters.value)
values = {value.name: value for value in item.parameters.value}
return values.get(parameter_name)


Expand Down Expand Up @@ -99,9 +88,7 @@ def _get_class_name(item):


def _transcribe_property(prop, owner=None):
# XXX: The unicode type doesn't exist in Python 3 (all strings are unicode)
# so we have to use type(u"") which works in both Python 2 and 3.
if isinstance(prop, (str, type(u""), numbers.Integral, float, dict)):
if isinstance(prop, (str, numbers.Integral, float, dict)):
return prop
elif isinstance(prop, set):
return list(prop)
Expand Down Expand Up @@ -371,7 +358,7 @@ def _extract_timecode_info(mob):
def _add_child(parent, child, source):
if child is None:
if debug:
print("Adding null child? {}".format(source))
print(f"Adding null child? {source}")
elif isinstance(child, otio.schema.Marker):
parent.markers.append(child)
else:
Expand Down Expand Up @@ -409,7 +396,7 @@ def _transcribe(item, parents, edit_rate, indent=0):
# complex than OTIO.

if isinstance(item, aaf2.content.ContentStorage):
msg = "Creating SerializableCollection for {}".format(_encoded_name(item))
msg = f"Creating SerializableCollection for {_encoded_name(item)}"
_transcribe_log(msg, indent)
result = otio.schema.SerializableCollection()

Expand All @@ -419,7 +406,7 @@ def _transcribe(item, parents, edit_rate, indent=0):
_add_child(result, child, mob)

elif isinstance(item, aaf2.mobs.Mob):
_transcribe_log("Creating Timeline for {}".format(_encoded_name(item)), indent)
_transcribe_log(f"Creating Timeline for {_encoded_name(item)}", indent)
result = otio.schema.Timeline()

for slot in item.slots:
Expand All @@ -442,7 +429,7 @@ def _transcribe(item, parents, edit_rate, indent=0):
_encoded_name(item), clipUsage
)
else:
itemMsg = "Creating SourceClip for {}".format(_encoded_name(item))
itemMsg = f"Creating SourceClip for {_encoded_name(item)}"

_transcribe_log(itemMsg, indent)
result = otio.schema.Clip()
Expand Down Expand Up @@ -599,7 +586,7 @@ def _transcribe(item, parents, edit_rate, indent=0):
result.out_offset = otio.opentime.RationalTime(out_offset, edit_rate)

elif isinstance(item, aaf2.components.Filler):
_transcribe_log("Creating Gap for {}".format(_encoded_name(item)), indent)
_transcribe_log(f"Creating Gap for {_encoded_name(item)}", indent)
result = otio.schema.Gap()

length = item.length
Expand All @@ -609,7 +596,7 @@ def _transcribe(item, parents, edit_rate, indent=0):
)

elif isinstance(item, aaf2.components.NestedScope):
msg = "Creating Stack for NestedScope for {}".format(_encoded_name(item))
msg = f"Creating Stack for NestedScope for {_encoded_name(item)}"
_transcribe_log(msg, indent)
# TODO: Is this the right class?
result = otio.schema.Stack()
Expand All @@ -619,7 +606,7 @@ def _transcribe(item, parents, edit_rate, indent=0):
_add_child(result, child, slot)

elif isinstance(item, aaf2.components.Sequence):
msg = "Creating Track for Sequence for {}".format(_encoded_name(item))
msg = f"Creating Track for Sequence for {_encoded_name(item)}"
_transcribe_log(msg, indent)
result = otio.schema.Track()

Expand All @@ -639,13 +626,13 @@ def _transcribe(item, parents, edit_rate, indent=0):
_add_child(result, child, component)

elif isinstance(item, aaf2.components.OperationGroup):
msg = "Creating operationGroup for {}".format(_encoded_name(item))
msg = f"Creating operationGroup for {_encoded_name(item)}"
_transcribe_log(msg, indent)
result = _transcribe_operation_group(item, parents, metadata,
edit_rate, indent + 2)

elif isinstance(item, aaf2.mobslots.TimelineMobSlot):
msg = "Creating Track for TimelineMobSlot for {}".format(_encoded_name(item))
msg = f"Creating Track for TimelineMobSlot for {_encoded_name(item)}"
_transcribe_log(msg, indent)
result = otio.schema.Track()

Expand All @@ -654,7 +641,7 @@ def _transcribe(item, parents, edit_rate, indent=0):
_add_child(result, child, item.segment)

elif isinstance(item, aaf2.mobslots.MobSlot):
msg = "Creating Track for MobSlot for {}".format(_encoded_name(item))
msg = f"Creating Track for MobSlot for {_encoded_name(item)}"
_transcribe_log(msg, indent)
result = otio.schema.Track()

Expand All @@ -671,7 +658,7 @@ def _transcribe(item, parents, edit_rate, indent=0):
pass

elif isinstance(item, aaf2.components.ScopeReference):
msg = "Creating Gap for ScopedReference for {}".format(_encoded_name(item))
msg = f"Creating Gap for ScopedReference for {_encoded_name(item)}"
_transcribe_log(msg, indent)
# TODO: is this like FILLER?

Expand All @@ -687,7 +674,7 @@ def _transcribe(item, parents, edit_rate, indent=0):
event_mobs = [p for p in parents if isinstance(p, aaf2.mobslots.EventMobSlot)]
if event_mobs:
_transcribe_log(
"Create marker for '{}'".format(_encoded_name(item)), indent
f"Create marker for '{_encoded_name(item)}'", indent
)

result = otio.schema.Marker()
Expand Down Expand Up @@ -731,7 +718,7 @@ def _transcribe(item, parents, edit_rate, indent=0):
)

elif isinstance(item, aaf2.components.Selector):
msg = "Transcribe selector for {}".format(_encoded_name(item))
msg = f"Transcribe selector for {_encoded_name(item)}"
_transcribe_log(msg, indent)

selected = item.getvalue('Selected')
Expand Down Expand Up @@ -766,7 +753,7 @@ def _transcribe(item, parents, edit_rate, indent=0):
# Perform a check here to make sure no potential Gap objects
# are slipping through the cracks
if isinstance(result, otio.schema.Gap):
err = "AAF Selector parsing error: {}".format(type(item))
err = f"AAF Selector parsing error: {type(item)}"
raise AAFAdapterError(err)

# A Selector can have a set of alternates to handle multiple options for an
Expand Down Expand Up @@ -824,7 +811,7 @@ def _transcribe(item, parents, edit_rate, indent=0):
# elif isinstance(item, pyaaf.AxProperty):
# self.properties['Value'] = str(item.GetValue())

elif isinstance(item, collections_abc.Iterable):
elif isinstance(item, collections.abc.Iterable):
msg = "Creating SerializableCollection for Iterable for {}".format(
_encoded_name(item))
_transcribe_log(msg, indent)
Expand All @@ -836,7 +823,7 @@ def _transcribe(item, parents, edit_rate, indent=0):
# For everything else, we just ignore it.
# To see what is being ignored, turn on the debug flag
if debug:
print("SKIPPING: {}: {} -- {}".format(type(item), item, result))
print(f"SKIPPING: {type(item)}: {item} -- {result}")

# Did we get anything? If not, we're done
if result is None:
Expand Down Expand Up @@ -911,7 +898,7 @@ def _find_timecode_track_start(track):
start = aaf_metadata["Segment"]["Start"]
except KeyError as e:
raise AAFAdapterError(
"Timecode missing '{}'".format(e)
f"Timecode missing '{e}'"
)

if edit_rate.denominator == 1:
Expand Down
6 changes: 3 additions & 3 deletions contrib/opentimelineio_contrib/adapters/ale.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def _parse_data_line(line, columns, fps, ale_name_column_key='Name'):
try:
start = otio.opentime.from_timecode(value, fps)
except (ValueError, TypeError):
raise ALEParseError("Invalid Start timecode: {}".format(value))
raise ALEParseError(f"Invalid Start timecode: {value}")
duration = None
end = None
if metadata.get("Duration", "") != "":
Expand Down Expand Up @@ -137,7 +137,7 @@ def _parse_data_line(line, columns, fps, ale_name_column_key='Name'):

def _cdl_values_from_metadata(asc_sop_string):

if not isinstance(asc_sop_string, (type(''), type(u''))):
if not isinstance(asc_sop_string, str):
return {}

asc_sop_values = ASC_SOP_REGEX.findall(asc_sop_string)
Expand Down Expand Up @@ -285,7 +285,7 @@ def write_to_string(input_otio, columns=None, fps=None, video_format=None):
headers = list(header.items())
headers.sort() # make the output predictable
for key, val in headers:
result += "{}\t{}\n".format(key, val)
result += f"{key}\t{val}\n"

# If the caller passed in a list of columns, use that, otherwise
# we need to discover the columns that should be output.
Expand Down
Loading

0 comments on commit 41ceb58

Please sign in to comment.