Skip to content

Commit fb67656

Browse files
Bump tk-core to v0.23.5 (#147)
1 parent 42bf294 commit fb67656

File tree

23 files changed

+1292
-422
lines changed

23 files changed

+1292
-422
lines changed

python/tk-core/commit_id

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
16655ba7b0141d457135ed870eee7fc0d5a04076
1+
62d128a8a3e06fe37cc9de5c6a699415c6b51c70

python/tk-core/info.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# This is automatically replaced with appropriate values
1313
# as the core bundle is uploaded to the app store.
1414

15-
version: "v0.23.2"
15+
version: "v0.23.5"
1616
documentation_url: "https://help.autodesk.com/view/SGDEV/ENU/?contextId=SA_INTEGRATIONS_USER_GUIDE"
1717
requires_shotgun_version: "v5.0.0"
1818

python/tk-core/python/tank/__init__.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,30 @@
3636
import warnings
3737

3838
if sys.version_info < (3, 7):
39-
raise Exception("This module requires Python version 3.7 or higher.")
39+
if os.environ.get("SHOTGUN_ALLOW_OLD_PYTHON", "0") != "1":
40+
# This is our preferred default behavior when using an old
41+
# unsupported Python version.
42+
# This way, we can control where the exception is raised, and it provides a
43+
# comprehensive error message rather than having users facing a random
44+
# Python traceback and trying to understand this is due to using an
45+
# unsupported Python version.
46+
47+
raise RuntimeError("This module requires Python version 3.7 or higher.")
48+
49+
warnings.warn(
50+
"Python versions older than 3.7 are no longer supported as of January "
51+
"2023. Since the SHOTGUN_ALLOW_OLD_PYTHON variable is enabled, this "
52+
"module is raising a warning instead of an exception. "
53+
"However, it is very likely that this module will not be able to work "
54+
"on this Python version.",
55+
RuntimeWarning,
56+
stacklevel=2,
57+
)
4058
elif sys.version_info < (3, 9):
4159
warnings.warn(
42-
"Python versions older than 3.9 are no longer supported since 2025-03 "
43-
"and compatibility will be removed at any time after 2026-01. "
44-
"Please update to Python 3.9 or a newer supported version.",
60+
"Python versions older than 3.9 are no longer supported as of March "
61+
"2025 and compatibility will be discontinued after March 2026. "
62+
"Please update to Python 3.11 or any other supported version.",
4563
DeprecationWarning,
4664
stacklevel=2
4765
)

python/tk-core/python/tank/authentication/sso_saml2/core/__init__.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,23 +43,23 @@ def __getattr__(name):
4343
if is_import:
4444
raise
4545

46+
deprecation_message = (
47+
f"Accessing '{__name__}.{name}' directly without explicit import "
48+
"is deprecated and compatibility will be discontinued after "
49+
f"September 2026. Explicitly import '{__name__}.{name}' instead."
50+
)
51+
4652
import warnings
4753
warnings.warn(
48-
f"Accessing '{__name__}.{name}' directly without explicit import "
49-
"is deprecated and will be removed at any time after 2026-07. "
50-
f"Explicitly import '{__name__}.{name}' instead.",
54+
deprecation_message,
5155
DeprecationWarning,
5256
stacklevel=2,
5357
)
5458

5559
try:
5660
import tank
5761
logger = tank.LogManager.get_logger(__name__)
58-
logger.warning(
59-
f"Accessing '{__name__}.{name}' directly without explicit import "
60-
"is deprecated and will be removed at any time after 2026-07. "
61-
f"Explicitly import '{__name__}.{name}' instead.",
62-
)
62+
logger.warning(deprecation_message)
6363
except:
6464
pass # nosec
6565

python/tk-core/python/tank/commands/install.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ def _run(self, log, env_name, engine_instance_name, app_name, preserve_yaml):
239239
% (env_name, engine_instance_name)
240240
)
241241

242-
if app_name.endswith(".git"):
242+
if util.is_git_repo_uri(app_name):
243243
# this is a git location!
244244
# run descriptor factory method
245245
log.info("Connecting to git...")
@@ -534,7 +534,7 @@ def _run(self, log, env_name, engine_name, preserve_yaml):
534534
% (env_name, e)
535535
)
536536

537-
if engine_name.endswith(".git"):
537+
if util.is_git_repo_uri(engine_name):
538538
# this is a git location!
539539
# run descriptor factory method
540540
log.info("Connecting to git...")

python/tk-core/python/tank/commands/setup_project_params.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import sys
1515

1616
from . import constants
17+
from . import util
1718

1819
from ..util import StorageRoots
1920
from ..util import sgre as re
@@ -1171,7 +1172,7 @@ def _process_config(self, config_uri):
11711172
# tk-config-xyz
11721173
# /path/to/file.zip
11731174
# /path/to/folder
1174-
if config_uri.endswith(".git"):
1175+
if util.is_git_repo_uri(config_uri):
11751176
# this is a git repository!
11761177
self._log.info("Hang on, loading configuration from git...")
11771178
descriptor = self._create_git_descriptor(config_uri)

