Skip to content

Support debug CPython ABI tags in environment compatibility#18739

Open
mjansche wants to merge 2 commits intoastral-sh:mainfrom
mjansche:fix-debug-cpython-abi-tags
Open

Support debug CPython ABI tags in environment compatibility#18739
mjansche wants to merge 2 commits intoastral-sh:mainfrom
mjansche:fix-debug-cpython-abi-tags

Conversation

@mjansche
Copy link
Copy Markdown

Summary

This PR fixes a problem in uv pip install, which currently refuses to install debug wheels in virtual environments with debug CPythons.

Before this change, wheel parsing already preserved debug ABI suffixes like cp313d and cp314d, but Tags::from_env only propagated free-threaded and legacy pymalloc variants. As a result, uv would detect a debug interpreter correctly during discovery while still generating cp313/cp314 environment tags, causing debug-built wheels to be rejected as incompatible.

Fix this by accepting a debug_enabled flag in Tags::from_env, mapping it to CPythonAbiVariants::Debug, and passing the interpreter debug state from the production call sites in uv-python and uv pip resolution.

Also update the affected tests and helpers, and add a regression test that verifies debug CPython 3.13 generates cp313-cp313d manylinux tags.

Test Plan

Tests run:

  • cargo test -p uv-platform-tags tags::tests::test_system_tags_debug_cpython -- --exact
  • cargo test -p uv-installer plan::tests::test_abi3_on_free_threaded_python_hint -- --exact
  • cargo test -p uv-installer plan::tests::test_gil_enabled_cpython_on_free_threaded_python_hint -- --exact
  • cargo test -p uv-installer plan::tests::test_abi3_on_regular_python_no_special_hint -- --exact
  • cargo test -p uv --test it pip_install::abi_compatibility_on_debug_python -- --exact

@mjansche mjansche force-pushed the fix-debug-cpython-abi-tags branch 2 times, most recently from f03126e to e7ab19a Compare March 27, 2026 16:29
@konstin
Copy link
Copy Markdown
Member

konstin commented Mar 30, 2026

We shouldn't need to track whether an interpreter is debug, debug and regular interpreters are ABI-compatible (https://docs.python.org/3.10/using/configure.html#python-debug-build):

Changed in version 3.8: Release builds and debug builds are now ABI compatible: defining the Py_DEBUG macro no longer implies the Py_TRACE_REFS macro (see the --with-trace-refs option), which introduces the only ABI incompatibility.

You shouldn't need the debug flag anymore, it's the same ABI.

Can you share the specific problem you had?

@mjansche
Copy link
Copy Markdown
Author

Makes sense, but in that case we need to relax some of the installation checks. Here is how the problem currently manifests. Let's say we have a trivial sdist of a native module:

native_demo-0.1.0.tar.gz

Map this into a docker container running ghcr.io/astral-sh/uv:debian. Then inside the running container:

apt update -qq && apt install -yqq python3-dbg python3-dev
uv venv --python /usr/bin/python3-dbg   # Important: debug build
. .venv/bin/activate

So far so good.

However, the next step fails:

# uv pip install /tmp/native_demo-0.1.0.tar.gz
Using Python 3.13.5 environment at: /root/.venv
Resolved 1 package in 20ms
      Built native-demo @ file:///tmp/native_demo-0.1.0.tar.gz
  x Failed to build `native-demo @ file:///tmp/native_demo-0.1.0.tar.gz`
  `-> The built wheel `native_demo-0.1.0-cp313-cp313d-linux_x86_64.whl` is not compatible with the current Python 3.13
      on manylinux x86_64

If we dig into it, we see that the wheel build succeeds, but the install fails:

# uv build --wheel /tmp/native_demo-0.1.0.tar.gz
[snip]
Successfully built /tmp/native_demo-0.1.0-cp313-cp313d-linux_x86_64.whl

# uv pip install /tmp/native_demo-0.1.0-cp313-cp313d-linux_x86_64.whl
Using Python 3.13.5 environment at: /root/.venv
Resolved 1 package in 15ms
error: Failed to determine installation plan
  Caused by: A path dependency is incompatible with the current platform: /tmp/native_demo-0.1.0-cp313-cp313d-linux_x86_64.whl

hint: The wheel is compatible with CPython 3.13 (`cp313d`), but you're using CPython 3.13 (`cp313`)

@konstin
Copy link
Copy Markdown
Member

konstin commented Mar 30, 2026

Can you file an issue with what you wrote above? This looks like we should fix it, but with a slightly different fix.

I'm also a bit surprised that setuptools still emits the d flag, given that it's not required anymore.

@mjansche
Copy link
Copy Markdown
Author

Done. #18769

@mjansche mjansche force-pushed the fix-debug-cpython-abi-tags branch 2 times, most recently from afb4364 to bde8b35 Compare March 30, 2026 19:20
@mjansche
Copy link
Copy Markdown
Author

mjansche commented Mar 30, 2026

You shouldn't need the debug flag anymore, it's the same ABI.

I thought about this and the ABI compatibility. I suspect that some mechanism -- not necessarily the present one -- is still going to be needed. The reason is that debug wheels should probably have higher priority when installing for debug CPython. Concretely, across existing tools (pip/packaging, or poetry) the following combinations are allowed:

  • Release wheel and release Python (the most common case)
  • Debug wheel and debug Python (what I'm trying to fix)
  • Release wheel and debug Python (also possible since 3.8, and works with the plain pip module)

The other combination (debug wheel and release Python) is not expected to work.

When multiple wheel flavors are present, the debug wheel is preferred when installing for debug Python.

We can approach this in multiple ways, but I don't see an immediate way of carrying around the information that a given wheel is a debug wheel, so that it can be preferred when installing for debug Python and rejected for release Python.

I've pushed a new version to illustrate what I mean. If there's a simpler way, I'm all ears.

@mjansche mjansche force-pushed the fix-debug-cpython-abi-tags branch from bde8b35 to 30dbdff Compare March 31, 2026 09:21
Since CPython 3.8, debug and release builds share the same ABI. A debug
interpreter now generates both the debug ABI tag (e.g. cp314d) and the
non-debug tag (cp314) as compatible, with the debug tag taking priority.
This matches the behavior of pip's packaging library.

Non-debug interpreters are unchanged: they do not accept cp314d wheels.
@mjansche mjansche force-pushed the fix-debug-cpython-abi-tags branch from 30dbdff to 408b527 Compare March 31, 2026 10:08
@konstin
Copy link
Copy Markdown
Member

konstin commented Mar 31, 2026

It seems like the CPython docs are misleading: python/cpython#146925

I'll review with the clarified CPython compatibility.

@mjansche
Copy link
Copy Markdown
Author

That makes sense and is compatible with the tentative conclusion I reached as I was trying this.

So a debug CPython can install either a debug wheel or a release wheel. Other tooling (pip & friends) seems to strongly suggest that debug wheels are preferred when installing for a debug Python and when both debug wheels and release wheels are available. I looked for a spec that would say that precisely, but no luck yet. But this is how plain old pip behaves and that behavior also makes intuitive sense. If we want to follow that here, we need some mechanism to track and match the properties of the wheels and the target environment.

@konstin
Copy link
Copy Markdown
Member

konstin commented Mar 31, 2026

There's no spec for the precedence for wheel tags, but generally tools prefer more specific wheel tags over more generic wheel tags and get the same priorities this way, so debug tags over regular tags like pip and friends makes a lot of sense.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants