Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow manylinux compatibility override via _manylinux module. #6039

Merged
merged 15 commits into from
Aug 21, 2024

Conversation

ChannyClaus
Copy link
Contributor

@ChannyClaus ChannyClaus commented Aug 12, 2024

Summary

resolves #5915, not entirely sure if manylinux_compatible should be a separate field in the JSON returned by the interpreter or there's some way to use the existing platform for it.

Test Plan

ran the below

rm -rf .venv
target/debug/uv venv
# commenting out the line below triggers the change..
# target/debug/uv pip install no-manylinux
target/debug/uv pip install cryptography --no-cache

is there an easy way to add this into the existing snapshot-based test suite? looking around to see if there's a way that doesn't involve something implementation-dependent like mocks.

update: i think the output does differ between these two, so probably we can use that. i lied - that "building..." output seems to be discarded.

@ChannyClaus ChannyClaus marked this pull request as draft August 12, 2024 17:38
@ChannyClaus ChannyClaus marked this pull request as ready for review August 12, 2024 20:31
@charliermarsh charliermarsh self-assigned this Aug 15, 2024
@charliermarsh charliermarsh added bug Something isn't working compatibility Compatibility with a specification or another tool labels Aug 15, 2024
@charliermarsh
Copy link
Member

Thanks! I can own reviewing this.

@charliermarsh
Copy link
Member

Hmm, looking at the source... I think this might be slightly more complicated. We don't just need to check what manylinux compatibility for the current glibc version. We also need to check compatibility for every prior manylinux version... Notice that in pip, they do:

def platform_tags(archs: Sequence[str]) -> Iterator[str]:
    """Generate manylinux tags compatible to the current platform.

    :param archs: Sequence of compatible architectures.
        The first one shall be the closest to the actual architecture and be the part of
        platform tag after the ``linux_`` prefix, e.g. ``x86_64``.
        The ``linux_`` prefix is assumed as a prerequisite for the current platform to
        be manylinux-compatible.

    :returns: An iterator of compatible manylinux tags.
    """
    if not _have_compatible_abi(sys.executable, archs):
        return
    # Oldest glibc to be supported regardless of architecture is (2, 17).
    too_old_glibc2 = _GLibCVersion(2, 16)
    if set(archs) & {"x86_64", "i686"}:
        # On x86/i686 also oldest glibc to be supported is (2, 5).
        too_old_glibc2 = _GLibCVersion(2, 4)
    current_glibc = _GLibCVersion(*_get_glibc_version())
    glibc_max_list = [current_glibc]
    # We can assume compatibility across glibc major versions.
    # https://sourceware.org/bugzilla/show_bug.cgi?id=24636
    #
    # Build a list of maximum glibc versions so that we can
    # output the canonical list of all glibc from current_glibc
    # down to too_old_glibc2, including all intermediary versions.
    for glibc_major in range(current_glibc.major - 1, 1, -1):
        glibc_minor = _LAST_GLIBC_MINOR[glibc_major]
        glibc_max_list.append(_GLibCVersion(glibc_major, glibc_minor))
    for arch in archs:
        for glibc_max in glibc_max_list:
            if glibc_max.major == too_old_glibc2.major:
                min_minor = too_old_glibc2.minor
            else:
                # For other glibc major versions oldest supported is (x, 0).
                min_minor = -1
            for glibc_minor in range(glibc_max.minor, min_minor, -1):
                glibc_version = _GLibCVersion(glibc_max.major, glibc_minor)
                tag = "manylinux_{}_{}".format(*glibc_version)
                if _is_compatible(arch, glibc_version):
                    yield f"{tag}_{arch}"
                # Handle the legacy manylinux1, manylinux2010, manylinux2014 tags.
                if glibc_version in _LEGACY_MANYLINUX_MAP:
                    legacy_tag = _LEGACY_MANYLINUX_MAP[glibc_version]
                    if _is_compatible(arch, glibc_version):
                        yield f"{legacy_tag}_{arch}"

So they're testing _is_compatible against all versions.

@charliermarsh
Copy link
Member

Maybe we should just settle for testing the current manylinux version though. Otherwise we'll have to test a bunch of versions and pass that around.

@charliermarsh
Copy link
Member

It seems more common that people use blanket implementations anyway:

def manylinux_compatible(*_, **__):  # PEP 600
    return False

@charliermarsh
Copy link
Member

The alternative is that we iterate over all glibc versions up to and including the current, call _is_compatible, and then pass back a dictionary.

@charliermarsh
Copy link
Member

What do you think @konstin?

@ChannyClaus
Copy link
Contributor Author

Hmm, looking at the source... I think this might be slightly more complicated. We don't just need to check what manylinux compatibility for the current glibc version. We also need to check compatibility for every prior manylinux version... Notice that in pip, they do:

