Imagine I have two packages foo and bar where foo is a dependency of bar. foo is already installed and I now want to pip installbar. Is it possible to do that without upgrading foo? In particular I want to install the latest version of bar that is satisfied with the already installed version of foo.
From pip help install
--upgrade-strategy <upgrade_strategy>
Determines how dependency upgrading should be handled
[default: only-if-needed]. "eager" - dependencies are
upgraded regardless of whether the currently installed
version satisfies the requirements of the upgraded
package(s). "only-if-needed" - are upgraded only when
they do not satisfy the requirements of the upgraded
package(s).
As far as I see this only covers the cases “always update” and “only update if needed”, but not “never update” as I need it.
I believe pip install bar (no upgrade flags at all) should do what you want. pip should pick the currently-installed foo unless bar explicitly says that version is not compatible.
If you add --use-feature=2020-resolver, I believe pip would even try to find a version of bar that can work with the currently-installed foo. You can read more about the 2020 resolver here.
pip should pick the currently-installed foo unless bar explicitly says that version is not compatible.
That is true, but the whole problem arises because the latest version of bar requires a newer version of foo. foo is expensive to download and install and I don’t have a special requirement for bar. Thus, I just want the latest version of bar that I can run with foo.
If you add --use-feature=2020-resolver , I believe pip would even try to find a version of bar that can work with the currently-installed foo .
That kinda works. In that case the command would look like this:
$ pip install --use-feature=2020-resolver $(python -c "import foo; print(f'{foo.__name__}=={foo.__version__}')") bar
Unfortunately this downloads every single version of bar until it finds a match. Example: foo==chardet and bar==requests:
$ pip install chardet==3.0.0
[...]
$ pip install --use-feature=2020-resolver $(python -c "import chardet; print(f'{chardet.__name__}=={chardet.__version__}')") requests
Requirement already satisfied: chardet==3.0.0 in ./.venv/lib/python3.6/site-packages (3.0.0)
Collecting requests
Using cached requests-2.24.0-py2.py3-none-any.whl (61 kB)
Collecting requests
Using cached requests-2.23.0-py2.py3-none-any.whl (58 kB)
Collecting requests
Using cached requests-2.22.0-py2.py3-none-any.whl (57 kB)
Collecting requests
Using cached requests-2.21.0-py2.py3-none-any.whl (57 kB)
Collecting requests
Using cached requests-2.20.1-py2.py3-none-any.whl (57 kB)
Collecting requests
Using cached requests-2.20.0-py2.py3-none-any.whl (60 kB)
Collecting requests
Using cached requests-2.19.1-py2.py3-none-any.whl (91 kB)
Collecting requests
Using cached requests-2.19.0-py2.py3-none-any.whl (91 kB)
Collecting requests
Using cached requests-2.18.4-py2.py3-none-any.whl (88 kB)
Collecting requests
Using cached requests-2.18.3-py2.py3-none-any.whl (88 kB)
Collecting requests
Using cached requests-2.18.2-py2.py3-none-any.whl (88 kB)
Collecting requests
Using cached requests-2.18.1-py2.py3-none-any.whl (88 kB)
Collecting requests
Using cached requests-2.18.0-py2.py3-none-any.whl (563 kB)
Collecting requests
Using cached requests-2.17.3-py2.py3-none-any.whl (87 kB)
Collecting requests
Using cached requests-2.17.2-py2.py3-none-any.whl (87 kB)
Collecting requests
Using cached requests-2.17.1-py2.py3-none-any.whl (87 kB)
Collecting requests
Using cached requests-2.17.0-py2.py3-none-any.whl (87 kB)
Collecting requests
Using cached requests-2.16.5-py2.py3-none-any.whl (87 kB)
Collecting requests
Using cached requests-2.16.4-py2.py3-none-any.whl (87 kB)
Collecting requests
Using cached requests-2.16.3-py2.py3-none-any.whl (86 kB)
Collecting requests
Using cached requests-2.16.2-py2.py3-none-any.whl (86 kB)
Collecting requests
Using cached requests-2.16.1-py2.py3-none-any.whl (85 kB)
Collecting requests
Using cached requests-2.16.0-py2.py3-none-any.whl (85 kB)
Collecting requests
Using cached requests-2.15.1-py2.py3-none-any.whl (558 kB)
Installing collected packages: requests
Successfully installed requests-2.15.1
As I said before, in my actual case bar is expensive to download and thus this is not a feasible approach.
If you must avoid download, your only choice is to specify bar’s version yourself. Python packaging does not provide a way to discover version conflicts before downloading a package, so pip has no way to know what version of bar without trying to download various versions it can use unless you tell it explicitly.
Thanks for the insight! I’ve asked this question at Stack Overflow before I did here. Do you want to provide your answer there? If not, are you OK if I cite you and answer myself?