Skip to content

Build abi3.abi3t wheels for Python 3.15 #37

Open

Description

@blankjul

Hey,

I have just wanted to build the binaries in pymoo for a new release and ran into the following issue shown below.
(see https://github.com/anyoptimization/pymoo/actions/runs/19623799509/job/56188870983#logs)

Can extend your build to include the new version as well? At least with a quick look at it I think that is the issue here.

+ uv venv /private/var/folders/6c/pzd640_546q6_yfn24r65c_40000gn/T/cibw-run-0n992_zu/cp314t-macosx_arm64/venv-test-arm64 --python /Library/Frameworks/PythonT.framework/Versions/3.14/bin/python3.14t
  Using CPython 3.14.0+freethreaded interpreter at: /Library/Frameworks/PythonT.framework/Versions/3.14/bin/python3.14t
  Creating virtual environment at: /private/var/folders/6c/pzd640_546q6_yfn24r65c_40000gn/T/cibw-run-0n992_zu/cp314t-macosx_arm64/venv-test-arm64
  Activate with: source /private/var/folders/6c/pzd640_546q6_yfn24r65c_40000gn/T/cibw-run-0n992_zu/cp314t-macosx_arm64/venv-test-arm64/bin/activate
  + which python
  /private/var/folders/6c/pzd640_546q6_yfn24r65c_40000gn/T/cibw-run-0n992_zu/cp314t-macosx_arm64/venv-test-arm64/bin/python
  + /Users/runner/hostedtoolcache/uv/0.9.11/aarch64/uv pip install /private/var/folders/6c/pzd640_546q6_yfn24r65c_40000gn/T/cibw-run-0n992_zu/cp314t-macosx_arm64/repaired_wheel/pymoo-0.6.1.6-cp314-cp314t-macosx_11_0_arm64.whl
  Using Python 3.14.0 environment at: /private/var/folders/6c/pzd640_546q6_yfn24r65c_40000gn/T/cibw-run-0n992_zu/cp314t-macosx_arm64/venv-test-arm64
  Resolved 24 packages in 162ms
  Downloading fonttools (2.8MiB)
  Downloading pillow (4.4MiB)
  Downloading scipy (20.4MiB)
  Downloading matplotlib (7.8MiB)
     Building moocore==0.1.9
   Downloaded pillow
   Downloaded fonttools
   Downloaded matplotlib
   Downloaded scipy
    × Failed to build `moocore==0.1.9`
    ├─▶ The build backend returned an error
    ╰─▶ Call to `setuptools.build_meta.build_wheel` failed (exit status: 1)
  
        [stdout]
        Ignoring py_limited_api=True for free-threaded build.
        running bdist_wheel
  
        [stderr]
        /Users/runner/work/_temp/setup-uv-cache/builds-v0/.tmp9nqxn6/lib/python3.14t/site-packages/setuptools/config/pyprojecttoml.py:72:
        _ExperimentalConfiguration: `[tool.distutils]` in `pyproject.toml` is
        still *experimental* and likely to change in future releases.
          config = read_configuration(filepath, True, ignore_option_errors,
        dist)
        Traceback (most recent call last):
          File "<string>", line 11, in <module>
            wheel_filename =
        backend.build_wheel("/Users/runner/work/_temp/setup-uv-cache/builds-v0/.tmpperhId",
        {}, None)
          File
        "/Users/runner/work/_temp/setup-uv-cache/builds-v0/.tmp9nqxn6/lib/python3.14t/site-packages/setuptools/build_meta.py",
        line 432, in build_wheel
            return _build(['bdist_wheel'])
          File
        "/Users/runner/work/_temp/setup-uv-cache/builds-v0/.tmp9nqxn6/lib/python3.14t/site-packages/setuptools/build_meta.py",
        line 423, in _build
            return self._build_with_temp_dir(
                   ~~~~~~~~~~~~~~~~~~~~~~~~~^
                cmd,
                ^^^^
            ...<3 lines>...
                self._arbitrary_args(config_settings),
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            )
            ^
          File
        "/Users/runner/work/_temp/setup-uv-cache/builds-v0/.tmp9nqxn6/lib/python3.14t/site-packages/setuptools/build_meta.py",
        line 404, in _build_with_temp_dir
            self.run_setup()
            ~~~~~~~~~~~~~~^^
          File
        "/Users/runner/work/_temp/setup-uv-cache/builds-v0/.tmp9nqxn6/lib/python3.14t/site-packages/setuptools/build_meta.py",
        line 317, in run_setup
            exec(code, locals())
            ~~~~^^^^^^^^^^^^^^^^
          File "<string>", line 4, in <module>
            sys.path.pop(0)
            ~~~~~~~~~~~~^^^
          File
        "/Users/runner/work/_temp/setup-uv-cache/builds-v0/.tmp9nqxn6/lib/python3.14t/site-packages/setuptools/__init__.py",
        line 115, in setup
            return distutils.core.setup(**attrs)
                   ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
          File
        "/Users/runner/work/_temp/setup-uv-cache/builds-v0/.tmp9nqxn6/lib/python3.14t/site-packages/setuptools/_distutils/core.py",
        line 186, in setup
            return run_commands(dist)
          File
        "/Users/runner/work/_temp/setup-uv-cache/builds-v0/.tmp9nqxn6/lib/python3.14t/site-packages/setuptools/_distutils/core.py",
        line 202, in run_commands
            dist.run_commands()
            ~~~~~~~~~~~~~~~~~^^
          File
        "/Users/runner/work/_temp/setup-uv-cache/builds-v0/.tmp9nqxn6/lib/python3.14t/site-packages/setuptools/_distutils/dist.py",
        line 1002, in run_commands
            self.run_command(cmd)
            ~~~~~~~~~~~~~~~~^^^^^
          File
        "/Users/runner/work/_temp/setup-uv-cache/builds-v0/.tmp9nqxn6/lib/python3.14t/site-packages/setuptools/dist.py",
        line 1102, in run_command
            super().run_command(command)
            ~~~~~~~~~~~~~~~~~~~^^^^^^^^^
          File
        "/Users/runner/work/_temp/setup-uv-cache/builds-v0/.tmp9nqxn6/lib/python3.14t/site-packages/setuptools/_distutils/dist.py",
        line 1020, in run_command
            cmd_obj.ensure_finalized()
            ~~~~~~~~~~~~~~~~~~~~~~~~^^
          File
        "/Users/runner/work/_temp/setup-uv-cache/builds-v0/.tmp9nqxn6/lib/python3.14t/site-packages/setuptools/_distutils/cmd.py",
        line 135, in ensure_finalized
            self.finalize_options()
            ~~~~~~~~~~~~~~~~~~~~~^^
          File
        "/Users/runner/work/_temp/setup-uv-cache/builds-v0/.tmp9nqxn6/lib/python3.14t/site-packages/setuptools/command/bdist_wheel.py",
        line 250, in finalize_options
            self._validate_py_limited_api()
            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
          File
        "/Users/runner/work/_temp/setup-uv-cache/builds-v0/.tmp9nqxn6/lib/python3.14t/site-packages/setuptools/command/bdist_wheel.py",
        line 285, in _validate_py_limited_api
            raise ValueError(
            ...<4 lines>...
            )
        ValueError: `py_limited_api='cp310'` not supported. `Py_LIMITED_API`
        is currently incompatible with `Py_GIL_DISABLED`. See
        https://github.com/python/cpython/issues/111506.
  
        hint: This usually indicates a problem with the package or the build
        environment.
    help: `moocore` (v0.1.9) was included because `pymoo` (v0.6.1.6) depends
          on `moocore`
                                                              ✕ 2.46s
Error: cibuildwheel: Command ['/Users/runner/hostedtoolcache/uv/0.9.11/aarch64/uv', 'pip', 'install', '/private/var/folders/6c/pzd640_546q6_yfn24r65c_40000gn/T/cibw-run-0n992_zu/cp314t-macosx_arm64/repaired_wheel/pymoo-0.6.1.6-cp314-cp314t-macosx_11_0_arm64.whl'] failed with code 1. 

Error: Process completed with exit code 1.

Activity

  1. MLopez-Ibanez commented on Nov 24, 2025

    @MLopez-Ibanez
    Contributor

    The problem is that you are building for Python 3.14t (the free-threading version): https://docs.python.org/3/howto/free-threading-python.html

    Currently, I skip building wheels for free-threading python:

    "cp314t-*", # Skip free-threaded builds

    moocore wheels are compatible with all python versions included 3.14 that are non-free-threading. The free-threading versions are still experimental so each new free-threading python version will need its own wheels.

    Moreover, since free-threading is still experimental and not the default, there may be bugs that only the Python developers can fix. I would expect most users of moocore and pymoo to use the default non-free-threaded version of Python 3.14.

    I am happy to create version-specific wheels for 3.14t for you to test if you think pymoo should work in free-threading mode, but you may wish to check all your CPython code to make sure you do support free-threading: https://docs.python.org/3/howto/free-threading-extensions.html#freethreading-extensions-howto

    Please let me know what you plan to do. I don't want to build for 3.14 free-threading unless you really need it.

  2. changed the title [-]Adding binaries to build in moocore for python[/-] [+]Build wheels for Python 3.14t (free-threading)[/+] on Nov 24, 2025
  3. MLopez-Ibanez commented on Nov 24, 2025

    @MLopez-Ibanez
    Contributor

    By the way, python/cpython#111506 is about extending the stable ABI to support free-threaded Python. If they do that, then the builds of moocore will work in both classical and free-threaded Python versions, without needing to build new wheels for each Python version.

  4. blankjul commented on Nov 25, 2025

    @blankjul
    Author

    actually fair point that it is currently flagged as experimental. I saw you already commented on the corresponding issue in pymoo as well.

    let me follow the same build pattern as moocore for now.

  5. changed the title [-]Build wheels for Python 3.14t (free-threading)[/-] [+]Build wheels for free-threading Python (3.15?)[/+] on Nov 25, 2025
  6. MLopez-Ibanez commented on Nov 25, 2025

    @MLopez-Ibanez
    Contributor

    OK, I'll keep this open in case somebody else wants to work on it. I will revisit this again once Python 3.15 is released. Hopefully the ABI will be stable (or even better, free-threading will be the default).

  7. tpgillam commented on Dec 18, 2025

    @tpgillam
    Contributor

    There appears to be appetite for free-threaded support btw; see user request here:

  8. Deathn0t commented on Dec 19, 2025

    @Deathn0t

    Hello,

    My appetite is mostly experimental 😄 I had not found this discussion yet! So no rush for me at least.

    I found out with a simple experiments using Python 3.14t that it seems to scale poorly w.r.t. threads for now.
    From 1 to 2 threads I get a speed-up significantly less than x2 (x1.45, from 84sec. to 58sec.). Looking at htop in same time clearly shows that the correct corresponding number of cores are busy!

    I used the following script if you want to play with that! I have not yet tested the same test without joblib but directly through threading module...

    # /// script
    # requires-python = ">=3.12"
    # dependencies = [
    #   "joblib",
    #   "numpy",
    # ]
    # ///
    
    # $ uv run -p 3.14t test_joblib.py 1
    # N-Jobs: 1
    # Duration: 84.40 sec.
    
    # $ uv run -p 3.14t test_joblib.py 2
    # N-Jobs: 2
    # Duration: 58.01 sec.
    
    # $ uv run -p 3.14t test_joblib.py 5
    # N-Jobs: 5
    # Duration: 77.45 sec.
    
    # $ uv run -p 3.14t test_joblib.py 10
    # N-Jobs: 10
    # Duration: 76.93 sec.
    
    import time
    import sys
    import numpy as np
    from joblib import Parallel, delayed
    
    
    def do_some_work(chunk_size: int, n_repetition: int):
        for _ in range(n_repetition):
            # I was just checking if the random generator would imply some
            # additional mutex overhead...
            # X = np.random.random((chunk_size, chunk_size))
            X = np.ones((chunk_size, chunk_size))
            Y = X @ X
            y = np.sum(Y)
        return y
    
    
    if __name__ == "__main__":
        chunk_size = 1000
        n_repetition = 1000
        n_tasks = 10
        n_jobs = int(sys.argv[-1])
        t1 = time.monotonic()
        results = Parallel(n_jobs=n_jobs, backend="threading")(
            delayed(do_some_work)(chunk_size, n_repetition) for _ in range(n_tasks)
        )
        d = time.monotonic() - t1
        print(f"N-Jobs: {n_jobs}")
        print(f"Duration: {d:.2f} sec.")
  9. MLopez-Ibanez commented on Dec 19, 2025

    @MLopez-Ibanez
    Contributor

    I would also guess that neither pymoo nor moocore will benefit from free-threaded python because expensive computations are done in C already for speed. It is relatively easy to parallelize the C code using OpenMP if desired.

  10. tpgillam commented on Dec 22, 2025

    @tpgillam
    Contributor

    I would also guess that neither pymoo nor moocore will benefit from free-threaded python because expensive computations are done in C already for speed. It is relatively easy to parallelize the C code using OpenMP if desired.

    I presume the benefit would be that if users wish to use free-threaded python for other parts of their code, then it'll be convenient if they can use other libraries from within the same interpreter. Even if e.g. moocore or pymoo wouldn't go any faster, other parts of the codebase might.

  11. ngoldbaum commented on Feb 23, 2026

    @ngoldbaum
  12. MLopez-Ibanez commented on Feb 23, 2026

    @MLopez-Ibanez
  13. ngoldbaum commented on Feb 23, 2026

    @ngoldbaum

    Thanks!

    Moreover, since free-threading is still experimental and not the default, there may be bugs that only the Python developers can fix. I would expect most users of moocore and pymoo to use the default non-free-threaded version of Python 3.14.

    For what it's worth, free-threaded Python 3.14 is no longer considered experimental. That said, it's not yet the default so in that sense it's a little experimental. See PEP 779 for more details about the current status.

    I will say that since you are using CFFI and since CFFI 2.0 fully supports the free-threaded build, I think you should feel safe to support the free-threaded build. I was heavily involved with updating CFFI last year and am happy to answer questions about that. I also wrote this documentation: https://cffi.readthedocs.io/en/stable/overview.html#thread-safety.

    Note that CFFI has always released the GIL when calling into extensions, so any thread safety issues possible on the free-threaded build should also be possible on the GIL-enabled build. So in that sense, I don't think you should be overly concerned about issues due to threading except insofar as people will want to use multithreaded parallelism where before, on the GIL-enabled build, most people keep away from the threading module because of the GIL.

  14. MLopez-Ibanez commented on Feb 23, 2026

    @MLopez-Ibanez
    Contributor

    Thank you for your detailed comments and your work on CFFI.

    The extra work (and extra computational power) of building and testing wheels for specific versions of free-threaded Python is too high. I will wait until there's a stable ABI for free-threaded Python and, ideally, a way to build wheels that work for both free-threaded and GIL-enabled Python.

    PEP 803 seems to imply that abi3.abi3t wheels will not be backwards compatible to older GIL-enabled Python. That would be unfortunate. I would like to build a single wheel that works for all supported versions of GIL-enabled Python (at least >=3.10) and all free-threaded versions of Python starting from 3.15.

  15. ngoldbaum commented on Feb 23, 2026

    @ngoldbaum

    PEP 803 seems to imply that abi3.abi3t wheels will not be backwards compatible to older GIL-enabled Python. That would be unfortunate. I would like to build a single wheel that works for all supported versions of GIL-enabled Python (at least >=3.10) and all free-threaded versions of Python starting from 3.15.

    As far as I understand that's
    not feasible, since it depends on things that were added to the stable ABI for 3.12 (PEP 697) and 3.15 (PEP 793). In the long term you'll be able to only have one build though, but for several years you'll have to have two builds. But you also only have to do the work once and not for every Python version.

  16. MLopez-Ibanez commented on Feb 24, 2026

    @MLopez-Ibanez
    Contributor

    As far as I understand that's not feasible, since it depends on things that were added to the stable ABI for 3.12 (PEP 697) and 3.15 (PEP 793). In the long term you'll be able to only have one build though, but for several years you'll have to have two builds. But you also only have to do the work once and not for every Python version.

    That's good enough! Hopefully we will see this working for 3.15.

  17. ngoldbaum commented on Feb 24, 2026

    @ngoldbaum
  18. MLopez-Ibanez commented on Aug 14, 2026

    @MLopez-Ibanez
    Contributor

    Once Python 3.15 is released, it should be possible to build cp-315.abi3.abi3t wheels that work for GIL and free-threaded python. I am happy to have both these wheels and the cp-310.abi3 wheels just for GIL python.

    I'm looking for help is modifying moocore's CI to build the abi3t wheels. If you can help, please open a PR. Feel free to use AI if that helps you.

  19. changed the title [-]Build wheels for free-threading Python (3.15?)[/-] [+]Build abi3.abi3t wheels for Python 3.15[/+] on Aug 14, 2026
  20. MLopez-Ibanez commented on Aug 22, 2026

    @MLopez-Ibanez
    Contributor

    This may have to wait until pypa/setuptools#5193 is merged or we switch to a different build tool.

  21. MLopez-Ibanez commented on Oct 21, 2026

    @MLopez-Ibanez
    Contributor

    This may have to wait until pypa/setuptools#5193 is merged or we switch to a different build tool.

    The PR is merged and a new version of setuptools is available so it should be possible to implement this. Any help is welcome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions