From af25d7167d868f061adeed1762367dccbd38b7e0 Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Thu, 29 Jan 2026 19:53:58 -0500 Subject: [PATCH] support free-threading python --- locallibs/get.py | 15 +++++++++++---- make_relocatable_python_framework.py | 13 ++++++++++++- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/locallibs/get.py b/locallibs/get.py index a9d867f..acc70cf 100644 --- a/locallibs/get.py +++ b/locallibs/get.py @@ -42,10 +42,12 @@ def __init__( python_version=DEFAULT_PYTHON_VERSION, os_version=DEFAULT_OS_VERSION, base_url=DEFAULT_BASEURL, + free_threading=False, ): self.python_version = python_version self.os_version = os_version self.base_url = base_url + self.free_threading = free_threading self.destination = "" def __del__(self): @@ -63,9 +65,11 @@ def download(self): base_url = self.base_url.replace('macosx', 'macos') else: base_url = self.base_url + # Add 't' suffix for free-threading builds + version_for_url = self.python_version + 't' if self.free_threading else self.python_version url = base_url % ( self.python_version, - self.python_version, + version_for_url, self.os_version, ) (file_handle, destination_path) = tempfile.mkstemp() @@ -90,9 +94,12 @@ def expand(self): def extract_framework(self): """Extracts the Python framework from the expanded pkg""" - payload = os.path.join( - self.expanded_path, "Python_Framework.pkg/Payload" - ) + # Use PythonT_Framework for free-threading builds + if self.free_threading: + pkg_name = "PythonT_Framework.pkg/Payload" + else: + pkg_name = "Python_Framework.pkg/Payload" + payload = os.path.join(self.expanded_path, pkg_name) cmd = [DITTO, "-xz", payload, self.destination] print("Extracting %s to %s..." % (payload, self.destination)) subprocess.check_call(cmd) diff --git a/make_relocatable_python_framework.py b/make_relocatable_python_framework.py index fdca736..7272e07 100755 --- a/make_relocatable_python_framework.py +++ b/make_relocatable_python_framework.py @@ -78,19 +78,30 @@ def main(): action="store_true", help="Do not install pip." ) + parser.add_option( + "--free-threading", + default=False, + action="store_true", + help="Use free-threading Python build (adds 't' suffix to version)." + ) parser.set_defaults(unsign=True) options, _arguments = parser.parse_args() framework_path = get.FrameworkGetter( python_version=options.python_version, os_version=options.os_version, base_url=options.baseurl, + free_threading=options.free_threading, ).download_and_extract(destination=options.destination) if framework_path: files_relocatablized = relocatablize(framework_path) if options.unsign: fix_broken_signatures(files_relocatablized) - short_version = ".".join(options.python_version.split(".")[0:2]) + # Extract major.minor version, adding 't' suffix for free-threading + version_parts = options.python_version.split(".") + short_version = ".".join(version_parts[0:2]) + if options.free_threading: + short_version += 't' install_extras( framework_path, version=short_version,