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

pip list --outdated should have a way to take requirements into account #9725

Closed
jribbens opened this issue Mar 22, 2021 · 16 comments
Closed
Labels
state: needs discussion This needs some more discussion type: feature request Request for a new feature

Comments

@jribbens
Copy link

What's the problem this feature will solve?

pip list --outdated is very useful, however there seems to be no way to take into account what versions your project actually needs. There is a difference between "a new minor version of this package has been released, that matches your requirements.txt and you should probably upgrade to immediately" and "a new major version of this package has been released, which you might want to refactor your code to use someday".

Basically I want a command that answers the question "what would pip install -U -r requirements.txt do, if anything, if I ran it?"

Describe the solution you'd like

e.g.

$ pip list --outdated
Package                  Version Latest  Type
------------------------ ------- ------- -----
Django                   2.2.15  3.1.7   wheel
idna                     2.10    3.1     wheel

$ pip list --outdated 'Django<3'
Package                  Version Latest  Type
------------------------ ------- ------- -----
Django                   2.2.15  2.2.19  wheel
idna                     2.10    3.1     wheel

$ cat requirements.txt
Django<3
idna<3

$ pip list --outdated -r requirements.txt
Package                  Version Latest  Type
------------------------ ------- ------- -----
Django                   2.2.15  2.2.19  wheel

Alternative Solutions

There is no way to work around this problem that I am aware of, short of creating another virtual environment, doing pip install -r requirements.txt from scratch in that new environment, doing pip list in both old and new environments, and diffing the output...

Another way of achieving the same end in a slightly less user-friendly manner would be a pip install --fetch-only or pip install -n type option, i.e. to go through the install process doing everything except the actual installation of the packages.

@uranusjr
Copy link
Member

uranusjr commented Mar 22, 2021

This has been raised numerous times. pip is a tool for interacting with a Python environment, and if you go through its commands, almost all of them involve something to manipulate an environment, or get information out of an environment. It is definitely possible for pip to implement this, but the way it does this will be exactly to create an environment, install into it, and then run pip list --outdated aganst it. Probably not what you want?

@uranusjr
Copy link
Member

Stepping back from the implementation a little, it seems like you’re quite convinced that pip “should” have this functionality. May I ask why? A tool should provide users a coherent workflow, instead of putting a bunch commands together “because it can”. What is your pip workflow that makes this a required functionality?

@jribbens
Copy link
Author

I am not understanding your comments at all I'm afraid. My suggestion is precisely a command to "get information out of an environment" (at least as much as pip list --outdated already is). I don't see why it would be implemented as you suggest, because that would not at all produce the output I have described.

I also don't understand why you doubt a command to ask "what packages could/should be updated" is not universally applicable. My workflow is unlikely to be different from anyone else's here. Why would anyone not need this command? Every time I use pip list --outdated I am surprised and confused that this option does not already exist.

@pfmoore
Copy link
Member

pfmoore commented Mar 22, 2021

IMO, the difficulty here is that pip list --outdated looks at just the installed packages, and determines what has newer versions available. It doesn't take dependencies into account at all, it's a simple compare - environment vs index.

The proposed functionality needs extra context, in the form of a set of requirements that you want to upgrade. That's a very different request (at least if you look "under the hood"). You're asking pip to look at what it would need to install to do the requested upgrade, and report that. That's not a variation on a list command, but instead it's a dry-run version of an install --upgrade. The fact that pip list doesn't currently take any sort of requirements as arguments should be a strong indication that it's for inspecting the environment, and it's not related to installation.

It's important to remember that pip is not intended as a "project management" tool, which knows what top-level dependencies you need, and manages them and tracks the installed versions that fulfil those dependencies. That functionality is provided by "higher level" projects like pipenv, poetry and pip-tools. Your proposed pip list --outdated extension sounds better suited for those tools, which maintain a holistic view of "what your project depends on".

If you were to propose that pip hand a --dry-run option for the install command, that would be much more in line with the logic of how pip's commands are structured IMO (I know that's an alternative you suggested originally, I'm saying it's better focusing on that rather than list). The request for a --dry-run flag has a long history - see #53 for the (extended) discussion - a lot of the earlier comments have been hidden because this was deferred until the introduction of the new resolver. I suspect one reason it's not gained a lot of traction is that many people use higher-level tools for this, as I mentioned above. But having said that, pip install --dry-run is IMO a reasonable feature request for pip, if someone were to want to do the work to implement it (I don't know if the pip developers will get to it ourselves if it's left to us, there's too many higher priority items that need work 🙂)

@pradyunsg
Copy link
Member

https://xkcd.com/1425/ comes to mind. :)

@jribbens
Copy link
Author

But having said that, pip install --dry-run is IMO a reasonable feature request for pip, if someone were to want to do the work to implement it

Is it not just a case then of doing what pip install already does and just stopping before actually installing the packages?

@jribbens
Copy link
Author

jribbens commented Mar 22, 2021

https://xkcd.com/1425/ comes to mind. :)

@pradyunsg ok, ye of little faith, here is a proof-of-concept implementation in a 9-line shell script:

