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

uv installs really old version of web3 in the presence of numpy and streamlit on 3.10, unlike pip #4372

Closed
wakamex opened this issue Jun 17, 2024 · 11 comments
Labels
question Asking for clarification or support resolver Related to the package resolver

Comments

@wakamex
Copy link

wakamex commented Jun 17, 2024

uv worked fine until a recent update to one of these packages (not uv itself, saw the same on 0.19) caused it to go into dependency resolution hell.

  • Find below my pip freeze results for pip and uv for 4 different configurations.
  • The first two are cursed and give the old web3.
  • The last two give the expected web3==6.19.0 which agrees with pip but at the cost of removing dependencies.
  • I used a fresh install of 3.10 through pyenv, new virtualenvs and latest pip
  • for uv I use uv venv .venv -p 3.10 && source .venv/bin/activate && uv pip install -e .
[project]
name = "project"
version = "1"
# with eth-typing, we get web3==3.16.3
dependencies = [
    "eth-typing",
    "numpy",
    "streamlit",
    "web3"
]
# === PIP FREEZE (pip-24.0) ===
# aiohttp==3.9.5
# aiosignal==1.3.1
# altair==5.3.0
# async-timeout==4.0.3
# attrs==23.2.0
# bitarray==2.9.2
# blinker==1.8.2
# cachetools==5.3.3
# certifi==2024.6.2
# charset-normalizer==3.3.2
# ckzg==1.0.2
# click==8.1.7
# cytoolz==0.12.3
# eth-account==0.11.2
# eth-hash==0.7.0
# eth-keyfile==0.8.1
# eth-keys==0.5.1
# eth-rlp==1.0.1
# eth-typing==4.3.1
# eth-utils==4.1.1
# eth_abi==5.1.0
# frozenlist==1.4.1
# gitdb==4.0.11
# GitPython==3.1.43
# hexbytes==0.3.1
# idna==3.7
# Jinja2==3.1.4
# jsonschema==4.22.0
# jsonschema-specifications==2023.12.1
# lru-dict==1.2.0
# markdown-it-py==3.0.0
# MarkupSafe==2.1.5
# mdurl==0.1.2
# multidict==6.0.5
# numpy==1.26.4
# packaging==24.1
# pandas==2.2.2
# parsimonious==0.10.0
# pillow==10.3.0
# project==1
# protobuf==4.25.3
# pyarrow==16.1.0
# pycryptodome==3.20.0
# pydeck==0.9.1
# Pygments==2.18.0
# python-dateutil==2.9.0.post0
# pytz==2024.1
# pyunormalize==15.1.0
# referencing==0.35.1
# regex==2024.5.15
# requests==2.32.3
# rich==13.7.1
# rlp==4.0.1
# rpds-py==0.18.1
# six==1.16.0
# smmap==5.0.1
# streamlit==1.35.0
# tenacity==8.4.1
# toml==0.10.2
# toolz==0.12.1
# tornado==6.4.1
# typing_extensions==4.12.2
# tzdata==2024.1
# urllib3==2.2.2
# watchdog==4.0.1
# web3==6.19.0
# websockets==12.0
# yarl==1.9.4
# === PIP FREEZE (pip-24.0) ===
# altair==4.2.2
# attrs==23.2.0
# blinker==1.8.2
# cachetools==5.3.3
# certifi==2024.6.2
# charset-normalizer==3.3.2
# click==8.1.7
# cytoolz==0.12.3
# entrypoints==0.4
# eth-hash==0.7.0
# eth-typing==4.3.1
# eth-utils==4.1.1
# ethereum-abi-utils==0.4.7
# ethereum-tester==0.1.0b3
# ethereum-utils==0.6.2
# gitdb==4.0.11
# gitpython==3.1.43
# idna==3.7
# importlib-metadata==7.1.0
# jinja2==3.1.4
# jsonschema==4.22.0
# jsonschema-specifications==2023.12.1
# markdown-it-py==3.0.0
# markupsafe==2.1.5
# mdurl==0.1.2
# numpy==2.0.0
# packaging==24.1
# pandas==2.2.2
# pillow==10.3.0
# -e file:///code/testrepo
# protobuf==3.20.3
# pyarrow==16.1.0
# pydeck==0.9.1
# pygments==2.18.0
# pylru==1.2.1
# pympler==1.0.1
# pysha3==1.0.2
# python-dateutil==2.9.0.post0
# pytz==2024.1
# referencing==0.35.1
# requests==2.32.3
# rich==13.7.1
# rlp==4.0.1
# rpds-py==0.18.1
# six==1.16.0
# smmap==5.0.1
# streamlit==1.22.0
# tenacity==8.4.1
# toml==0.10.2
# toolz==0.12.1
# tornado==6.4.1
# typing-extensions==4.12.2
# tzdata==2024.1
# tzlocal==5.2
# urllib3==2.2.2
# validators==0.28.3
# watchdog==4.0.1
# web3==3.16.3
# zipp==3.19.2

