pypa/wheel

Can't build wheels on CPython `3.13t` (no GIL / PEP 703) when `py-limited-api` option is set

Opened this issue · 6 comments

I ran into this issue while trying to build a pycryptodome wheel on CPython 3.13t.
See Legrandin/pycryptodome#813

The pycryptodome project sets the py-limited-api option to cp35 in order to limit its abi3 wheels to cp35 and above.

However, when using CPython 3.13t (built without global interpreter lock - PEP 703), this option raises an AssertionError when trying to build the wheel.

The reason for this is this if-else-block:
https://github.com/pypa/wheel/blob/0.43.0/src/wheel/bdist_wheel.py#L344-L348

Building CPython 3.13 without the GIL adds the t ABI flag, so the (impl_name + impl_ver).startswith("cp3") check is incorrect where it sets abi_tag = "abi3" if the condition is true. The AssertionError is then raised afterwards when it checks for supported tags:
https://github.com/pypa/wheel/blob/0.43.0/src/wheel/bdist_wheel.py#L349-L356

$ python3.13 -c 'import sys;print(f"{sys.version_info=}\n{sys.abiflags=}")'
sys.version_info=sys.version_info(major=3, minor=13, micro=0, releaselevel='beta', serial=2)
sys.abiflags='t'

$ pip -v install --no-cache --no-binary=:all: pycryptodome
...
  running install_scripts
  Traceback (most recent call last):
    File "/tmp/venv-pycryptodome-313t/lib/python3.13/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py", line 353, in <module>
      main()
      ~~~~^^
    File "/tmp/venv-pycryptodome-313t/lib/python3.13/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py", line 335, in main
      json_out['return_val'] = hook(**hook_input['kwargs'])
                               ~~~~^^^^^^^^^^^^^^^^^^^^^^^^
    File "/tmp/venv-pycryptodome-313t/lib/python3.13/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py", line 251, in build_wheel
      return _build_backend().build_wheel(wheel_directory, config_settings,
             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                          metadata_directory)
                                          ^^^^^^^^^^^^^^^^^^^
    File "/tmp/pip-build-env-n5p4723l/overlay/lib/python3.13/site-packages/setuptools/build_meta.py", line 410, in build_wheel
      return self._build_with_temp_dir(
             ~~~~~~~~~~~~~~~~~~~~~~~~~^
          ['bdist_wheel'],
          ^^^^^^^^^^^^^^^^
      ...<3 lines>...
          self._arbitrary_args(config_settings),
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      )
      ^
    File "/tmp/pip-build-env-n5p4723l/overlay/lib/python3.13/site-packages/setuptools/build_meta.py", line 395, in _build_with_temp_dir
      self.run_setup()
      ~~~~~~~~~~~~~~^^
    File "/tmp/pip-build-env-n5p4723l/overlay/lib/python3.13/site-packages/setuptools/build_meta.py", line 311, in run_setup
      exec(code, locals())
      ~~~~^^^^^^^^^^^^^^^^
    File "<string>", line 500, in <module>
    File "/tmp/pip-build-env-n5p4723l/overlay/lib/python3.13/site-packages/setuptools/__init__.py", line 103, in setup
      return distutils.core.setup(**attrs)
             ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
    File "/tmp/pip-build-env-n5p4723l/overlay/lib/python3.13/site-packages/setuptools/_distutils/core.py", line 184, in setup
      return run_commands(dist)
    File "/tmp/pip-build-env-n5p4723l/overlay/lib/python3.13/site-packages/setuptools/_distutils/core.py", line 200, in run_commands
      dist.run_commands()
      ~~~~~~~~~~~~~~~~~^^
    File "/tmp/pip-build-env-n5p4723l/overlay/lib/python3.13/site-packages/setuptools/_distutils/dist.py", line 969, in run_commands
      self.run_command(cmd)
      ~~~~~~~~~~~~~~~~^^^^^
    File "/tmp/pip-build-env-n5p4723l/overlay/lib/python3.13/site-packages/setuptools/dist.py", line 968, in run_command
      super().run_command(command)
      ~~~~~~~~~~~~~~~~~~~^^^^^^^^^
    File "/tmp/pip-build-env-n5p4723l/overlay/lib/python3.13/site-packages/setuptools/_distutils/dist.py", line 988, in run_command
      cmd_obj.run()
      ~~~~~~~~~~~^^
    File "/tmp/pip-build-env-n5p4723l/normal/lib/python3.13/site-packages/wheel/bdist_wheel.py", line 405, in run
      impl_tag, abi_tag, plat_tag = self.get_tag()
                                    ~~~~~~~~~~~~^^
    File "/tmp/pip-build-env-n5p4723l/normal/lib/python3.13/site-packages/wheel/bdist_wheel.py", line 355, in get_tag
      tag in supported_tags
  AssertionError: would build wheel with unsupported tag ('cp35', 'abi3', 'linux_x86_64')
  error: subprocess-exited-with-error
  
  × Building wheel for pycryptodome (pyproject.toml) did not run successfully.
  │ exit code: 1
  ╰─> See above for output.
  
  note: This error originates from a subprocess, and is likely not a problem with pip.
  full command: /tmp/venv-pycryptodome-313t/bin/python3.13 /tmp/venv-pycryptodome-313t/lib/python3.13/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py build_wheel /tmp/tmp7erx0b00
  cwd: /tmp/pip-install-tj_45mnk/pycryptodome_a71993a696bd4012b7591b24261f2f5c
  Building wheel for pycryptodome (pyproject.toml): finished with status 'error'
  ERROR: Failed building wheel for pycryptodome
Failed to build pycryptodome
ERROR: Could not build wheels for pycryptodome, which is required to install pyproject.toml-based projects

Tag validation is handled by a vendored copy of the packaging library. If there's a tag validation issue, please open an issue there. I will update the vendored copy when there's a fixed upstream release.

This isn't a packaging issue, because if I remove the option from pycryptodome's setup.cfg, then a cp313t wheel is built just fine.

Please re-read what I posted and see the linked lines of code above which explain the issue.

This is not supposed to be an abi3 wheel. abi3 is incompatible with no-GIL builds (t):

Apologies. But if this concerns bdist_wheel, then I must redirect you to the setuptools project which is now the canonical location of that command.

The way I handle this in scikit-build-core is that if abi3 isn't supported, it is ignored instead and a regular build is created. This is true for free-threading, or if the target version is higher than the current version of Python. (And yes, pypa/setuptools is where all this lives now)

Ok, I see, this was vendored in setuptools but hasn't made it into a new release just yet (current one is 70.0.0):
pypa/setuptools@b3d3e93

However, this should be fixed here too IMO, because there probably are projects which set a specific version of setuptools or which limit the max version, which means they won't get any fixes without the wheel package.

Going to open another issue on the setuptools issue tracker now...

If they have a problem, then they would need to bump the setuptools version. This is perfectly reasonable if someone expects to get new features working with their build system.