Skip to content

Commit 509eca8

Browse files
SG-32657 Enable support for Python 3.10 in CI (#920)
- Support [deprecation](https://peps.python.org/pep-0632/) of distutils for setuptools > 60. - We can't switch to `packaging.version.parse` because many TK components depend of `distutils.version.LooseVersion`. To handle the distutils deprecation, we're switching to the bundled version living on setuptools >= 60. The deprecation warning is still there, so we're suppressing just this one. - Re-enable commented tests - Support [deprecation](python/cpython#25174) of `isSet()` - Upgrade python-api v3.4.0
1 parent 6766e56 commit 509eca8

File tree

20 files changed

+3298
-174
lines changed

20 files changed

+3298
-174
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
[![VFX Platform](https://img.shields.io/badge/vfxplatform-2020-yellow.svg)](http://www.vfxplatform.com/)
2-
[![Python 2.7 3.7](https://img.shields.io/badge/python-2.7%20%7C%203.7-blue.svg)](https://www.python.org/)
1+
[![VFX Platform](https://img.shields.io/badge/vfxplatform-2023%202022%202021%202020-blue.svg)](http://www.vfxplatform.com/)
2+
[![Python 3.7 3.9 3.10](https://img.shields.io/badge/python-3.7%20%7C%203.9%20%7C%203.10-blue.svg)](https://www.python.org/)
33
[![Reference Documentation](http://img.shields.io/badge/doc-reference-blue.svg)](http://developer.shotgridsoftware.com/tk-core)
44
[![Build Status](https://dev.azure.com/shotgun-ecosystem/Toolkit/_apis/build/status/shotgunsoftware.tk-core?branchName=master)](https://dev.azure.com/shotgun-ecosystem/Toolkit/_build/latest?definitionId=38&branchName=master)
55
[![codecov](https://codecov.io/gh/shotgunsoftware/tk-core/branch/master/graph/badge.svg)](https://codecov.io/gh/shotgunsoftware/tk-core)

python/tank/util/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
is_version_newer,
2323
is_version_older_or_equal,
2424
is_version_newer_or_equal,
25+
suppress_known_deprecation,
2526
)
2627

2728
from .shotgun_entity import get_sg_entity_name_field

python/tank/util/metrics.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,7 @@ def run(self):
424424
)
425425

426426
# Run until halted
427-
while not self._halt_event.isSet():
427+
while not self._halt_event.is_set():
428428

429429
# get the next available metric and dispatch it
430430
try:

python/tank/util/version.py

Lines changed: 56 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,19 @@
77
# By accessing, using, copying or modifying this work you indicate your
88
# agreement to the Shotgun Pipeline Toolkit Source Code License. All rights
99
# not expressly granted therein are reserved by Shotgun Software Inc.
10+
import warnings
11+
import contextlib
12+
import sys
13+
14+
if sys.version_info[0:2] >= (3, 10):
15+
from setuptools._distutils.version import LooseVersion
16+
else:
17+
from distutils.version import LooseVersion
1018

11-
from distutils.version import LooseVersion
1219
from . import sgre as re
1320
from ..errors import TankError
1421

22+
1523
GITHUB_HASH_RE = re.compile("^[0-9a-fA-F]{7,40}$")
1624

1725

@@ -115,6 +123,20 @@ def is_version_number(version):
115123
return False
116124

117125

126+
@contextlib.contextmanager
127+
def suppress_known_deprecation():
128+
"""
129+
Imported function from setuptools.distutils module
130+
"""
131+
with warnings.catch_warnings(record=True) as ctx:
132+
warnings.filterwarnings(
133+
action="default",
134+
category=DeprecationWarning,
135+
message="distutils Version classes are deprecated.",
136+
)
137+
yield ctx
138+
139+
118140
def _compare_versions(a, b):
119141
"""
120142
Tests if version a is newer than version b.
@@ -124,8 +146,8 @@ def _compare_versions(a, b):
124146
125147
:rtype: bool
126148
"""
127-
if b is None:
128-
# a is always newer than None
149+
if b in [None, "Undefined"]:
150+
# a is always newer than None or `Undefined`
129151
return True
130152

131153
if _is_git_commit(a) and not _is_git_commit(b):
@@ -157,37 +179,40 @@ def _compare_versions(a, b):
157179
# First, try to use LooseVersion for comparison. This should work in
158180
# most cases.
159181
try:
160-
version_a = LooseVersion(a).version
161-
version_b = LooseVersion(b).version
162-
version_num_a = []
163-
version_num_b = []
164-
# taking only the integers of the version to make comparison
165-
for version in version_a:
166-
if isinstance(version, (int)):
167-
version_num_a.append(version)
168-
elif version == "-":
169-
break
170-
for version in version_b:
171-
if isinstance(version, (int)):
172-
version_num_b.append(version)
173-
elif version == "-":
174-
break
175-
176-
# Comparing equal number versions with with one of them with '-' appended, if a version
177-
# has '-' appended it's older than the same version with '-' at the end
178-
if version_num_a == version_num_b:
179-
if "-" in a and "-" not in b:
180-
return False # False, version a is older than b
181-
elif "-" in b and "-" not in a:
182-
return True # True, version a is older than b
182+
with suppress_known_deprecation():
183+
# Supress `distutils Version classes are deprecated.` for Python 3.10
184+
version_a = LooseVersion(a).version
185+
version_b = LooseVersion(b).version
186+
187+
version_num_a = []
188+
version_num_b = []
189+
# taking only the integers of the version to make comparison
190+
for version in version_a:
191+
if isinstance(version, (int)):
192+
version_num_a.append(version)
193+
elif version == "-":
194+
break
195+
for version in version_b:
196+
if isinstance(version, (int)):
197+
version_num_b.append(version)
198+
elif version == "-":
199+
break
200+
201+
# Comparing equal number versions with with one of them with '-' appended, if a version
202+
# has '-' appended it's older than the same version with '-' at the end
203+
if version_num_a == version_num_b:
204+
if "-" in a and "-" not in b:
205+
return False # False, version a is older than b
206+
elif "-" in b and "-" not in a:
207+
return True # True, version a is older than b
208+
else:
209+
return LooseVersion(a) > LooseVersion(
210+
b
211+
) # If both has '-' compare '-rcx' versions
183212
else:
184213
return LooseVersion(a) > LooseVersion(
185214
b
186-
) # If both has '-' compare '-rcx' versions
187-
else:
188-
return LooseVersion(a) > LooseVersion(
189-
b
190-
) # If they are different numeric versions
215+
) # If they are different numeric versions
191216
except TypeError:
192217
# To mimick the behavior in Python 2.7 as closely as possible, we will
193218
# If LooseVersion comparison didn't work, try to extract a numeric
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1f132f8f495333acc7303996a8151d73b2c204ae
1+
11db780c4a18993130a988d73f9e50bd7d17e53f
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import base64
2+
import re
3+
4+
from ... import pyparsing as pp
5+
6+
from .error import *
7+
8+
9+
try: # pyparsing>=3.0.0
10+
downcaseTokens = pp.common.downcaseTokens
11+
except AttributeError:
12+
downcaseTokens = pp.downcaseTokens
13+
14+
UNQUOTE_PAIRS = re.compile(r"\\(.)")
15+
unquote = lambda s, l, t: UNQUOTE_PAIRS.sub(r"\1", t[0][1:-1])
16+
17+
# https://tools.ietf.org/html/rfc7235#section-1.2
18+
# https://tools.ietf.org/html/rfc7235#appendix-B
19+
tchar = "!#$%&'*+-.^_`|~" + pp.nums + pp.alphas
20+
token = pp.Word(tchar).setName("token")
21+
token68 = pp.Combine(pp.Word("-._~+/" + pp.nums + pp.alphas) + pp.Optional(pp.Word("=").leaveWhitespace())).setName(
22+
"token68"
23+
)
24+
25+
quoted_string = pp.dblQuotedString.copy().setName("quoted-string").setParseAction(unquote)
26+
auth_param_name = token.copy().setName("auth-param-name").addParseAction(downcaseTokens)
27+
auth_param = auth_param_name + pp.Suppress("=") + (quoted_string | token)
28+
params = pp.Dict(pp.delimitedList(pp.Group(auth_param)))
29+
30+
scheme = token("scheme")
31+
challenge = scheme + (params("params") | token68("token"))
32+
33+
authentication_info = params.copy()
34+
www_authenticate = pp.delimitedList(pp.Group(challenge))
35+
36+
37+
def _parse_authentication_info(headers, headername="authentication-info"):
38+
"""https://tools.ietf.org/html/rfc7615
39+
"""
40+
header = headers.get(headername, "").strip()
41+
if not header:
42+
return {}
43+
try:
44+
parsed = authentication_info.parseString(header)
45+
except pp.ParseException as ex:
46+
# print(ex.explain(ex))
47+
raise MalformedHeader(headername)
48+
49+
return parsed.asDict()
50+
51+
52+
def _parse_www_authenticate(headers, headername="www-authenticate"):
53+
"""Returns a dictionary of dictionaries, one dict per auth_scheme."""
54+
header = headers.get(headername, "").strip()
55+
if not header:
56+
return {}
57+
try:
58+
parsed = www_authenticate.parseString(header)
59+
except pp.ParseException as ex:
60+
# print(ex.explain(ex))
61+
raise MalformedHeader(headername)
62+
63+
retval = {
64+
challenge["scheme"].lower(): challenge["params"].asDict()
65+
if "params" in challenge
66+
else {"token": challenge.get("token")}
67+
for challenge in parsed
68+
}
69+
return retval

0 commit comments

Comments
 (0)