Closed hynek closed 4 months ago
Oh wow, that's interesting.
Thank you!
hey running into weird edge cases is my only talent ;)
I haven't figured out why yet, but something in the requirements is leading us to choose a really old version of FastAPI. Like, it looks like we first try to pin starlette
, but we start with a version that's too new for FastAPI, so then we try all the FastAPI versions, and maybe we eventually find a FastAPI version that doesn't require starlette
at all.
E.g., if you change the starlette
requirement to starlette==0.36.3
, you end up with a much better FastAPI version. Will need to think on how to hint to the resolver that this is bad.
Uh you're right. If I install using .[dev]
I get fastapi==0.1.17
. If I install uv pip install fastapi
I get fastapi==0.109.2
(I'm gonna leave editing of the bug title to you)
I have something similar happening with torchvision
, but only when installed from the cu118 repo. Running uv pip install torch torchvision --verbose --index-url https://download.pytorch.org/whl/cu118
fails. It looks like it is repeatedly selecting older versions until it hits one that has a dependency it can't resolve at all, at which point it bails.
$ uv --version
uv 0.1.3
$ python -m platform
Linux-6.7.4-arch1-1-x86_64-with-glibc2.39
Yeah, unfortunately uv is producing a valid resolution (I assume), it's just not identical to pip's because the resolver ends up taking a different path. (There are many valid resolutions, even under the constraint that you want to choose the latest available versions.) If we iterated over the packages in a different order, we might end up with the same thing. But I agree that the outcome here seems bad, and we should try to hint at the resolver to take a different path.
So this is a case where the resolution path produces a very undesirable solution, but another path produces a much more desirable one. Interesting. The main issue is probably that pubgrub doesn't explore the whole solution space and stops as soon as one solution is found. And as soon as one package is pinned it won't ever change the chosen version except if it reaches a dead-end and backtracks.
In a way, we can say that the pyproject is not correctly specified, because it says it's compatible with any fastapi version, which is not true. It's only that the current solver in pip chooses something that fits the bill. In my opinion the correct answer is to fix the dependency specification inside svcs.
However, if we think of things that can help, I imagine the order in which dependencies are specified could give an indication of the importance they have to the person who specified them. This way the priority of a package can be influenced by this order? It will definitely not generalize to all situations and for sure make the solver slower in general. So meh ...
I haven't figured out why yet, but something in the requirements is leading us to choose a really old version of FastAPI. Like, it looks like we first try to pin
starlette
, but we start with a version that's too new for FastAPI, so then we try all the FastAPI versions, and maybe we eventually find a FastAPI version that doesn't requirestarlette
at all.
I see fastapi has an upper bound on starlette: https://github.com/tiangolo/fastapi/blob/master/pyproject.toml#L44
I will again suggest that it might be better when you have two requirements and one of the packages upper bounds the other requirements that you prefer backtracking on the package that is upper bounded: https://github.com/astral-sh/uv/issues/1398#issuecomment-1947572237
With the caveat that this is my intuition on what would produce better results and I've not had a chance to try and implement it myself yet and prove it.
The main issue is probably that pubgrub doesn't explore the whole solution space and stops as soon as one solution is found
FYI, it's easy to produce a set of requirments where the whole solution space is larger than the number of atoms in the obserable universe. All real world dependency resolution algorithms will stop pretty quickly once they have a solution.
All real world dependency resolution algorithms will stop pretty quickly once they have a solution.
Indeed, what I meant to say is that some solvers have a notion of "good" solution, like SMT solvers (such as microsoft Z3). But pubgrub does not. It only has local decision making strategies. So like "what should we try NOW"? but no notion of optimality of a solution.
Could it be that this has been fixed? Or is the fix just not general enough?
pipx run --spec uv==0.1.6 uv pip install --reinstall -e .[dev]
gives me fastapi==0.1.17
pipx run --spec uv==0.1.7 uv pip install --reinstall -e .[dev]
gives me fastapi==0.109.2
Which is as of writing the latest version.
svcs which has quite… interesting… dependencies doesn't seem to flip-flop dependencies from a pip install -Ue .[dev]
anymore:
I have something similar happening with
torchvision
, but only when installed from the cu118 repo. Runninguv pip install torch torchvision --verbose --index-url https://download.pytorch.org/whl/cu118
fails. It looks like it is repeatedly selecting older versions until it hits one that has a dependency it can't resolve at all, at which point it bails.$ uv --version uv 0.1.3 $ python -m platform Linux-6.7.4-arch1-1-x86_64-with-glibc2.39
This just saved my life, i've been going crazy all day playing with rye + uv couldn't figure out why it was holding back all my packages! Thanks so much! I might make a pr over at rye
, maybe in FAQ section, that describes this scenario a bit
I've checked https://github.com/hynek/svcs at 85827a173fd7b9952abf34a8f198c7d1fb40f43d with the latest version of uv and the original problems don't occur anymore (mypy tests/typing/fastapi.py
passes successfully) and pip install --force-reinstall fastapi
gives us the same versions as uv pip install --reinstall --editable .[dev]
. I think our prioritization changes fix this.
just for completeness, as I wrote in https://github.com/astral-sh/uv/issues/1575#issuecomment-1958816302 it already worked before, but @charliermarsh mentioned it might've just been due to FastAPI releasing something new with different version constraints or something? Not saying, it's not fixed – just saying that svcs isn't a useful signal anymore. :)
I've tested with uv pip install --reinstall --editable .[dev] --exclude-newer 2024-02-17
so i'm confident this is fixed in uv rather than by external circumstances :)
I've noticed that when installing packages that contain type hints, those hints don't get installed.
For example take https://github.com/hynek/svcs
If I install the dev dependencies using
uv pip install --reinstall --editable .[dev]
I get Mypy and FastAPI installed.But, if I run
mypy tests/typing/fastapi.py
, I get:Running
pip install --force-reinstall fastapi
fixes it:Between the installations, I can observe how
$VIRTUAL_ENV/lib/python3.12/site-packages/fastapi/py.typed
is missing and appears after installing it using pip. If I reinstall using uv, it vanishes again.