pip icon indicating copy to clipboard operation
pip copied to clipboard

Make --no-binary build a wheel locally instead of calling setup.py install

Open sbidoul opened this issue 3 years ago • 11 comments

This is one of a series of deprecations meant to collect feedback on the ultimate goal of always installing source distributions by first building a wheel and then installing from it.

This is made with the following changes:

  • add a new feature flag --use-feature=always-install-via-wheel, that is intended to become the default and only mechanism in the future
  • when --no-binary is used without the feature flag, emit a deprecation warning about the fallback to setup.py install
  • when --no-binary is used with the feature flag, build a wheel from the sdist (via PEP 517 or setup.py bdist_wheel) then install it
  • when --no-binary is used with the feature flag, the wheel that was built locally is cached (unless the cache is disabled)
  • since --install-option, --build-option and --global-option imply --no-binary, the deprecation warning will be emitted when these options are used without the feature flag
  • deprecate --install-option
  • ~allow using --build-option in the install command, as well as in requirement.txt lines, as a transitory mechanism until the ecosystem supports PEP 517 config settings, which are meant to replace both --build-options and --global-options~

Towards #8102

sbidoul avatar Apr 03 '21 10:04 sbidoul

--no-binary currently means two things:

  • in conjunction with --only-binary it impacts the source selection mechanism (whether pip installs from wheel or sdist)
  • skip the wheel building and directly skips to setup.py install.

Since we want to deprecate the second meaning I'd suggest to add two transitional (and incompatible) feature flags: no-binary-allows-setuptools-install & no-binary-allows-setuptools-install.

In pip 21.1, there would be no behavior change but:

  • using --no-binary without any of those feature flags would yield a warning about the upcoming change (and --no-binary would mean setup.py install)
  • --no-binary with no-binary-allows-setuptools-install set would allow the use of bdist_wheel and wheel caching
  • --no-binary with no-binary-forces-setuptools-install set would not produce any warning and would force the current behavior of forcing setup.py install

In pip 21.2:

  • using --no-binary alone would not yield any warning (and would allow the use of bdist_wheel and wheel caching)
  • --no-binary with no-binary-allows-setuptools-install set would allow the use of bdist_wheel and wheel caching (but maybe yield a warning about the going away feature flag)
  • --no-binary with no-binary-forces-setuptools-install would still force the current behavior of forcing setup.py install (and yield a warning about the going away feature flag).

In pip 21.3 --no-binary will mean what we want it to mean ^^

The always-install-via-wheel feature flag still makes sense and can be added at the same time but I fear the deprecation cycle will be much longer.

--install-option should also be deprecated with a newly allowed --build-option suggested as replacement but again, I think this can happen at the same time as the --no-binary disambiguation.

xavfernandez avatar Apr 16 '21 17:04 xavfernandez

That sounds good overall! I only disagree on the timelines.

We'd need longer timelines for the no-setup.py-install change too. Lots of folks are depending on the fact that they can somehow invoke setup.py install still, and we have to see what their use cases are before we say whether things will break or not.

I do think that removing things is the best way to get people to react tho, as long as we have an escape hatch that goes away in 6 months.

And, also, regarding the timeline 21.1 is like, this weekend or the next. And finally, we usually need to wait 6 months before changing the default after first communicating a change; per our deprecation policy.

pradyunsg avatar Apr 17 '21 06:04 pradyunsg

@xavfernandez thanks a lot for looking in details into this issue ! I think I initially considered something close to what you propose but then found a roadblock. I'll look again.

Have you considered the fact that, currently, using --global-options implies --no-binary ?

--no-binary currently means two things:

