pip
pip copied to clipboard
Make --no-binary build a wheel locally instead of calling setup.py install
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 tosetup.py install
- when
--no-binary
is used with the feature flag, build a wheel from the sdist (via PEP 517 orsetup.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 theinstall
command, as well as inrequirement.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
--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 meansetup.py install
) -
--no-binary
withno-binary-allows-setuptools-install
set would allow the use of bdist_wheel and wheel caching -
--no-binary
withno-binary-forces-setuptools-install
set would not produce any warning and would force the current behavior of forcingsetup.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
withno-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
withno-binary-forces-setuptools-install
would still force the current behavior of forcingsetup.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.
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.
@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.
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 meansetup.py install
) -
--no-binary
withno-binary-allows-setuptools-install
set would allow the use of bdist_wheel and wheel caching -
--no-binary
withno-binary-forces-setuptools-install
set would not produce any warning and would force the current behavior of forcingsetup.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 meansetup.py install
) ---global-option
withno-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
withno-binary-forces-setuptools-install
set would not produce any warning and would force the current behavior of forcingsetup.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
withno-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
withno-binary-forces-setuptools-install
would still force the current behavior of forcingsetup.py install
(and yield a warning about the going away feature flag) -
--global-option
withno-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
withno-binary-forces-setuptools-install
would still force the current behavior of forcingsetup.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 install
anymore.
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:
-
pip wheel --no-binary -r requirements.txt ./dist
(resolve and prepare a folder of wheels from source) -
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
?
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. :)
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?
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...)
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.
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.
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?
Superseded by #11358, #11451, #11453.