# removing eth-typing brings web3 up to 5.23.0
# dependencies = [
#     "numpy",
#     "streamlit",
#     "web3"
# ]
# === PIP FREEZE (pip-24.0) ===
# aiohttp==3.9.5
# aiosignal==1.3.1
# altair==5.3.0
# async-timeout==4.0.3
# attrs==23.2.0
# bitarray==2.9.2
# blinker==1.8.2
# cachetools==5.3.3
# certifi==2024.6.2
# charset-normalizer==3.3.2
# ckzg==1.0.2
# click==8.1.7
# cytoolz==0.12.3
# eth-account==0.11.2
# eth-hash==0.7.0
# eth-keyfile==0.8.1
# eth-keys==0.5.1
# eth-rlp==1.0.1
# eth-typing==4.3.1
# eth-utils==4.1.1
# eth_abi==5.1.0
# frozenlist==1.4.1
# gitdb==4.0.11
# GitPython==3.1.43
# hexbytes==0.3.1
# idna==3.7
# Jinja2==3.1.4
# jsonschema==4.22.0
# jsonschema-specifications==2023.12.1
# lru-dict==1.2.0
# markdown-it-py==3.0.0
# MarkupSafe==2.1.5
# mdurl==0.1.2
# multidict==6.0.5
# numpy==1.26.4
# packaging==24.1
# pandas==2.2.2
# parsimonious==0.10.0
# pillow==10.3.0
# project==1
# protobuf==4.25.3
# pyarrow==16.1.0
# pycryptodome==3.20.0
# pydeck==0.9.1
# Pygments==2.18.0
# python-dateutil==2.9.0.post0
# pytz==2024.1
# pyunormalize==15.1.0
# referencing==0.35.1
# regex==2024.5.15
# requests==2.32.3
# rich==13.7.1
# rlp==4.0.1
# rpds-py==0.18.1
# six==1.16.0
# smmap==5.0.1
# streamlit==1.35.0
# tenacity==8.4.1
# toml==0.10.2
# toolz==0.12.1
# tornado==6.4.1
# typing_extensions==4.12.2
# tzdata==2024.1
# urllib3==2.2.2
# watchdog==4.0.1
# web3==6.19.0
# websockets==12.0
# yarl==1.9.4
# === PIP FREEZE (pip-24.0) ===
# aiohttp==3.9.5
# aiosignal==1.3.1
# altair==4.2.2
# async-timeout==4.0.3
# attrs==23.2.0
# base58==2.1.1
# bitarray==2.9.2
# blinker==1.8.2
# cachetools==5.3.3
# certifi==2024.6.2
# charset-normalizer==3.3.2
# click==8.1.7
# cytoolz==0.12.3
# entrypoints==0.4
# eth-abi==2.2.0
# eth-account==0.5.9
# eth-hash==0.7.0
# eth-keyfile==0.5.1
# eth-keys==0.3.4
# eth-rlp==0.2.1
# eth-typing==2.3.0
# eth-utils==1.9.5
# frozenlist==1.4.1
# gitdb==4.0.11
# gitpython==3.1.43
# hexbytes==0.3.1
# idna==3.7
# importlib-metadata==7.1.0
# ipfshttpclient==0.7.0
# jinja2==3.1.4
# jsonschema==3.2.0
# lru-dict==1.3.0
# markdown-it-py==3.0.0
# markupsafe==2.1.5
# mdurl==0.1.2
# multiaddr==0.0.9
# multidict==6.0.5
# netaddr==1.3.0
# numpy==2.0.0
# packaging==24.1
# pandas==2.2.2
# parsimonious==0.8.1
# pillow==10.3.0
# -e file:///code/testrepo
# protobuf==3.20.3
# pyarrow==16.1.0
# pycryptodome==3.20.0
# pydeck==0.9.1
# pygments==2.18.0
# pympler==1.0.1
# pyrsistent==0.20.0
# python-dateutil==2.9.0.post0
# pytz==2024.1
# requests==2.32.3
# rich==13.7.1
# rlp==2.0.1
# setuptools==70.0.0
# six==1.16.0
# smmap==5.0.1
# streamlit==1.22.0
# tenacity==8.4.1
# toml==0.10.2
# toolz==0.12.1
# tornado==6.4.1
# typing-extensions==4.12.2
# tzdata==2024.1
# tzlocal==5.2
# urllib3==2.2.2
# validators==0.28.3
# varint==1.0.2
# watchdog==4.0.1
# web3==5.23.0
# websockets==9.1
# yarl==1.9.4
# zipp==3.19.2