python/tk-core/python/tank/commands/switch.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ def run_interactive(self, log, args):
130130

131131
if fourth_param == "app_store":
132132
mode = "app_store"
133-
elif fourth_param.endswith(".git"):
133+
elif util.is_git_repo_uri(fourth_param):
134134
mode = "git"
135135
path = fourth_param
136136
else:

python/tk-core/python/tank/commands/util.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@
1212
Utility methods that are specific to tank commands
1313
"""
1414

15+
from typing import List, Tuple
16+
1517
from . import constants
1618

1719

18-
def should_use_legacy_yaml_parser(args):
20+
def should_use_legacy_yaml_parser(args: List[str]) -> Tuple[bool, List[str]]:
1921
"""
2022
Given a set of command line args, determine if the
2123
legacy yaml parser should be used.
@@ -33,3 +35,19 @@ def should_use_legacy_yaml_parser(args):
3335
legacy_parser = False
3436

3537
return (legacy_parser, args)
38+
39+
40+
def is_git_repo_uri(uri: str) -> bool:
41+
"""
42+
Checks if the given config URI is a Git repository URI.
43+
"""
44+
return any(
45+
(
46+
# GitHub repo URLs end with .git
47+
uri.endswith(".git"),
48+
# Git SSH URLs start with git@
49+
uri.startswith("git@"),
50+
# Azure DevOps repo URLs contain `_git` in the HTTPS URLs
51+
uri.startswith("https://") and "_git" in uri,
52+
)
53+
)

python/tk-core/python/tank/util/version.py

Lines changed: 53 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,41 @@
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
1110
import contextlib
12-
import sys
13-
14-
LooseVersion = None
15-
try:
16-
import packaging.version
17-
except ModuleNotFoundError:
18-
try:
19-
# Try importing from setuptools.
20-
# If it fails, then we can't do much at the moment
21-
# The DCC should have either setuptools or packaging installed.
22-
from setuptools._distutils.version import LooseVersion
23-
except ModuleNotFoundError:
24-
try:
25-
# DCCs with older versions of Python 3.12
26-
from distutils.version import LooseVersion
27-
except ModuleNotFoundError:
28-
pass
11+
import warnings
12+
13+
from tank_vendor.packaging.version import parse as version_parse
2914

30-
from . import sgre as re
3115
from .. import LogManager
3216
from ..errors import TankError
33-
17+
from . import sgre as re
3418

3519
logger = LogManager.get_logger(__name__)
3620
GITHUB_HASH_RE = re.compile("^[0-9a-fA-F]{7,40}$")
3721

22+
# Normalize non-standard version formats
23+
# into PEP 440–compliant forms ("1.2.3") to ensure compatibility with
24+
# Python’s version parsing utilities (e.g., packaging.version.parse).
25+
# Reference: https://peps.python.org/pep-0440/
26+
_VERSION_PATTERNS = [
27+
( # Extract version from software names: "Software Name 21.0" -> "21.0"
28+
re.compile(r"^[a-zA-Z\s]+(\d+(?:\.\d+)*(?:v\d+(?:\.\d+)*)?)$"),
29+
r"\1",
30+
),
31+
( # Dot-v format: "6.3v6" -> "6.3.6"
32+
re.compile(r"^(\d+)\.(\d+)v(\d+)$"),
33+
r"\1.\2.\3",
34+
),
35+
( # Simple v format: "2019v0.1" -> "2019.0.1"
36+
re.compile(r"^(\d+)v(\d+(?:\.\d+)*)$"),
37+
r"\1.\2",
38+
),
39+
( # Service pack with/without dot: "2017.2sp1" or "2017.2.sp1" -> "2017.2.post1"
40+
re.compile(r"^(\d+(?:\.\d+)*)\.?(sp|hotfix|hf)(\d+)$"),
41+
r"\1.post\3",
42+
),
43+
]
44+
3845