def platform_tags(archs: Sequence[str]) -> Iterator[str]:
    """Generate manylinux tags compatible to the current platform.

    :param archs: Sequence of compatible architectures.
        The first one shall be the closest to the actual architecture and be the part of
        platform tag after the ``linux_`` prefix, e.g. ``x86_64``.
        The ``linux_`` prefix is assumed as a prerequisite for the current platform to
        be manylinux-compatible.

    :returns: An iterator of compatible manylinux tags.
    """
    if not _have_compatible_abi(sys.executable, archs):
        return
    # Oldest glibc to be supported regardless of architecture is (2, 17).
    too_old_glibc2 = _GLibCVersion(2, 16)
    if set(archs) & {"x86_64", "i686"}:
        # On x86/i686 also oldest glibc to be supported is (2, 5).
        too_old_glibc2 = _GLibCVersion(2, 4)
    current_glibc = _GLibCVersion(*_get_glibc_version())
    glibc_max_list = [current_glibc]
    # We can assume compatibility across glibc major versions.
    # https://sourceware.org/bugzilla/show_bug.cgi?id=24636
    #
    # Build a list of maximum glibc versions so that we can
    # output the canonical list of all glibc from current_glibc
    # down to too_old_glibc2, including all intermediary versions.
    for glibc_major in range(current_glibc.major - 1, 1, -1):
        glibc_minor = _LAST_GLIBC_MINOR[glibc_major]
        glibc_max_list.append(_GLibCVersion(glibc_major, glibc_minor))
    for arch in archs:
        for glibc_max in glibc_max_list:
            if glibc_max.major == too_old_glibc2.major:
                min_minor = too_old_glibc2.minor
            else:
                # For other glibc major versions oldest supported is (x, 0).
                min_minor = -1
            for glibc_minor in range(glibc_max.minor, min_minor, -1):
                glibc_version = _GLibCVersion(glibc_max.major, glibc_minor)
                tag = "manylinux_{}_{}".format(*glibc_version)
                if _is_compatible(arch, glibc_version):
                    yield f"{tag}_{arch}"
                # Handle the legacy manylinux1, manylinux2010, manylinux2014 tags.
                if glibc_version in _LEGACY_MANYLINUX_MAP:
                    legacy_tag = _LEGACY_MANYLINUX_MAP[glibc_version]
                    if _is_compatible(arch, glibc_version):
                        yield f"{legacy_tag}_{arch}"

So they're testing _is_compatible against all versions.

ah, probably should've looked there as well - i can implement the equivalent logic if y'all decide that to be the way to go 🌵

for what it's worth i do think what you point out in #6039 (comment) is probably true 😅

@charliermarsh
Copy link
Member

I think we should just document it and move forward as-is.

@charliermarsh charliermarsh force-pushed the no-manylinux branch 2 times, most recently from 8bc77ad to b43f389 Compare August 21, 2024 01:44
@charliermarsh charliermarsh enabled auto-merge (squash) August 21, 2024 01:44
@charliermarsh charliermarsh force-pushed the no-manylinux branch 2 times, most recently from ad55f95 to e4fca21 Compare August 21, 2024 01:45
@charliermarsh charliermarsh merged commit c9774e9 into astral-sh:main Aug 21, 2024
56 checks passed
@ChannyClaus ChannyClaus deleted the no-manylinux branch August 21, 2024 01:58
tmeijn pushed a commit to tmeijn/dotfiles that referenced this pull request Aug 22, 2024
This MR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [astral-sh/uv](https://github.com/astral-sh/uv) | patch | `0.3.0` -> `0.3.1` |

MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot).

**Proposed changes to behavior should be submitted there as MRs.**

---

### Release Notes

<details>
<summary>astral-sh/uv (astral-sh/uv)</summary>

### [`v0.3.1`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#031)

[Compare Source](astral-sh/uv@0.3.0...0.3.1)

##### Enhancements

-   Add `--with-editable` support to `uv run` ([#&#8203;6262](astral-sh/uv#6262))
-   Respect `.python-version` files and `pyproject.toml` in `uv python find` ([#&#8203;6369](astral-sh/uv#6369))
-   Allow manylinux compatibility override via `_manylinux` module ([#&#8203;6039](astral-sh/uv#6039))

##### CLI

-   Avoid treating `uv add -r` as `--raw-sources` ([#&#8203;6287](astral-sh/uv#6287))

##### Bug fixes

-   Always invoke found interpreter when `uv run python` is used ([#&#8203;6363](astral-sh/uv#6363))
-   Avoid adding extra newline for script with non-empty prelude ([#&#8203;6366](astral-sh/uv#6366))
-   Fix metadata cache instability for lockfile ([#&#8203;6332](astral-sh/uv#6332))
-   Handle Ctrl-C properly in `uvx` invocations ([#&#8203;6346](astral-sh/uv#6346))
-   Ignore workspace discovery errors with `--no-workspace` ([#&#8203;6328](astral-sh/uv#6328))
-   Invalidate `uv.lock` when virtual `dev-dependencies` change ([#&#8203;6291](astral-sh/uv#6291))
-   Make cache robust to removed archives ([#&#8203;6284](astral-sh/uv#6284))
-   Preserve Git username for SSH dependencies ([#&#8203;6335](astral-sh/uv#6335))
-   Respect `--no-build-isolation` in `uv add` ([#&#8203;6368](astral-sh/uv#6368))
-   Respect `.python-version` files in `uv run` outside projects ([#&#8203;6361](astral-sh/uv#6361))
-   Use `sys_executable` for `uv run` invocations ([#&#8203;6354](astral-sh/uv#6354))
-   Use atomic write for `pip compile` output ([#&#8203;6274](astral-sh/uv#6274))
-   Use consistent logic for deserializing short revisions ([#&#8203;6341](astral-sh/uv#6341))

##### Documentation

-   Remove the preview default value of `python-preference` ([#&#8203;6301](astral-sh/uv#6301))
-   Update env vars doc about `XDG_*` variables on macOS ([#&#8203;6337](astral-sh/uv#6337))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this MR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box

---

This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy40NDAuNyIsInVwZGF0ZWRJblZlciI6IjM3LjQ0MC43IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJSZW5vdmF0ZSBCb3QiXX0=-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working compatibility Compatibility with a specification or another tool
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Does uv honor the no-manylinux install flags?
2 participants