# removing either numpy or streamlit brings web3 up to 6.19.0
# dependencies = [
#     "numpy",
#     "web3"
# ]
# === PIP FREEZE (pip-24.0) ===
# aiohttp==3.9.5
# aiosignal==1.3.1
# async-timeout==4.0.3
# attrs==23.2.0
# bitarray==2.9.2
# certifi==2024.6.2
# charset-normalizer==3.3.2
# ckzg==1.0.2
# cytoolz==0.12.3
# eth-account==0.11.2
# eth-hash==0.7.0
# eth-keyfile==0.8.1
# eth-keys==0.5.1
# eth-rlp==1.0.1
# eth-typing==4.3.1
# eth-utils==4.1.1
# eth_abi==5.1.0
# frozenlist==1.4.1
# hexbytes==0.3.1
# idna==3.7
# jsonschema==4.22.0
# jsonschema-specifications==2023.12.1
# lru-dict==1.2.0
# multidict==6.0.5
# numpy==2.0.0
# parsimonious==0.10.0
# project==1
# protobuf==5.27.1
# pycryptodome==3.20.0
# pyunormalize==15.1.0
# referencing==0.35.1
# regex==2024.5.15
# requests==2.32.3
# rlp==4.0.1
# rpds-py==0.18.1
# toolz==0.12.1
# typing_extensions==4.12.2
# urllib3==2.2.2
# web3==6.19.0
# websockets==12.0
# yarl==1.9.4
# === UV PIP FREEZE (uv 0.2.12) ===
# aiohttp==3.9.5
# aiosignal==1.3.1
# async-timeout==4.0.3
# attrs==23.2.0
# bitarray==2.9.2
# certifi==2024.6.2
# charset-normalizer==3.3.2
# ckzg==1.0.2
# cytoolz==0.12.3
# eth-abi==5.1.0
# eth-account==0.11.2
# eth-hash==0.7.0
# eth-keyfile==0.8.1
# eth-keys==0.5.1
# eth-rlp==1.0.1
# eth-typing==4.3.1
# eth-utils==4.1.1
# frozenlist==1.4.1
# hexbytes==0.3.1
# idna==3.7
# jsonschema==4.22.0
# jsonschema-specifications==2023.12.1
# lru-dict==1.2.0
# multidict==6.0.5
# numpy==2.0.0
# parsimonious==0.10.0
# -e file:///code/testrepo
# protobuf==5.27.1
# pycryptodome==3.20.0
# pyunormalize==15.1.0
# referencing==0.35.1
# regex==2024.5.15
# requests==2.32.3
# rlp==4.0.1
# rpds-py==0.18.1
# toolz==0.12.1
# typing-extensions==4.12.2
# urllib3==2.2.2
# web3==6.19.0
# websockets==12.0
# yarl==1.9.4