3946
def is_version_head(version):
4047
"""
@@ -150,28 +157,29 @@ def suppress_known_deprecation():
150157
yield ctx
151158

152159

153-
def version_parse(version_string):
160+
def normalize_version_format(version: str) -> str:
154161
"""
155-
Parse a version string into a Version object. We also support LooseVersion
156-
for compatibility with older versions of Python.
162+
Normalize version strings by applying common format transformations.
163+
164+
This function exists because packaging.version.parse() follows PEP 440
165+
and cannot handle non-standard version formats like "v1.2.3" or "6.3v6",
166+
which are commonly found in various software tools and DCCs but don't
167+
conform to the PEP 440 specification.
157168
158-
:param str version_string: The version string to parse.
169+
Transformations applied:
170+
- Extract version numbers from software names: "Software Name 21.0" -> "21.0"
171+
- Convert dot-v format: "6.3v6" -> "6.3.6"
172+
- Convert simple v format: "2019v0.1" -> "2019.0.1"
173+
- Convert service pack formats: "2017.2sp1" -> "2017.2.post1", "2017.2.sp1" -> "2017.2.post1"
159174
160-
:rtype: packaging.version.Version, LooseVersion or str as fallback.
175+
:param str version: Version string to normalize
176+
:return str: Normalized version string compatible with PEP 440
161177
"""
162-
if "packaging" in sys.modules:
163-
try:
164-
return packaging.version.parse(version_string)
165-
except packaging.version.InvalidVersion:
166-
# Version cannot be parsed with packaging.version (SG-40480)
167-
pass
168178

169-
if LooseVersion:
170-
with suppress_known_deprecation():
171-
return LooseVersion(version_string)
179+
for compiled_pattern, replacement in _VERSION_PATTERNS:
180+
version = compiled_pattern.sub(replacement, version)
172181

173-
# Fallback to string comparison
174-
return version_string
182+
return version
175183

176184

177185
def _compare_versions(a, b):
@@ -205,79 +213,12 @@ def _compare_versions(a, b):
205213
# comparing against HEAD - our version is always old
206214
return False
207215

208-
if a.startswith("v"):
209-
a = a[1:]
210-
if b.startswith("v"):
211-
b = b[1:]
212-
213-
if "packaging" in sys.modules:
214-
version_a = version_parse(a)
215-
version_b = version_parse(b)
216-
if isinstance(version_a, str) or isinstance(version_b, str):
217-
return a > b
218-
219-
return version_a > version_b
220-
221-
if LooseVersion:
222-
# In Python 3, LooseVersion comparisons between versions where a non-numeric
223-
# version component is compared to a numeric one fail. We'll work around this
224-
# as follows:
225-
# First, try to use LooseVersion for comparison. This should work in
226-
# most cases.
227-
try:
228-
with suppress_known_deprecation():
229-
# Supress `distutils Version classes are deprecated.` for Python 3.10
230-
version_a = LooseVersion(a).version
231-
version_b = LooseVersion(b).version
232-
233-
version_num_a = []
234-
version_num_b = []
235-
# taking only the integers of the version to make comparison
236-
for version in version_a:
237-
if isinstance(version, (int)):
238-
version_num_a.append(version)
239-
elif version == "-":
240-
break
241-
for version in version_b:
242-
if isinstance(version, (int)):
243-
version_num_b.append(version)
244-
elif version == "-":
245-
break
246-
247-
# Comparing equal number versions with with one of them with '-' appended, if a version
248-
# has '-' appended it's older than the same version with '-' at the end
249-
if version_num_a == version_num_b:
250-
if "-" in a and "-" not in b:
251-
return False # False, version a is older than b
252-
elif "-" in b and "-" not in a:
253-
return True # True, version a is older than b
254-
else:
255-
return LooseVersion(a) > LooseVersion(
256-
b
257-
) # If both has '-' compare '-rcx' versions
258-
else:
259-
return LooseVersion(a) > LooseVersion(
260-
b
261-
) # If they are different numeric versions
262-
except TypeError:
263-
version_expr = re.compile(r"^((?:\d+)(?:\.\d+)*)(.+)$")
264-
match_a = version_expr.match(a)
265-
match_b = version_expr.match(b)
266-
if match_a and match_b:
267-
# If we could get two numeric versions, generate LooseVersions for
268-
# them.
269-
ver_a = LooseVersion(match_a.group(1))
270-
ver_b = LooseVersion(match_b.group(1))
271-
if ver_a != ver_b:
272-
# If they're not identical, return based on this comparison
273-
return ver_a > ver_b
274-
else:
275-
# If the numeric versions do match, do a string comparsion for
276-
# the rest.
277-
return match_a.group(2) > match_b.group(2)
278-
elif match_a or match_b:
279-
# If only one had a numeric version, treat that as the newer version.
280-
return bool(match_a)
281-
282-
# In the case that both versions are non-numeric, do a string comparison.
283-
return a > b
216+
a = normalize_version_format(a)
217+
b = normalize_version_format(b)
218+
219+
# Use packaging.version (either system or vendored)
220+
# This is now guaranteed to be available
221+
version_a = version_parse(a)
222+
version_b = version_parse(b)
223+
224+
return version_a > version_b
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# This file is dual licensed under the terms of the Apache License, Version
2+
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
3+
# for complete details.
4+
5+
__title__ = "packaging"
6+
__summary__ = "Core utilities for Python packages"
7+
__uri__ = "https://github.com/pypa/packaging"
8+
9+
__version__ = "25.0"
10+
11+
__author__ = "Donald Stufft and individual contributors"
12+
__email__ = "[email protected]"
13+
14+
__license__ = "BSD-2-Clause or Apache-2.0"
15+
__copyright__ = f"2014 {__author__}"

0 commit comments

Comments
 (0)