VENV=$(python -c 'import sys; print(sys.prefix.rstrip("/"))')
TDIR=$(mktemp -d -p"$(dirname "$VENV")")
cp -pr "$VENV/" "$TDIR/"
TPY="$TDIR/"$(basename "$VENV")"/bin/python"
python -mpip list | tail +3 >"$TDIR/old-packages"
"$TPY" -mpip install -U "$@"
"$TPY" -mpip list | tail +3 >"$TDIR/new-packages"
diff -u0 "$TDIR/old-packages" "$TDIR/new-packages"
rm -r -- "$TDIR"

@uranusjr
Copy link
Member

Looks like you have a good plan for things already, maybe more than we do. Care to organise them into a pull request to save everyone time?

@pradyunsg pradyunsg added state: needs discussion This needs some more discussion type: feature request Request for a new feature labels Mar 23, 2021
@jribbens
Copy link
Author

Looks like you have a good plan for things already, maybe more than we do. Care to organise them into a pull request to save everyone time?

Probably best if you just give me direct commit access. Many thanks in advance.

@pfmoore
Copy link
Member

pfmoore commented Mar 23, 2021

Probably best if you just give me direct commit access.

I assume that's intended as sarcasm. But just to be clear, a PR should be fine - even people with commit access work via PRs.

If you don't intend to work on it yourself, I suspect the request is mostly just a duplicate of #53, at least in the sense that I've explained why I'd see --dry-run as a better fit than a pip list --outdated option, so you're more likely to get acceptance of that approach.

Either way, if we can keep the discussion constructive that would be appreciated. @jribbens I assume you didn't need to be told that your shell implementation is a bit simplistic, but if you do have an interest in expanding it into a "proper" implementation/PR, it would be very welcome. If not, it'll happen when someone does have the interest in taking it further, but I can't say when that will be.

@jribbens
Copy link
Author

I assume that's intended as sarcasm

It seemed appropriate in reply to the rather misguided and rude comment I was responding to.

I assume you didn't need to be told that your shell implementation is a bit simplistic

Of course, it was just a response to the XKCD 1425 implication that what I was suggesting was inherently not something a computer can do. Also it's a useful working demonstration of the information I am suggesting that pip should be able to output.

Is an install --dry-run option trivial to implement, or not - and if not, is it at least simple to summarise the difficulty? ;-) Unlike you guys I have never looked at the internal workings of pip, so I don't know off-hand.

@pfmoore
Copy link
Member

pfmoore commented Mar 23, 2021

Disclaimer - although I am pretty familiar with pip's internals, they are a complex mess of backward compatibility and technical debt, so most of the time, I'm just guessing until I look at the details myself 🙂

Is an install --dry-run option trivial to implement, or not - and if not, is it at least simple to summarise the difficulty?

Probably not. For a start, install itself is a complex beast, and there's also the question of what precisely a dry run would involve. Your script for example, doesn't take into account the user-site directory, "use system site" virtual environments, etc, all of which could have an impact on the implementation. They might not, but no-one will know until they look at the code.

I don't want to paralyze everything with speculation, though. Ultimately, someone will look at the code, and may come up with an easy way forward, or may find it's a lot of work. Which they can then choose to do or give up. There's no real pressure either way.

My gut feel is that it'll be messier that you initially expect, but it's not going to be impossible. And it'll probably take longer (elapsed time) that you'd hope, because people will come up with a bunch of edge cases you hadn't thought of. But there's people who can help with that stuff, once you have an initial working implementation to talk about.

@pradyunsg
Copy link
Member

pradyunsg commented Mar 24, 2021

FWIW, this should not be that tricky any more. All the recent technical debt paydown we've done, over the course of introducing the new resolver (I'm including the work from before the grant funded work too) should mean that's it's a relatively small patch. The bigger concern with this is converting whatever we get after the whole dependency resolution process, into something that's consumable by our end users.

I don't think that's usable as is though (like, those object don't really have an easily serializable form), and we're basically discussing #53 at this point. I'd suggest moving the rest of the discussion over there.

@sbidoul
Copy link
Member

sbidoul commented Jun 26, 2022

With #10771, you can do this to know what needs to be upgraded (as well as new dependencies to be installed), assuming your top level requirements are declared in a python project (pyproject.toml) in the current directory:

pip install -q --dry-run --upgrade --quiet --report - . | jq -r ".install[].metadata | [.name, .version] | @tsv"

@sbidoul
Copy link
Member

sbidoul commented Jul 15, 2022

In the OP:

Basically I want a command that answers the question "what would pip install -U -r requirements.txt do, if anything, if I ran it?"

Since this is now supported with --dry-run, and further machine-readable with --report, I'm going ahead and closing this issue.

Don't hesitate to say so if there is something else that I missed.

@sbidoul sbidoul closed this as completed Jul 15, 2022
@jribbens
Copy link
Author

Sounds good, I'll take a look when it's released to see how it compares to my imagined version ;-)

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 16, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
state: needs discussion This needs some more discussion type: feature request Request for a new feature
Projects
None yet
Development

No branches or pull requests

5 participants