From eb2a6532f967fae3f4abd15c7923b67fef608b67 Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Mon, 28 Oct 2024 18:14:11 +0000 Subject: [PATCH] Support free threaded Python versions like '3.13t' Python wheels, pyenv, and a number of other tools use 't' in the Python version number to identify free threaded builds. For example, '3.13t', '3.14.0a1', '3.14t-dev'. This PR supports that syntax in `actions/setup-python`, strips the "t", and adds "-freethreading" to the architecture to select the correct Python version. See #771 --- dist/setup/index.js | 27 +++++++++++++++++++++++++-- src/find-python.ts | 30 ++++++++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/dist/setup/index.js b/dist/setup/index.js index e56f9660..97b5e5ce 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -91038,9 +91038,15 @@ function useCpythonVersion(version, architecture, updateEnvironment, checkLatest return __awaiter(this, void 0, void 0, function* () { var _a; let manifest = null; - const desugaredVersionSpec = desugarDevVersion(version); - let semanticVersionSpec = pythonVersionToSemantic(desugaredVersionSpec, allowPreReleases); + const [desugaredVersionSpec, freethreaded] = desugarFreeThreadedVersion(version); + const desugaredVersionSpec2 = desugarDevVersion(desugaredVersionSpec); + let semanticVersionSpec = pythonVersionToSemantic(desugaredVersionSpec2, allowPreReleases); core.debug(`Semantic version spec of ${version} is ${semanticVersionSpec}`); + if (freethreaded) { + // Free threaded versions use an architecture suffix like `x64-freethreaded` + core.debug(`Using freethreaded version of ${semanticVersionSpec}`); + architecture += freethreaded; + } if (checkLatest) { manifest = yield installer.getManifest(); const resolvedVersion = (_a = (yield installer.findReleaseFromManifest(semanticVersionSpec, architecture, manifest))) === null || _a === void 0 ? void 0 : _a.version; @@ -91115,6 +91121,23 @@ function useCpythonVersion(version, architecture, updateEnvironment, checkLatest }); } exports.useCpythonVersion = useCpythonVersion; +/* Identify freethreaded versions like, 3.13t, 3.13t-dev, 3.14.0a1t. Returns + * the version without the `t` and the architectures suffix, if freethreaded */ +function desugarFreeThreadedVersion(versionSpec) { + const prereleaseVersion = /(\d+\.\d+\.\d+)(t)((?:a|b|rc)\d*)/g; + if (prereleaseVersion.test(versionSpec)) { + return [versionSpec.replace(prereleaseVersion, '$1$3'), '-freethreaded']; + } + const majorMinor = /^(\d+\.\d+)(t)$/; + if (majorMinor.test(versionSpec)) { + return [versionSpec.replace(majorMinor, '$1'), '-freethreaded']; + } + const devVersion = /^(\d+\.\d+)(t)(-dev)$/; + if (devVersion.test(versionSpec)) { + return [versionSpec.replace(devVersion, '$1$3'), '-freethreaded']; + } + return [versionSpec, '']; +} /** Convert versions like `3.8-dev` to a version like `~3.8.0-0`. */ function desugarDevVersion(versionSpec) { const devVersion = /^(\d+)\.(\d+)-dev$/; diff --git a/src/find-python.ts b/src/find-python.ts index 77278770..3c2b8b13 100644 --- a/src/find-python.ts +++ b/src/find-python.ts @@ -38,13 +38,21 @@ export async function useCpythonVersion( allowPreReleases: boolean ): Promise { let manifest: tc.IToolRelease[] | null = null; - const desugaredVersionSpec = desugarDevVersion(version); + const [desugaredVersionSpec, freethreaded] = + desugarFreeThreadedVersion(version); + const desugaredVersionSpec2 = desugarDevVersion(desugaredVersionSpec); let semanticVersionSpec = pythonVersionToSemantic( - desugaredVersionSpec, + desugaredVersionSpec2, allowPreReleases ); core.debug(`Semantic version spec of ${version} is ${semanticVersionSpec}`); + if (freethreaded) { + // Free threaded versions use an architecture suffix like `x64-freethreaded` + core.debug(`Using freethreaded version of ${semanticVersionSpec}`); + architecture += freethreaded; + } + if (checkLatest) { manifest = await installer.getManifest(); const resolvedVersion = ( @@ -159,6 +167,24 @@ export async function useCpythonVersion( return {impl: 'CPython', version: installed}; } +/* Identify freethreaded versions like, 3.13t, 3.13t-dev, 3.14.0a1t. Returns + * the version without the `t` and the architectures suffix, if freethreaded */ +function desugarFreeThreadedVersion(versionSpec: string) { + const prereleaseVersion = /(\d+\.\d+\.\d+)(t)((?:a|b|rc)\d*)/g; + if (prereleaseVersion.test(versionSpec)) { + return [versionSpec.replace(prereleaseVersion, '$1$3'), '-freethreaded']; + } + const majorMinor = /^(\d+\.\d+)(t)$/; + if (majorMinor.test(versionSpec)) { + return [versionSpec.replace(majorMinor, '$1'), '-freethreaded']; + } + const devVersion = /^(\d+\.\d+)(t)(-dev)$/; + if (devVersion.test(versionSpec)) { + return [versionSpec.replace(devVersion, '$1$3'), '-freethreaded']; + } + return [versionSpec, '']; +} + /** Convert versions like `3.8-dev` to a version like `~3.8.0-0`. */ function desugarDevVersion(versionSpec: string) { const devVersion = /^(\d+)\.(\d+)-dev$/;