# removing either numpy or streamlit brings web3 up to 6.19.0
# dependencies = [
#     "streamlit",
#     "web3"
# ]
# === PIP FREEZE (pip-24.0) ===
# aiohttp==3.9.5
# aiosignal==1.3.1
# altair==5.3.0
# async-timeout==4.0.3
# attrs==23.2.0
# bitarray==2.9.2
# blinker==1.8.2
# cachetools==5.3.3
# certifi==2024.6.2
# charset-normalizer==3.3.2
# ckzg==1.0.2
# click==8.1.7
# cytoolz==0.12.3
# eth-account==0.11.2
# eth-hash==0.7.0
# eth-keyfile==0.8.1
# eth-keys==0.5.1
# eth-rlp==1.0.1
# eth-typing==4.3.1
# eth-utils==4.1.1
# eth_abi==5.1.0
# frozenlist==1.4.1
# gitdb==4.0.11
# GitPython==3.1.43
# hexbytes==0.3.1
# idna==3.7
# Jinja2==3.1.4
# jsonschema==4.22.0
# jsonschema-specifications==2023.12.1
# lru-dict==1.2.0
# markdown-it-py==3.0.0
# MarkupSafe==2.1.5
# mdurl==0.1.2
# multidict==6.0.5
# numpy==1.26.4
# packaging==24.1
# pandas==2.2.2
# parsimonious==0.10.0
# pillow==10.3.0
# project==1
# protobuf==4.25.3
# pyarrow==16.1.0
# pycryptodome==3.20.0
# pydeck==0.9.1
# Pygments==2.18.0
# python-dateutil==2.9.0.post0
# pytz==2024.1
# pyunormalize==15.1.0
# referencing==0.35.1
# regex==2024.5.15
# requests==2.32.3
# rich==13.7.1
# rlp==4.0.1
# rpds-py==0.18.1
# six==1.16.0
# smmap==5.0.1
# streamlit==1.35.0
# tenacity==8.4.1
# toml==0.10.2
# toolz==0.12.1
# tornado==6.4.1
# typing_extensions==4.12.2
# tzdata==2024.1
# urllib3==2.2.2
# watchdog==4.0.1
# web3==6.19.0
# websockets==12.0
# yarl==1.9.4
# === UV PIP FREEZE (uv 0.2.12) ===
# aiohttp==3.9.5
# aiosignal==1.3.1
# altair==5.3.0
# async-timeout==4.0.3
# attrs==23.2.0
# bitarray==2.9.2
# blinker==1.8.2
# cachetools==5.3.3
# certifi==2024.6.2
# charset-normalizer==3.3.2
# ckzg==1.0.2
# click==8.1.7
# cytoolz==0.12.3
# eth-abi==5.1.0
# eth-account==0.11.2
# eth-hash==0.7.0
# eth-keyfile==0.8.1
# eth-keys==0.5.1
# eth-rlp==1.0.1
# eth-typing==4.3.1
# eth-utils==4.1.1
# frozenlist==1.4.1
# gitdb==4.0.11
# gitpython==3.1.43
# hexbytes==0.3.1
# idna==3.7
# jinja2==3.1.4
# jsonschema==4.22.0
# jsonschema-specifications==2023.12.1
# lru-dict==1.2.0
# markdown-it-py==3.0.0
# markupsafe==2.1.5
# mdurl==0.1.2
# multidict==6.0.5
# numpy==1.26.4
# packaging==24.1
# pandas==2.2.2
# parsimonious==0.10.0
# pillow==10.3.0
# -e file:///code/testrepo
# protobuf==4.25.3
# pyarrow==16.1.0
# pycryptodome==3.20.0
# pydeck==0.9.1
# pygments==2.18.0
# python-dateutil==2.9.0.post0
# pytz==2024.1
# pyunormalize==15.1.0
# referencing==0.35.1
# regex==2024.5.15
# requests==2.32.3
# rich==13.7.1
# rlp==4.0.1
# rpds-py==0.18.1
# six==1.16.0
# smmap==5.0.1
# streamlit==1.35.0
# tenacity==8.4.1
# toml==0.10.2
# toolz==0.12.1
# tornado==6.4.1
# typing-extensions==4.12.2
# tzdata==2024.1
# urllib3==2.2.2
# watchdog==4.0.1
# web3==6.19.0
# websockets==12.0
# yarl==1.9.4
@zanieb
Copy link
Member

zanieb commented Jun 18, 2024

Hi! Can you add lower bounds to any of your dependencies? It's very hard to choose which package to backtrack on and any heuristic improves one case at the cost of others. See also #4333 and #1398

@zanieb zanieb added question Asking for clarification or support resolver Related to the package resolver labels Jun 18, 2024
@wakamex
Copy link
Author

wakamex commented Jun 18, 2024

This is a contrived example to show that something is broken. Adding lower bounds seems like it would make it more contrived?

The repo this broke on has a much longer dependency list, which took me a while to sort through to narrow it down to these 3 as the cause. See our pyproject.toml here: https://github.com/delvtech/agent0/blob/main/pyproject.toml.

