pypa / pip

The Python package installer
https://pip.pypa.io/
MIT License
9.36k stars 2.98k forks source link

Require minimum pip version #11118

Open ax3l opened 2 years ago

ax3l commented 2 years ago

What's the problem this feature will solve?

Pip continues to ship breaking changes. That is fine, it's great that it moves forward as a project, but we need some control to which pip versions downstream projects support without manual steps for our users.

For instance, in pip 22.1 the following breaking changes came in:

In order to not break CI and user workflows uncontrollably on release days of pip, we need a way to express the supported pip range, e.g., in pyproject.toml #4145

Describe the solution you'd like

Let projects somewhere declare the working pip versions, so we have a chance to adopt to the breaking changes.

Alternative Solutions

I currently only have a way forward, documenting all my users to always use the latest pip because I use pip embedded in complex build scripts.

I probably can try to transition complex build logic away from pip and use build and packaging once they are mature?

Additional context

Code of Conduct

pfmoore commented 2 years ago

If your production build processes use pip, and you're not able to react to pip changes in a timely manner, then why don't you pin the version of pip that you use? That's a genuine question, and I appreciate that the answer might be nothing more than "we never bothered in the past, and it's a lot of work to change it now". But it would be really useful for us to properly understand whether there are genuine technical reasons why pinning a pip version won't work, as opposed to just where it's a bunch of work that you don't want to do (for genuine reasons - again, I'm not suggesting "just pin pip" is a trivial thing for you to do).

My feeling is that pinning pip is probably perfectly sufficient for most people, but it's a lot of work (changing scripts that create virtualenvs to explicitly reinstall the exact version of pip you want, forcing CI environments to use a precise pip version rather than "whatever comes out of the box", etc etc). So they carry on taking the risk, and mostly being OK, but get frustrated when a change does break something.

I probably can try to go away from pip and use build and packaging once they are mature?

The design exercise of working out where you're using pip to do builds (i.e., where it would be replaced with build) and where you're using it just to install wheels (where you could replace it with installer) would be useful in any case. My impression is that the breakage you're concerned about is almost entirely around builds, and if you knew which invocations of pip were to do builds, you could probably just pin those invocations of pip, which might be easier.

