From 3a424f33cd2e577b24b47ab04a47bfcdd81de013 Mon Sep 17 00:00:00 2001 From: erhe Date: Fri, 15 Mar 2024 15:59:26 +0100 Subject: [PATCH 01/15] remove six --- source/ftrack_api/_weakref.py | 66 --------------------------- source/ftrack_api/attribute.py | 7 ++- source/ftrack_api/cache.py | 29 +++--------- source/ftrack_api/collection.py | 7 ++- source/ftrack_api/entity/base.py | 5 +- source/ftrack_api/entity/location.py | 25 +++++----- source/ftrack_api/event/base.py | 4 +- source/ftrack_api/event/expression.py | 3 +- source/ftrack_api/event/hub.py | 8 ++-- source/ftrack_api/query.py | 4 +- source/ftrack_api/session.py | 19 +++----- 11 files changed, 40 insertions(+), 137 deletions(-) delete mode 100644 source/ftrack_api/_weakref.py diff --git a/source/ftrack_api/_weakref.py b/source/ftrack_api/_weakref.py deleted file mode 100644 index 69cc6f4b..00000000 --- a/source/ftrack_api/_weakref.py +++ /dev/null @@ -1,66 +0,0 @@ -""" -Yet another backport of WeakMethod for Python 2.7. -Changes include removing exception chaining and adding args to super() calls. - -Copyright (c) 2001-2019 Python Software Foundation.All rights reserved. - -Full license available in LICENSE.python. -""" -from weakref import ref - - -class WeakMethod(ref): - """ - A custom `weakref.ref` subclass which simulates a weak reference to - a bound method, working around the lifetime problem of bound methods. - """ - - __slots__ = "_func_ref", "_meth_type", "_alive", "__weakref__" - - def __new__(cls, meth, callback=None): - try: - obj = meth.__self__ - func = meth.__func__ - except AttributeError: - raise TypeError( - "argument should be a bound method, not {}".format(type(meth)) - ) - - def _cb(arg): - # The self-weakref trick is needed to avoid creating a reference - # cycle. - self = self_wr() - if self._alive: - self._alive = False - if callback is not None: - callback(self) - - self = ref.__new__(cls, obj, _cb) - self._func_ref = ref(func, _cb) - self._meth_type = type(meth) - self._alive = True - self_wr = ref(self) - return self - - def __call__(self): - obj = super(WeakMethod, self).__call__() - func = self._func_ref() - if obj is None or func is None: - return None - return self._meth_type(func, obj) - - def __eq__(self, other): - if isinstance(other, WeakMethod): - if not self._alive or not other._alive: - return self is other - return ref.__eq__(self, other) and self._func_ref == other._func_ref - return NotImplemented - - def __ne__(self, other): - if isinstance(other, WeakMethod): - if not self._alive or not other._alive: - return self is not other - return ref.__ne__(self, other) or self._func_ref != other._func_ref - return NotImplemented - - __hash__ = ref.__hash__ diff --git a/source/ftrack_api/attribute.py b/source/ftrack_api/attribute.py index 4a8fdbab..0a9b158e 100644 --- a/source/ftrack_api/attribute.py +++ b/source/ftrack_api/attribute.py @@ -4,8 +4,7 @@ from __future__ import absolute_import from builtins import object -import collections -from six.moves import collections_abc +import collections.abc import copy import logging import functools @@ -538,7 +537,7 @@ def _adapt_to_collection(self, entity, value): value, self.creator, self.key_attribute, self.value_attribute ) - elif isinstance(value, collections_abc.Mapping): + elif isinstance(value, collections.abc.Mapping): # Convert mapping. # TODO: When backend model improves, revisit this logic. # First get existing value and delete all references. This is @@ -612,7 +611,7 @@ def _adapt_to_collection(self, entity, value): value = ftrack_api.collection.CustomAttributeCollectionProxy(value) - elif isinstance(value, collections_abc.Mapping): + elif isinstance(value, collections.abc.Mapping): # Convert mapping. # TODO: When backend model improves, revisit this logic. # First get existing value and delete all references. This is diff --git a/source/ftrack_api/cache.py b/source/ftrack_api/cache.py index 2ea7ebe4..947530f0 100644 --- a/source/ftrack_api/cache.py +++ b/source/ftrack_api/cache.py @@ -16,36 +16,19 @@ """ from builtins import str -from six import string_types from builtins import object -from six.moves import collections_abc import functools import abc +import collections.abc import copy import inspect import re -try: - # Python 2.x - import anydbm -except ImportError: - import dbm as anydbm - - +import pickle import contextlib from future.utils import with_metaclass -try: - try: - import _pickle as pickle - except: - import six - from six.moves import cPickle as pickle -except: - try: - import cPickle as pickle - except: - import pickle +import dbm as anydbm import ftrack_api.inspection import ftrack_api.symbol @@ -454,11 +437,11 @@ def __key(self, item): # TODO: Consider using a more robust and comprehensive solution such as # dill (https://github.com/uqfoundation/dill). - if isinstance(item, collections_abc.Iterable): - if isinstance(item, string_types): + if isinstance(item, collections.abc.Iterable): + if isinstance(item, str): return pickle.dumps(item, pickle_protocol) - if isinstance(item, collections_abc.Mapping): + if isinstance(item, collections.abc.Mapping): contents = self.item_separator.join( [ ( diff --git a/source/ftrack_api/collection.py b/source/ftrack_api/collection.py index 1e77f906..173827b9 100644 --- a/source/ftrack_api/collection.py +++ b/source/ftrack_api/collection.py @@ -7,8 +7,7 @@ from builtins import str import logging -import collections -from six.moves import collections_abc +import collections.abc import copy import ftrack_api.exception @@ -19,7 +18,7 @@ from ftrack_api.logging import LazyLogMessage as L -class Collection(collections_abc.MutableSequence): +class Collection(collections.abc.MutableSequence): """A collection of entities.""" def __init__(self, entity, attribute, mutable=True, data=None): @@ -152,7 +151,7 @@ def __ne__(self, other): return not self == other -class MappedCollectionProxy(collections_abc.MutableMapping): +class MappedCollectionProxy(collections.abc.MutableMapping): """Common base class for mapped collection of entities.""" def __init__(self, collection): diff --git a/source/ftrack_api/entity/base.py b/source/ftrack_api/entity/base.py index cf8fa4b7..78b4b15b 100644 --- a/source/ftrack_api/entity/base.py +++ b/source/ftrack_api/entity/base.py @@ -5,8 +5,7 @@ from builtins import str import abc -import collections -from six.moves import collections_abc +import collections.abc import logging import ftrack_api.symbol @@ -40,7 +39,7 @@ def __repr__(self): class Entity( with_metaclass( - DynamicEntityTypeMetaclass, _EntityBase, collections_abc.MutableMapping + DynamicEntityTypeMetaclass, _EntityBase, collections.abc.MutableMapping ) ): """Base class for all entities.""" diff --git a/source/ftrack_api/entity/location.py b/source/ftrack_api/entity/location.py index 418e345b..322e7b33 100644 --- a/source/ftrack_api/entity/location.py +++ b/source/ftrack_api/entity/location.py @@ -2,10 +2,7 @@ # :copyright: Copyright (c) 2015 ftrack from builtins import zip -from six import string_types -from builtins import object -import collections -from six.moves import collections_abc +import collections.abc import functools import ftrack_api.entity.base @@ -21,7 +18,7 @@ MixinBaseClass = with_metaclass( ftrack_api.entity.base.DynamicEntityTypeMetaclass, ftrack_api.entity.base._EntityBase, - collections_abc.MutableMapping, + collections.abc.MutableMapping, ) @@ -129,8 +126,8 @@ def add_components(self, components, sources, recursive=True, _depth=0): issues and any transferred data under the 'transferred' detail key. """ - if isinstance(sources, string_types) or not isinstance( - sources, collections_abc.Sequence + if isinstance(sources, str) or not isinstance( + sources, collections.abc.Sequence ): sources = [sources] @@ -512,10 +509,10 @@ def get_resource_identifiers(self, components): # Optionally decode resource identifier. if self.resource_identifier_transformer: for index, resource_identifier in enumerate(resource_identifiers): - resource_identifiers[ - index - ] = self.resource_identifier_transformer.decode( - resource_identifier, context={"component": components[index]} + resource_identifiers[index] = ( + self.resource_identifier_transformer.decode( + resource_identifier, context={"component": components[index]} + ) ) return resource_identifiers @@ -544,9 +541,9 @@ def _get_resource_identifiers(self, components): resource_identifiers_map = {} for component_location in component_locations: - resource_identifiers_map[ - component_location["component_id"] - ] = component_location["resource_identifier"] + resource_identifiers_map[component_location["component_id"]] = ( + component_location["resource_identifier"] + ) resource_identifiers = [] missing = [] diff --git a/source/ftrack_api/event/base.py b/source/ftrack_api/event/base.py index 733b8ca1..fd37cd9e 100644 --- a/source/ftrack_api/event/base.py +++ b/source/ftrack_api/event/base.py @@ -3,10 +3,10 @@ from builtins import str import uuid -from six.moves import collections_abc +import collections.abc -class Event(collections_abc.MutableMapping): +class Event(collections.abc.MutableMapping): """Represent a single event.""" def __init__( diff --git a/source/ftrack_api/event/expression.py b/source/ftrack_api/event/expression.py index 05ca47bc..6c318ba6 100644 --- a/source/ftrack_api/event/expression.py +++ b/source/ftrack_api/event/expression.py @@ -2,7 +2,6 @@ # :copyright: Copyright (c) 2014 ftrack from builtins import map -from six import string_types from builtins import object from operator import eq, ne, ge, le, gt, lt @@ -266,7 +265,7 @@ def match(self, candidate): if ( self._operator is eq - and isinstance(self._value, string_types) + and isinstance(self._value, str) and self._value[-1] == self._wildcard ): return self._value[:-1] in value diff --git a/source/ftrack_api/event/hub.py b/source/ftrack_api/event/hub.py index 937452a9..f2f1b41c 100644 --- a/source/ftrack_api/event/hub.py +++ b/source/ftrack_api/event/hub.py @@ -6,8 +6,7 @@ from builtins import str from builtins import range from builtins import object -import collections -from six.moves import collections_abc +import collections.abc import urllib.parse import threading import queue as queue @@ -18,7 +17,6 @@ import functools import json import socket -import warnings import ssl import requests @@ -129,7 +127,7 @@ def __init__(self, server_url, api_user, api_key, headers=None, cookies=None): def _validate_mapping(mapping): """Validate mapping is a mapping type and return as dict.""" - if not isinstance(mapping, collections_abc.Mapping): + if not isinstance(mapping, collections.abc.Mapping): raise TypeError("Expected mapping, got {0!r}.".format(mapping)) return dict(mapping) @@ -1014,7 +1012,7 @@ def _handle_packet(self, code, packet_identifier, path, data): if len(args) == 1: event_payload = args[0] - if isinstance(event_payload, collections_abc.Mapping): + if isinstance(event_payload, collections.abc.Mapping): try: event = ftrack_api.event.base.Event(**event_payload) except Exception: diff --git a/source/ftrack_api/query.py b/source/ftrack_api/query.py index 62c7dd5b..2443cf08 100644 --- a/source/ftrack_api/query.py +++ b/source/ftrack_api/query.py @@ -2,12 +2,12 @@ # :copyright: Copyright (c) 2014 ftrack import re -from six.moves import collections_abc +import collections.abc import ftrack_api.exception -class QueryResult(collections_abc.Sequence): +class QueryResult(collections.abc.Sequence): """Results from a query.""" OFFSET_EXPRESSION = re.compile("(?Poffset (?P\d+))") diff --git a/source/ftrack_api/session.py b/source/ftrack_api/session.py index d8a4f69e..8884e5be 100644 --- a/source/ftrack_api/session.py +++ b/source/ftrack_api/session.py @@ -7,12 +7,10 @@ from builtins import zip from builtins import map from builtins import str -from six import string_types from builtins import object import json import logging -import collections -from six.moves import collections_abc +import collections.abc import datetime import os import getpass @@ -55,10 +53,7 @@ import ftrack_api.logging from ftrack_api.logging import LazyLogMessage as L -try: - from weakref import WeakMethod -except ImportError: - from ftrack_api._weakref import WeakMethod +from weakref import WeakMethod class SessionAuthentication(requests.auth.AuthBase): @@ -255,12 +250,12 @@ def __init__( self._request = requests.Session() if cookies: - if not isinstance(cookies, collections_abc.Mapping): + if not isinstance(cookies, collections.abc.Mapping): raise TypeError("The cookies argument is required to be a mapping.") self._request.cookies.update(cookies) if headers: - if not isinstance(headers, collections_abc.Mapping): + if not isinstance(headers, collections.abc.Mapping): raise TypeError("The headers argument is required to be a mapping.") headers = dict(headers) @@ -716,7 +711,7 @@ def ensure(self, entity_type, data, identifying_keys=None): for identifying_key in identifying_keys: value = data[identifying_key] - if isinstance(value, string_types): + if isinstance(value, str): value = '"{0}"'.format(value) elif isinstance(value, (arrow.Arrow, datetime.datetime, datetime.date)): @@ -1798,7 +1793,7 @@ def decode(self, string): def _decode(self, item): """Return *item* transformed into appropriate representation.""" - if isinstance(item, collections_abc.Mapping): + if isinstance(item, collections.abc.Mapping): if "__type__" in item: if item["__type__"] == "datetime": item = arrow.get(item["value"]) @@ -2408,7 +2403,7 @@ def __exit__(self, exception_type, exception_value, traceback): self._session.record_operations = self._current_record_operations -class OperationPayload(collections_abc.MutableMapping): +class OperationPayload(collections.abc.MutableMapping): """Represent operation payload.""" def __init__(self, *args, **kwargs): From f85cf816d486edbdbf0846efdc5b9c41b2fba150 Mon Sep 17 00:00:00 2001 From: erhe Date: Fri, 15 Mar 2024 16:00:35 +0100 Subject: [PATCH 02/15] remove six dependency. --- poetry.lock | 4 ++-- pyproject.toml | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/poetry.lock b/poetry.lock index 56c5a83f..d473c817 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.0 and should not be changed by hand. [[package]] name = "alabaster" @@ -1383,4 +1383,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "ec18327795c4d3eb920f561ce49fc6c8895601a0f7008dd6d6ef8f56714858d2" +content-hash = "12d641bdeb3f17d4156b44eb0c718a34757eb628fb551c820a8fb47dcdfbf848" diff --git a/pyproject.toml b/pyproject.toml index 56f75ba6..42f99bb9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,7 +35,6 @@ pyparsing = ">=2.0,<3" clique = "==1.6.1" websocket-client = ">=0.40.0,<1" future = ">=0.16.0,<1" -six = ">=1.13.0,<2" platformdirs = ">=4.0.0,<5" wheel = "^0.41.2" From d36d2f5c5c4ccba3fb2d6ef63f8fe5956d72bba7 Mon Sep 17 00:00:00 2001 From: erhe Date: Fri, 15 Mar 2024 16:04:31 +0100 Subject: [PATCH 03/15] remove python 2 version. --- source/ftrack_api/plugin.py | 96 +++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 52 deletions(-) diff --git a/source/ftrack_api/plugin.py b/source/ftrack_api/plugin.py index 2a28af7b..baab3823 100644 --- a/source/ftrack_api/plugin.py +++ b/source/ftrack_api/plugin.py @@ -9,64 +9,56 @@ import uuid import traceback -try: - from inspect import getfullargspec - -except ImportError: - # getargspec is deprecated in version 3.0. convert `ArgSpec` to a named - # tuple `FullArgSpec`. We only rely on the values of varargs and varkw. - - # Implemented with "https://github.com/tensorflow/tensorflow/blob/3d69fd003d4acef0ea5663a4794c1e9a4f6ec998/tensorflow/python/util/tf_inspect.py#L34" - # as reference. - import inspect - - FullArgSpec = collections.namedtuple( - "FullArgSpec", - [ - "args", - "varargs", - "varkw", - "defaults", - "kwonlyargs", - "kwonlydefaults", - "annotations", - ], +import importlib.util +import importlib.machinery + + +import inspect + +FullArgSpec = collections.namedtuple( + "FullArgSpec", + [ + "args", + "varargs", + "varkw", + "defaults", + "kwonlyargs", + "kwonlydefaults", + "annotations", + ], +) + + +def getfullargspec(func): + """a python 2 version of `getfullargspec`. getargspec is deprecated in version 3.0. convert `ArgSpec` + to a named tuple `FullArgSpec`. We only rely on the values of varargs and varkw. + + Implemented with "https://github.com/tensorflow/tensorflow/blob/3d69fd003d4acef0ea5663a4794c1e9a4f6ec998/tensorflow/python/util/tf_inspect.py#L34" + as reference.""" + spec = inspect.getargspec(func) + + return FullArgSpec( + args=spec.args, + varargs=spec.varargs, + varkw=spec.keywords, + defaults=spec.defaults, + kwonlyargs=[], + kwonlydefaults=None, + annotations={}, ) - def getfullargspec(func): - """a python 2 version of `getfullargspec`.""" - spec = inspect.getargspec(func) - return FullArgSpec( - args=spec.args, - varargs=spec.varargs, - varkw=spec.keywords, - defaults=spec.defaults, - kwonlyargs=[], - kwonlydefaults=None, - annotations={}, - ) +def load_source(modname, filename): + # https://docs.python.org/3/whatsnew/3.12.html#imp + loader = importlib.machinery.SourceFileLoader(modname, filename) + module = importlib.util.module_from_spec( + importlib.util.spec_from_file_location(modname, filename, loader=loader) + ) -try: - from imp import load_source - -except ImportError: - # The imp module is deprecated in version 3.12. Use importlib instead. - import importlib.util - import importlib.machinery - - def load_source(modname, filename): - # https://docs.python.org/3/whatsnew/3.12.html#imp - - loader = importlib.machinery.SourceFileLoader(modname, filename) - module = importlib.util.module_from_spec( - importlib.util.spec_from_file_location(modname, filename, loader=loader) - ) - - loader.exec_module(module) + loader.exec_module(module) - return module + return module def discover(paths, positional_arguments=None, keyword_arguments=None): From eeca56b6fd46a9096dc8a435366d41c8a1df36c5 Mon Sep 17 00:00:00 2001 From: erhe Date: Fri, 15 Mar 2024 16:10:29 +0100 Subject: [PATCH 04/15] metaclass update. --- source/ftrack_api/_version.py | 2 +- source/ftrack_api/accessor/base.py | 4 +--- source/ftrack_api/cache.py | 5 ++--- source/ftrack_api/data.py | 3 +-- source/ftrack_api/entity/base.py | 5 +---- source/ftrack_api/entity/location.py | 27 +++++++++++++++------------ source/ftrack_api/structure/base.py | 4 +--- 7 files changed, 22 insertions(+), 28 deletions(-) diff --git a/source/ftrack_api/_version.py b/source/ftrack_api/_version.py index 7668c0fb..6021d77c 100644 --- a/source/ftrack_api/_version.py +++ b/source/ftrack_api/_version.py @@ -1,2 +1,2 @@ # These version placeholders will be replaced later during substitution. -__version__ = "0.0.1.dev" +__version__ = "3.0.0rc1.post1.dev0+3a424f3" diff --git a/source/ftrack_api/accessor/base.py b/source/ftrack_api/accessor/base.py index 32085a67..50938191 100644 --- a/source/ftrack_api/accessor/base.py +++ b/source/ftrack_api/accessor/base.py @@ -1,14 +1,12 @@ # :coding: utf-8 # :copyright: Copyright (c) 2013 ftrack -from builtins import object import abc import ftrack_api.exception -from future.utils import with_metaclass -class Accessor(with_metaclass(abc.ABCMeta, object)): +class Accessor(metaclass=abc.ABCMeta): """Provide data access to a location. A location represents a specific storage, but access to that storage may diff --git a/source/ftrack_api/cache.py b/source/ftrack_api/cache.py index 947530f0..96ea85b9 100644 --- a/source/ftrack_api/cache.py +++ b/source/ftrack_api/cache.py @@ -26,7 +26,6 @@ import pickle import contextlib -from future.utils import with_metaclass import dbm as anydbm @@ -34,7 +33,7 @@ import ftrack_api.symbol -class Cache(with_metaclass(abc.ABCMeta, object)): +class Cache(metaclass=abc.ABCMeta): """Cache interface. Derive from this to define concrete cache implementations. A cache is @@ -361,7 +360,7 @@ def set(self, key, value): super(SerialisedCache, self).set(key, value) -class KeyMaker(with_metaclass(abc.ABCMeta, object)): +class KeyMaker(metaclass=abc.ABCMeta): """Generate unique keys.""" def __init__(self): diff --git a/source/ftrack_api/data.py b/source/ftrack_api/data.py index 2f9a3518..8d05d166 100644 --- a/source/ftrack_api/data.py +++ b/source/ftrack_api/data.py @@ -5,10 +5,9 @@ import os from abc import ABCMeta, abstractmethod import tempfile -from future.utils import with_metaclass -class Data(with_metaclass(ABCMeta, object)): +class Data(metaclass=ABCMeta): """File-like object for manipulating data.""" def __init__(self): diff --git a/source/ftrack_api/entity/base.py b/source/ftrack_api/entity/base.py index 78b4b15b..e0e4e9ee 100644 --- a/source/ftrack_api/entity/base.py +++ b/source/ftrack_api/entity/base.py @@ -14,7 +14,6 @@ import ftrack_api.exception import ftrack_api.operation from ftrack_api.logging import LazyLogMessage as L -from future.utils import with_metaclass class _EntityBase(object): @@ -38,9 +37,7 @@ def __repr__(self): class Entity( - with_metaclass( - DynamicEntityTypeMetaclass, _EntityBase, collections.abc.MutableMapping - ) + _EntityBase, collections.abc.MutableMapping, metaclass=DynamicEntityTypeMetaclass ): """Base class for all entities.""" diff --git a/source/ftrack_api/entity/location.py b/source/ftrack_api/entity/location.py index 322e7b33..42675879 100644 --- a/source/ftrack_api/entity/location.py +++ b/source/ftrack_api/entity/location.py @@ -12,15 +12,6 @@ import ftrack_api.inspection from ftrack_api.logging import LazyLogMessage as L -from future.utils import with_metaclass - - -MixinBaseClass = with_metaclass( - ftrack_api.entity.base.DynamicEntityTypeMetaclass, - ftrack_api.entity.base._EntityBase, - collections.abc.MutableMapping, -) - class Location(ftrack_api.entity.base.Entity): """Represent storage for components.""" @@ -587,7 +578,11 @@ def get_url(self, component): return self.accessor.get_url(resource_identifier) -class MemoryLocationMixin(MixinBaseClass): +class MemoryLocationMixin( + ftrack_api.entity.base._EntityBase, + collections.abc.MutableMapping, + metaclass=ftrack_api.entity.base.DynamicEntityTypeMetaclass, +): """Represent storage for components. Unlike a standard location, only store metadata for components in this @@ -649,7 +644,11 @@ def _get_resource_identifiers(self, components): return resource_identifiers -class UnmanagedLocationMixin(MixinBaseClass): +class UnmanagedLocationMixin( + ftrack_api.entity.base._EntityBase, + collections.abc.MutableMapping, + metaclass=ftrack_api.entity.base.DynamicEntityTypeMetaclass, +): """Location that does not manage data.""" def _add_data(self, component, resource_identifier, source): @@ -684,7 +683,11 @@ def _get_context(self, component, source): return context -class ServerLocationMixin(MixinBaseClass): +class ServerLocationMixin( + ftrack_api.entity.base._EntityBase, + collections.abc.MutableMapping, + metaclass=ftrack_api.entity.base.DynamicEntityTypeMetaclass, +): """Location representing ftrack server. Adds convenience methods to location, specific to ftrack server. diff --git a/source/ftrack_api/structure/base.py b/source/ftrack_api/structure/base.py index bf4a4a4f..266abd56 100644 --- a/source/ftrack_api/structure/base.py +++ b/source/ftrack_api/structure/base.py @@ -1,12 +1,10 @@ # :coding: utf-8 # :copyright: Copyright (c) 2014 ftrack -from builtins import object from abc import ABCMeta, abstractmethod -from future.utils import with_metaclass -class Structure(with_metaclass(ABCMeta, object)): +class Structure(metaclass=ABCMeta): """Structure plugin interface. A structure plugin should compute appropriate paths for data. From d3365f71a3364a294a6b7ee7f3debebb71d4500a Mon Sep 17 00:00:00 2001 From: erhe Date: Fri, 15 Mar 2024 16:11:54 +0100 Subject: [PATCH 05/15] replace string_types. --- source/ftrack_api/session.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/ftrack_api/session.py b/source/ftrack_api/session.py index 8884e5be..9ba02772 100644 --- a/source/ftrack_api/session.py +++ b/source/ftrack_api/session.py @@ -772,7 +772,7 @@ def get(self, entity_type, entity_key): self.logger.debug(L("Get {0} with key {1}", entity_type, entity_key)) primary_key_definition = self.types[entity_type].primary_key_attributes - if isinstance(entity_key, string_types): + if isinstance(entity_key, str): entity_key = [entity_key] if len(entity_key) != len(primary_key_definition): @@ -2195,7 +2195,7 @@ def encode_media(self, media, version_id=None, keep_original="auto"): is a FileComponent, and deleted if it is a file path. You can specify True or False to change this behavior. """ - if isinstance(media, string_types): + if isinstance(media, str): # Media is a path to a file. server_location = self.get("Location", ftrack_api.symbol.SERVER_LOCATION_ID) if keep_original == "auto": From fc5f409877d3cd09315d1771932845cdf341f760 Mon Sep 17 00:00:00 2001 From: erhe Date: Fri, 15 Mar 2024 16:14:47 +0100 Subject: [PATCH 06/15] bad convert. --- source/ftrack_api/plugin.py | 35 +---------------------------------- 1 file changed, 1 insertion(+), 34 deletions(-) diff --git a/source/ftrack_api/plugin.py b/source/ftrack_api/plugin.py index baab3823..6e05e8be 100644 --- a/source/ftrack_api/plugin.py +++ b/source/ftrack_api/plugin.py @@ -4,7 +4,6 @@ from __future__ import absolute_import import logging -import collections import os import uuid import traceback @@ -15,38 +14,6 @@ import inspect -FullArgSpec = collections.namedtuple( - "FullArgSpec", - [ - "args", - "varargs", - "varkw", - "defaults", - "kwonlyargs", - "kwonlydefaults", - "annotations", - ], -) - - -def getfullargspec(func): - """a python 2 version of `getfullargspec`. getargspec is deprecated in version 3.0. convert `ArgSpec` - to a named tuple `FullArgSpec`. We only rely on the values of varargs and varkw. - - Implemented with "https://github.com/tensorflow/tensorflow/blob/3d69fd003d4acef0ea5663a4794c1e9a4f6ec998/tensorflow/python/util/tf_inspect.py#L34" - as reference.""" - spec = inspect.getargspec(func) - - return FullArgSpec( - args=spec.args, - varargs=spec.varargs, - varkw=spec.keywords, - defaults=spec.defaults, - kwonlyargs=[], - kwonlydefaults=None, - annotations={}, - ) - def load_source(modname, filename): # https://docs.python.org/3/whatsnew/3.12.html#imp @@ -118,7 +85,7 @@ def discover(paths, positional_arguments=None, keyword_arguments=None): else: # Attempt to only pass arguments that are accepted by the # register function. - specification = getfullargspec(module.register) + specification = inspect.getfullargspec(module.register) selected_positional_arguments = positional_arguments selected_keyword_arguments = keyword_arguments From 9a831dab2879dc7c18fd7ce58e5ffe9af775f276 Mon Sep 17 00:00:00 2001 From: erhe Date: Fri, 15 Mar 2024 16:42:05 +0100 Subject: [PATCH 07/15] format. --- source/ftrack_api/formatter.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/source/ftrack_api/formatter.py b/source/ftrack_api/formatter.py index 85a36a6b..682af3b4 100644 --- a/source/ftrack_api/formatter.py +++ b/source/ftrack_api/formatter.py @@ -76,15 +76,17 @@ def format( formatters.setdefault( "header", - lambda text: "\x1b[1m\x1b[44m\x1b[97m{}\x1b[0m\033[0m".format(text) - if _can_do_colors() - else text, + lambda text: ( + "\x1b[1m\x1b[44m\x1b[97m{}\x1b[0m\033[0m".format(text) + if _can_do_colors() + else text + ), ) formatters.setdefault( "label", - lambda text: "\x1b[1m\x1b[34m{}\x1b[0m\033[0m".format(text) - if _can_do_colors() - else text, + lambda text: ( + "\x1b[1m\x1b[34m{}\x1b[0m\033[0m".format(text) if _can_do_colors() else text + ), ) # Determine indents. From 97000ce40939f03f60a0e7b9a8812dfe15d12e49 Mon Sep 17 00:00:00 2001 From: erhe Date: Fri, 15 Mar 2024 16:43:37 +0100 Subject: [PATCH 08/15] format location. --- source/ftrack_api/entity/location.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/source/ftrack_api/entity/location.py b/source/ftrack_api/entity/location.py index 42675879..3a575fb0 100644 --- a/source/ftrack_api/entity/location.py +++ b/source/ftrack_api/entity/location.py @@ -500,10 +500,10 @@ def get_resource_identifiers(self, components): # Optionally decode resource identifier. if self.resource_identifier_transformer: for index, resource_identifier in enumerate(resource_identifiers): - resource_identifiers[index] = ( - self.resource_identifier_transformer.decode( - resource_identifier, context={"component": components[index]} - ) + resource_identifiers[ + index + ] = self.resource_identifier_transformer.decode( + resource_identifier, context={"component": components[index]} ) return resource_identifiers @@ -532,9 +532,9 @@ def _get_resource_identifiers(self, components): resource_identifiers_map = {} for component_location in component_locations: - resource_identifiers_map[component_location["component_id"]] = ( - component_location["resource_identifier"] - ) + resource_identifiers_map[ + component_location["component_id"] + ] = component_location["resource_identifier"] resource_identifiers = [] missing = [] From b43b0e6b9e32067da379e5a27f78250ce2b8dcab Mon Sep 17 00:00:00 2001 From: erhe Date: Mon, 18 Mar 2024 09:09:06 +0100 Subject: [PATCH 09/15] limit workflow concurrency --- .github/workflows/cicd.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml index 76c86d5d..471d4bd1 100644 --- a/.github/workflows/cicd.yml +++ b/.github/workflows/cicd.yml @@ -9,6 +9,12 @@ on: pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + + jobs: check-formatting: runs-on: ubuntu-latest From 4a0d44b43472baca07c9feee26ea0acc45698648 Mon Sep 17 00:00:00 2001 From: erhe Date: Mon, 18 Mar 2024 10:37:50 +0100 Subject: [PATCH 10/15] wrong abc. --- source/ftrack_api/event/hub.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/ftrack_api/event/hub.py b/source/ftrack_api/event/hub.py index f2f1b41c..50d41b33 100644 --- a/source/ftrack_api/event/hub.py +++ b/source/ftrack_api/event/hub.py @@ -127,7 +127,7 @@ def __init__(self, server_url, api_user, api_key, headers=None, cookies=None): def _validate_mapping(mapping): """Validate mapping is a mapping type and return as dict.""" - if not isinstance(mapping, collections.abc.Mapping): + if not isinstance(mapping, collections_abc.Mapping): raise TypeError("Expected mapping, got {0!r}.".format(mapping)) return dict(mapping) @@ -1070,7 +1070,7 @@ def _decode(self, string): def _decode_object_hook(self, item): """Return *item* transformed.""" - if isinstance(item, collections_abc.Mapping): + if isinstance(item, collections.abc.Mapping): if "inReplyToEvent" in item: item["in_reply_to_event"] = item.pop("inReplyToEvent") From 354e8cb5b0397c4c107b1654340014163ffa54d9 Mon Sep 17 00:00:00 2001 From: erhe Date: Mon, 18 Mar 2024 10:38:29 +0100 Subject: [PATCH 11/15] replacement. --- source/ftrack_api/event/hub.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/ftrack_api/event/hub.py b/source/ftrack_api/event/hub.py index 50d41b33..4e870677 100644 --- a/source/ftrack_api/event/hub.py +++ b/source/ftrack_api/event/hub.py @@ -127,7 +127,7 @@ def __init__(self, server_url, api_user, api_key, headers=None, cookies=None): def _validate_mapping(mapping): """Validate mapping is a mapping type and return as dict.""" - if not isinstance(mapping, collections_abc.Mapping): + if not isinstance(mapping, collections.abc.Mapping): raise TypeError("Expected mapping, got {0!r}.".format(mapping)) return dict(mapping) From d39c5fbf9ecf4a1474b8631059dfdac2d7af66ed Mon Sep 17 00:00:00 2001 From: erhe Date: Mon, 18 Mar 2024 13:54:00 +0100 Subject: [PATCH 12/15] update lock. --- poetry.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 68d3a009..abde39a8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1495,4 +1495,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "2a80fcaa4615afd1da17d46d520b28cc6d0b54a6245ab4e34e4fa20904bc2d82" +content-hash = "9ad60cf82d221f5dec9dab8e151aec981fd38a0c8955812c27a80cad7bed9ceb" From 917293ca4c8fc54aedd349d15942523b1ac9aa78 Mon Sep 17 00:00:00 2001 From: erhe Date: Mon, 18 Mar 2024 18:46:19 +0100 Subject: [PATCH 13/15] revert changes to _version.py --- source/ftrack_api/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/ftrack_api/_version.py b/source/ftrack_api/_version.py index 6021d77c..7668c0fb 100644 --- a/source/ftrack_api/_version.py +++ b/source/ftrack_api/_version.py @@ -1,2 +1,2 @@ # These version placeholders will be replaced later during substitution. -__version__ = "3.0.0rc1.post1.dev0+3a424f3" +__version__ = "0.0.1.dev" From 3100d2adad797da5ad423984f9fc413f1c58e91e Mon Sep 17 00:00:00 2001 From: erhe Date: Fri, 22 Mar 2024 15:48:04 +0100 Subject: [PATCH 14/15] remove "future" dependency --- poetry.lock | 12 +----------- pyproject.toml | 1 - source/ftrack_api/entity/factory.py | 4 +--- source/ftrack_api/inspection.py | 3 +-- 4 files changed, 3 insertions(+), 17 deletions(-) diff --git a/poetry.lock b/poetry.lock index abde39a8..1f772823 100644 --- a/poetry.lock +++ b/poetry.lock @@ -431,16 +431,6 @@ files = [ {file = "flaky-3.7.0.tar.gz", hash = "sha256:3ad100780721a1911f57a165809b7ea265a7863305acb66708220820caf8aa0d"}, ] -[[package]] -name = "future" -version = "0.18.3" -description = "Clean single-source support for Python 3 and 2" -optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -files = [ - {file = "future-0.18.3.tar.gz", hash = "sha256:34a17436ed1e96697a86f9de3d15a3b0be01d8bc8de9c1dffd59fb8234ed5307"}, -] - [[package]] name = "identify" version = "2.5.35" @@ -1495,4 +1485,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "9ad60cf82d221f5dec9dab8e151aec981fd38a0c8955812c27a80cad7bed9ceb" +content-hash = "bbcd65bc4c3c6670b39d3442bdbdb98569b938ece98d62ecd3287a3e75fb5ee7" diff --git a/pyproject.toml b/pyproject.toml index 67fbc91e..b01b312a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,7 +32,6 @@ termcolor = ">=1.1.0,<2" pyparsing = ">=2.0,<3" clique = "==1.6.1" websocket-client = ">=0.40.0,<1" -future = ">=0.16.0,<1" platformdirs = ">=4.0.0,<5" wheel = "^0.41.2" diff --git a/source/ftrack_api/entity/factory.py b/source/ftrack_api/entity/factory.py index cda4f0d5..195ebd5d 100644 --- a/source/ftrack_api/entity/factory.py +++ b/source/ftrack_api/entity/factory.py @@ -151,10 +151,8 @@ def create(self, schema, bases=None): class_namespace["primary_key_attributes"] = schema["primary_key"][:] class_namespace["default_projections"] = default_projections - from future.utils import native_str - cls = type( - native_str(class_name), # type doesn't accept unicode. + str(class_name), # type doesn't accept unicode. tuple(class_bases), class_namespace, ) diff --git a/source/ftrack_api/inspection.py b/source/ftrack_api/inspection.py index a9cd8d1e..d1255c20 100644 --- a/source/ftrack_api/inspection.py +++ b/source/ftrack_api/inspection.py @@ -2,7 +2,6 @@ # :copyright: Copyright (c) 2015 ftrack from builtins import str -from future.utils import native_str import collections import ftrack_api.symbol @@ -32,7 +31,7 @@ def primary_key(entity): ) # todo: Compatiblity fix, review for better implementation. - primary_key[native_str(name)] = native_str(value) + primary_key[str(name)] = str(value) return primary_key From b6af7e58f91d2b659ef2d2ff03a4e92512acc2ea Mon Sep 17 00:00:00 2001 From: erhe Date: Fri, 22 Mar 2024 16:36:51 +0100 Subject: [PATCH 15/15] update failing test. --- test/unit/entity/test_user.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/unit/entity/test_user.py b/test/unit/entity/test_user.py index 9a3ab0c3..8e6d6c39 100644 --- a/test/unit/entity/test_user.py +++ b/test/unit/entity/test_user.py @@ -1,8 +1,6 @@ # :coding: utf-8 # :copyright: Copyright (c) 2016 ftrack -from past.builtins import long - def test_force_start_timer(new_user, task): """Successfully force starting a timer when another timer is running.""" @@ -31,7 +29,7 @@ def test_timer_creates_timelog(new_user, task, unique_name): assert timelog["name"] == unique_name assert timelog["comment"] == comment assert timelog["start"] == timer_start - assert isinstance(timelog["duration"], (int, long, float)) + assert isinstance(timelog["duration"], (int, float)) assert timelog["duration"] < 60