I want the latest compatible version of everything, as I do in our repo (don't think this is a rare use-case). Pip finds 6.19.0, while uv fails to find a recent compatible version and just keeps back-searching until it somehow resolves to a really old version.

I guess I could set the expected pip solution of 6.19.0 as the lower bound? Then it should just fail?

Just tried it, and guess what? It successfully installs the expected version. Seems like a bug somewhere. Why wouldn't uv just try the latest release of web3 first? Are there different levels of compatibility that it somehow dismisses 6.19.0 as less compatible than 3.16.3?

dependencies = [
    "eth-typing",
    "numpy",
    "streamlit",
    "web3>=6.19.0"
]
# === PIP FREEZE (pip-24.0) ===
# aiohttp==3.9.5
# aiosignal==1.3.1
# altair==5.3.0
# async-timeout==4.0.3
# attrs==23.2.0
# bitarray==2.9.2
# blinker==1.8.2
# cachetools==5.3.3
# certifi==2024.6.2
# charset-normalizer==3.3.2
# ckzg==1.0.2
# click==8.0.4
# cytoolz==0.12.3
# eth-abi==5.1.0
# eth-account==0.11.2
# eth-hash==0.7.0
# eth-keyfile==0.8.1
# eth-keys==0.5.1
# eth-rlp==1.0.1
# eth-typing==4.3.1
# eth-utils==4.1.1
# frozenlist==1.4.1
# gitdb==4.0.11
# gitpython==3.1.43
# hexbytes==0.3.1
# idna==3.7
# importlib-metadata==7.1.0
# jinja2==3.1.4
# jsonschema==4.22.0
# jsonschema-specifications==2023.12.1
# lru-dict==1.2.0
# markupsafe==2.1.5
# multidict==6.0.5
# numpy==2.0.0
# packaging==24.1
# pandas==2.2.2
# parsimonious==0.10.0
# pillow==10.3.0
# -e file:///code/testrepo
# protobuf==5.27.1
# pyarrow==16.1.0
# pycryptodome==3.20.0
# pydeck==0.9.1
# pympler==1.0.1
# python-dateutil==2.9.0.post0
# pytz==2024.1
# pyunormalize==15.1.0
# referencing==0.35.1
# regex==2024.5.15
# requests==2.32.3
# rlp==4.0.1
# rpds-py==0.18.1
# semver==3.0.2
# six==1.16.0
# smmap==5.0.1
# streamlit==1.9.0
# toml==0.10.2
# toolz==0.12.1
# tornado==6.4.1
# typing-extensions==4.12.2
# tzdata==2024.1
# tzlocal==5.2
# urllib3==2.2.2
# validators==0.28.3
# watchdog==4.0.1
# web3==6.19.0
# websockets==12.0
# yarl==1.9.4
# zipp==3.19.2

@zanieb
Copy link
Member

zanieb commented Jun 18, 2024

Just tried it, and guess what? It successfully installs the expected version. Seems like a bug somewhere. Why wouldn't uv just try the latest release of web3 first?

That's usually the case because you've constrained the problem space of the resolver. If there isn't a lower bound on dependencies it is possible for the resolver to backtrack in an unexpected way due to transitive constraints added by other dependencies. The resolution we're producing is "valid" with the given constraints, just not expected or ideal. I'd highly recommend taking a look at the linked issues as there's a lot of detail about how the resolver can get in situations like this.

@zanieb
Copy link
Member

zanieb commented Jun 18, 2024

To be clear, we want to improve the behavior of the resolver in cases like this but it's an open research problem what the best way to do so is.

@wakamex
Copy link
Author

wakamex commented Jun 18, 2024

using -v 2>&1 | grep -E "Selecting: |Adding transitive dependency" tells an interesting story:

  • select numpy 2.0 which just came out
  • start scrolling back through streamlit versions from 1.35.0 which has numpy>=1.19.3, <2
  • settle on streamlit 1.22.0 which has 'numpy*'
  • consider web3==6.19.0 but rule it out because its protobuf>=4.21.6 clashes with streamlit's protobuf>=3.12, <4
  • settle on web3 5.23.0 which has 'protobuf>=3.10.0, <4'

so it's the timeless problem of "should we have upper bounds" wherein we favor older versions that are sure to work versus ruling out compatibility with future versions that might work.

EDIT: pip choose to backtrack through numpy, which scores a hole in one in this case
EDIT2: I wanted to see if pip does something smart like "choose to backtrack on numpy because it released a major version 2 days ago and is most likely to be the one causing problems" but instead it collects the latest version of the 3 deps, fails, then uses a sorted key to choose the next step. in this case, the requested_order is the tie-breaker, so it backtracks on numpy as the first item on the list.

{'not requires_python': True, 'not direct': False, 'not pinned': True, 'not backtrack_cause': True, 'inferred_depth': 1.0, 'requested_order': 0, 'not unfree': True, 'identifier': 'numpy'}
{'not requires_python': True, 'not direct': False, 'not pinned': True, 'not backtrack_cause': True, 'inferred_depth': 1.0, 'requested_order': 1, 'not unfree': True, 'identifier': 'streamlit'}
{'not requires_python': True, 'not direct': False, 'not pinned': True, 'not backtrack_cause': True, 'inferred_depth': 1.0, 'requested_order': 2, 'not unfree': True, 'identifier': 'web3'}

@charliermarsh
Copy link
Member

If the goal is to have behavior that’s closer to pip, we may be able to close this as a duplicate of #3149 which would give us more similar “requested order” behavior.

In general though, if you’re seeing a resolution that gives you packages with lower versions that o you’d like, I still think the right solution is to add a lower bound. pip and uv could change heuristics at any time which could lead to a different resolution. If a resolution isn’t matching what you want, it makes sense to encode that in your constraints.

@wakamex
Copy link
Author

wakamex commented Jun 18, 2024

I definitely learned more about dependency resolution. Seems like this is just a difference in approach.

There's a fundamentally different approach to dependency resolution, if I understand it correctly:

  • pip checks the latest version of all deps, then backtracks on listed order in case of a version mismatch (numpy in this case)
  • uv checks deps one at a time, in listed order, and backtracks on the first package that results in a version mismatch (streamlit in this case)

Both are arbitrary, just in different ways. I think I'd prefer backtracking on "most recent version" across all chosen packages. That would consistently pick numpy in this example, irrespective of listed order. However that requires having access to release date, which I'm not sure is even in the metadata. As well, pip's approach of fetching all packages before backtracking makes more sense to me, so you could find the "most recent version" reliably, without impact from listed order. If uv had a slower "bleeding edge" resolution mode that did this, I'd probably choose that for my personal projects where my aim is to try out the latest version of everything and help teams with issues as they arise.

My team is going to add lower bounds, and possibly upper bounds, going forward. So in practice that solves our problem. Feel free to close.

@notatallshaw
Copy link
Contributor

notatallshaw commented Jun 18, 2024

  • pip checks the latest version of all deps, then backtracks on listed order in case of a version mismatch (numpy in this case)

It's a little more complicated than that for pip. Pip does indeed first do a breadth first search of the direct dependencies, check for the latest of each, but after that it does a depth first search of the transitive dependencies.

For example, pip will have a very different behavior if instead of having these dependencies in a requirements.txt you put them as dependencies in a pyproject.toml and install that package, these will now be treated as transitive dependencies (as the only direct dependency is now the package) and pip will do a depth first search for them immediately.

So there are many situations where pip can end up also installing really old versions of a package, and the advise is the same from pip, constrain your dependencies by adding reasonable lower bounds.

@zanieb zanieb closed this as completed Jun 18, 2024
@wakamex
Copy link
Author

wakamex commented Jun 18, 2024

pip will have a very different behavior if instead of having these dependencies in a requirements.txt you put them as dependencies in a pyproject.toml and install that package, these will now be treated as transitive dependencies (as the only direct dependency is now the package) and pip will do a depth first search for them immediately.

Seems that's not the case as my tests above where all with pyproject.toml, unless something else is going on. I agree pip's approach is basically equally arbitrary, and not superior in general. They just seem to have a different way of parsing "requested order".

@zanieb
Copy link
Member

zanieb commented Jun 18, 2024

Thanks for doing some investigation! We appreciate it.

@notatallshaw
Copy link
Contributor

Seems that's not the case as my tests above where all with pyproject.toml, unless something else is going on. I agree pip's approach is basically equally arbitrary, and not superior in general. They just seem to have a different way of parsing "requested order".

Well there is a big different between direct and transitive dependencies for pip, you will get "nicer" behavior when they are direct dependencies, such as pulled from a requirements.txt. I'm looking at ways to improve this, so pip can understanding if there is only 1 candidate for a package,to treat its dependencies as direct dependencies when resolving.

But also you're right, the ordering of transitive requirements is different, also resolvelib (the resolution library for pip) has less situations where it has to exhaust all candidates of a particular requirement compared pubgrub-rs (the resolution library for uv).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Asking for clarification or support resolver Related to the package resolver
Projects
None yet
Development

No branches or pull requests

4 participants