It's unlikely that there's much point in changing pip's deprecation policy much - your issue here seems to be more with the fact that we make changes at all than because you'd find longer deprecation periods helpful. And having pip read pyproject.toml and somehow ensure that the right version of pip is used sounds really hard (we'd need pip to know all about what command line flags were intruduced when, etc, so that we could reliably invoke a different version of pip, for example). So realistically, we'd need some confirmation that the amount of work needed for a feature like this genuinely is less than the cost of projects pinning pip when they need to.

potiuk commented 2 years ago

100% agree with @pfmoore .

Agree it's annoying when options disappear, but ranges of pip version is a nightmare for pip maintainers. That would be hell of a complexity and I believe the goal of pip maintainers (a very good one IMHO) is to more-or-less gently push everyone to upgrade to latest version of pip as fast as humanly possible (I perfectly understand that - we do the same with Airflow).

Providing the users with "escape hatch" and being able to effectively forever pin to lower versions of pip is 100% against that goal actually - because ... it will NOT make people migrate to new versions as soon as possible. In fact it will make them migrate as late as possible - which is totally opposite to the goal.

The solution is easy and we use it in Airflow.

See PR merged today: https://github.com/apache/airflow/pull/23665

Simply fix pip version used in CI - this will give you expected stability for your CI. Then setup notification to see when new version of pip is released an migrate to newer version explicitly soon after (fixing all problems you will encounter). Pip is an important tool and "mother" of all dependencies, so it should be rather easy to track when new version is released (or you can rely on warnings generated in pip). And it takes quite a bit of time for your users to start using it - so you should have quite enough time to fix any problems introduced by changes in pip.

dstufft commented 2 years ago

Practically speaking pip can’t upgrade or downgrade the currently running process. It can upgrade or downgrade the files on disk that make up the current process, but the current process is more or less fixed without a lot of really fragile work.

It wouldn’t be hard to add a pip version constraint that pip checked, but because of the above, the only reasonable thing pip could do is error out if the version doesn’t match. That’s maybe a valuable thing as it lets people that are making things that users clone and then run against fail in a more obvious way.

But there isn’t a reasonable way to go from that to having pip run the correct version after pip has already started.

Sent from my iPhone

On May 12, 2022, at 6:23 PM, Jarek Potiuk @.***> wrote:

 100% agree with @pfmoore .

Agree it's annoying when options disappear, but ranges of pip version is a nightmare for pip maintainers. That would be hell of a complexity and I believe the goal of pip maintainer (a very good one IMHO) is to more-or-less gently push everyone to upgrade to latest version of pip as fast as humanly possible (I perfectly understand that - we do the same with Airflow).

Providing the users with "escape hatch" and being able to effectively forever pin to lower versions of pip is 100% against that goal actually - because ... it will NOT make people migrate to new versions as soon as possible. In fact it will migrate them as late as possible - which is totally opposite to the goal.

The solution is easy and we use in Airflow.

See PR merged today: apache/airflow#23665

Simply fix pip version used in CI - this will give you expected stability for your CI. Then setup notification to see when new version of pip is released an migrate to newer version explicitly soon after (fixing all problems you will encounter). Pip is an important tool and "mother" of all dependencies, so it should be rather easy to track when new version is released (or you can rely on warnings generated in pip). And it takes quite a bit of time for your users to start using it - so you should have quite enough time to fix any problems introduced by changes in pip.

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you are subscribed to this thread.

pradyunsg commented 2 years ago

And, with that constraint, the only thing that’s possible is that pip errors out if it’s outside of the specified range. This has two problems/consequences:

pradyunsg commented 2 years ago

One thing I’d be fine with is a pip CLI flag (that also means you can set a env var or use pip’s configuration flags) that makes pip error out if the version isn’t right. Older versions will still ignore this.

This will be scoped for the pip run, which can be configured for the machine or environment basis, rather than on a per-project basis. That feels more appropriate and in-line with what’s being requested. Would this work for such a use case?

ax3l commented 2 years ago

I would already be happy if I can specify that I need a minimal version of pip and that pip errors out if that minimal version is not found, and prints the usual self-note how to self-update to users.

Yes, that won't be caught by versions of pip released today, but it will make things clearer in the future.

I cannot follow why reading a corresponding toml section in pyproject.toml is described as very complicated.

ax3l commented 2 years ago

For CI, pinning pip is a valid choice.

With regards to future transition options, like the strongly recommended --use-feature advertising for in-tree-builds: I really think that if you want to people to use these flags, do not error out once they become default (but warn that they are now superfluous). People need a few releases to remove them again and there is literally no harm - that way, people can adopt to new features and do not break once it becomes default. It widens the pip versions they can work with.

After all, I am not only talking CI scripts here. These are also workflow documentations that application and library developers have to update for users, etc. Some systems in sensitive areas are only updated once in a blue moon (and are not connected to the internet), so application and library developers need to keep docs and scripts for those as well. The more one can automate there the better.

There’s not much functional difference between a failure because a flag was removed vs a failure from pip because something you want has been removed. The error message is different, which may or may not be useful.

Agreed. If one automation is to clearly fail because the workflow requires a newer pip - then I think that is fine, transparent, and actionable. A user knows what to do (upgrade pip), they get no guidance what to do for the current error (upgrade? downgrade?) and maintainers have little chance to express known too-old releases. The case "too-old" is very common, as pip introduces new features (build time deps, resolvers, etc.) and user-facing workflows start to rely on them.

pradyunsg commented 2 years ago

With regards to future transition options, like the strongly recommended --use-feature advertising for in-tree-builds: I really think that if you want to people to use these flags, do not error out once they become default (but warn that they are now superfluous).

FWIW, the flag was kept around an extra release or two, before removal.

There's a cost to keeping things around for a long time but that is significantly greater for the opt-out case rather than the opt-in case.

potiuk commented 2 years ago

IMHO it's a very good idea to remove those flags immediately even if it is annoying. It's just delaying the inevitable removal and has very little benefits.

From a pure social engineering and 'shaping your users behaviours' POV it is the best approach IMHO.

For CI and automation scripts - use pinning. This - by nature - can be centrally managed - and allow those who contribute to the code to manage it for everyone. This is actually cool because this way pip maintainers effectively delegate the 'upgrade as soon as you can to the maintainers of the projects that are using them. And those '3rd party product maintainers' are incentives to migrate to newer versions because their users might use the new version for manual pip commands and you - as a maintainer - have no real control on which version they have so you have to upgrade fast.

Removing the flags immediately after they become defaults, actually pretty much forces the maintainers to pin pip in their CI and upgrade as soon as new version is released when you think of it. That's the only sustainable way. They have not much choice. If it stayed there for a few releases, the 'pinning' incentive for CI would be far weaker and would break the mechanism.

On the other hand those feature flags are only intended to be used by adding new features and allowing those maintainers to update their CI to test if the new features do not break things. They should almost never be used by the users of projects that use pip. And almost never should regular users be 'used to' using those flags.

If you try to get into the shoes of pip maintainers - this is really best way. Even of it is slightly annoying for you as the maintainer of your project, the benefit for the whole community which can move faster and use best practices introduced by pip far outweigh the individual annoyance ( and are also good for you and your users in a long run).

This is - IMHO - super smart way to achieve the goal of "make the users of 'pip' to upgrade asap". It's actually brilliant. As a product maintainer I am - rather gently but firmly - forced to do the right thing. On one hand as i know that next pip release might break CI of main, on the other hand because I know my users might use new pip version soon after it is released. Delaying the removal would make this mechanism much weaker.

I have to bring some of that to our Airflow processes :)

,

henryiii commented 2 years ago

On the second point, --no-build-isolation checking for dependencies is great (because it bring this inline with pypa/build), but it does need an opt-out; one of the (several) reasons to disable build isolation is because you are setting up a specific environment that is not allowed by pyproject.toml; a very common case is if you require cmake and ninja, but Conda-forge's cmake and ninja do not install the corresponding Python packages. Another one is if the package authors tightly pin build requirements, but you are building in Pyodide or some other environment where you only have one version available. So having it check by default is nice, but there does have to be a way to opt-out.

Looking at the help text, I don't see an obvious way to disable it.

For reference, here's build's options:

  --skip-dependency-check, -x
                        do not check that build dependencies are installed
  --no-isolation, -n    do not isolate the build in a virtual environment

If its missing, calling it --skip-dependency-check, -x would be perfect. :) It used to be that -xn was identical to pip's --no-build-isolation.

pradyunsg commented 2 years ago

We're going to change the build dependency checking to be opt-in, see #11116.