Additionally, it also influences use of the wheel cache (https://github.com/pypa/pip/issues/9162). When --no-binary starts building wheels I think it should cache them and use the cached wheel if one is found corresponding to the requested sdist. Just like it does when a distribution has no published wheels, and so --no-binary really mean one thing: do not download wheels. To avoid multiplying feature flags I think this should be part of the same deprecation.

sbidoul avatar Apr 17 '21 13:04 sbidoul

That sounds good overall! I only disagree on the timelines.

Fair point, I forgot about our 6 months policy 😅 .

The flags and deprecation warning would be introduced in version N (possibly 21.1 or the next), the behavior change would happen in version N+2 and flags could be definitely removed in N+4.

Additionally, it also influences use of the wheel cache

Since it currently disables the wheel building, it currently has no impact on wheel caching right ? So from my point of view, there is no deprecation needed on that front. But I totally agree with you on the fact that When --no-binary starts building wheels I think it should cache them and use the cached wheel if one is found corresponding to the requested sdist :+1:

Have you considered the fact that, currently, using --global-options implies --no-binary ?

This seems strange since --global-options is also passed to bdist_wheel, but ok I'll try to also include those option in a new proposal with updated versions.


In pip 21.1, we add two transitional (and incompatible) feature flags: no-binary-allows-setuptools-install & no-binary-forces-setuptools-install. There would be no behavior change but:

  • using --no-binary without any of those feature flags would yield a warning about the upcoming change (and --no-binary would mean setup.py install)
  • --no-binary with no-binary-allows-setuptools-install set would allow the use of bdist_wheel and wheel caching
  • --no-binary with no-binary-forces-setuptools-install set would not produce any warning and would force the current behavior of forcing setup.py install
  • using --install-option would yield a warning about it going away
  • using --global-option without any of those feature flags would yield a warning about the upcoming change (and would still mean setup.py install) ---global-option with no-binary-allows-setuptools-install set would allow the use of bdist_wheel and wheel caching (with --build-option/--global-option content as one the cache key)
  • --global-option with no-binary-forces-setuptools-install set would not produce any warning and would force the current behavior of forcing setup.py install

In pip 21.3:

  • using --no-binary alone would not yield any warning (and would allow the use of bdist_wheel and wheel caching)
  • --no-binary with no-binary-allows-setuptools-install set would allow the use of bdist_wheel and wheel caching (but maybe yield a warning about the going away feature flag)
  • --no-binary with no-binary-forces-setuptools-install would still force the current behavior of forcing setup.py install (and yield a warning about the going away feature flag)
  • --global-option with no-binary-allows-setuptools-install set would allow the use of bdist_wheel and wheel caching (with --build-option/--global-option content as one the cache key) (but maybe yield a warning about the going away feature flag)
  • --global-option with no-binary-forces-setuptools-install would still force the current behavior of forcing setup.py install (and yield a warning about the going away feature flag).
  • --install-option goes away

In pip 22.1 --no-binary will mean what we want it to mean and --global-option won't force setup.py installanymore.

xavfernandez avatar Apr 19 '21 10:04 xavfernandez

Apologies in advance for the potentially off-topic question.

I am really optimistic about a world where it is possible to always install from wheels, even for packages which do not publish wheels.

I'm hopeful that it would eventually enable a workflow such as this:

  1. pip wheel --no-binary -r requirements.txt ./dist (resolve and prepare a folder of wheels from source)
  2. pip install ./dist/*.whl --no-index (unpack wheels)

This would allow for the use of third-party pip dependencies on systems without compilers and enables easy caching of reproducible dependencies.

Am I correct in my understanding here?

Would this work for all packages, or only packages that have wheel specified in a pyproject.toml?

groodt avatar May 02 '21 03:05 groodt

I'd recommend doing something different:

  • pip download --no-binary :all:.
  • Use pypa/build (pip install build) and build the packages into a "wheelhouse" using that (and not pip wheel).
  • You can pip install exactly as described or even install from subsets, like pip install --no-index --find-link wheelhouse-path package1 package2.

That's effectively what the reproducible wheels project is going to be doing pretty soon: https://reproduciblewheels.com/

This also gives you a lot more control over the build pipeline, since you're invoking build, which has a CLI for simple use cases and provides an API for advanced use cases. OTOH, if you don't need careful control over the isolated build environments, then, yes, that should work fine. :)

pradyunsg avatar May 02 '21 06:05 pradyunsg

I'd recommend doing something different:

Thanks for the tip. Seems sensible! Is that going to be able to always build wheels, even if a package author doesn't setup their package for wheels by default?

groodt avatar May 04 '21 09:05 groodt

even if a package author doesn't setup their package for wheels by default?

I'm not sure how a package author could not "setup their package for wheels by default". They'd have to actively go out of their way to make it impossible to build wheels. (Of course, that's assuming you are able to install the package - if you;re missing a C compiler and the package includes C code, you won't be able to build a wheel, but you won't be able to install the package without a wheel either...)

pfmoore avatar May 04 '21 10:05 pfmoore

I'm not sure how a package author could not "setup their package for wheels by default".

Thats great! Yes, I'm assuming working packages that are pip installable.

I wasn't sure if PEP-517 required wheel to be specified in a pyproject.toml or something to enable the new equivalent of the old python setup.py bdist_wheel. Is Python packaging at the stage where all installations are going via an intermediate wheel stage at this point? For whatever reason, I thought they didn't all pass through this intermediate stage.

groodt avatar May 04 '21 10:05 groodt

Is Python packaging at the stage where all installations are going via an intermediate wheel stage at this point?

It's headed in that direction, but there's still a few projects that don't work that way.

pradyunsg avatar May 04 '21 10:05 pradyunsg

It has been suggested that sdists installed with "setup.py install" could be used for projects that need to include symlinks, since the wheel format does not allow them. The change in workflow to create a wheel prior to installation will break symlinks. Is there a way that can be addressed?

tomashek avatar May 05 '21 03:05 tomashek

Superseded by #11358, #11451, #11453.

sbidoul avatar Sep 17 '22 12:09 sbidoul