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

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

Closed
sbidoul opened this issue Apr 3, 2021 · 12 comments
Closed

Comments

@sbidoul
Copy link
Member

sbidoul commented Apr 3, 2021

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 sbidoul changed the title Make --no-binary build a wheel locally instead of calling setup.py install Deprecate legacy setup.py install when --no-binary is used Apr 3, 2021
@sbidoul sbidoul changed the title Deprecate legacy setup.py install when --no-binary is used Make --no-binary build a wheel locally instead of calling setup.py install Apr 3, 2021
@xavfernandez
Copy link
Member

xavfernandez commented Apr 16, 2021

--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.

@pradyunsg
Copy link
Member

pradyunsg commented Apr 17, 2021

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.

@sbidoul
Copy link
Member Author

sbidoul commented Apr 17, 2021

@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 (#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.

@xavfernandez
Copy link
Member

xavfernandez commented Apr 19, 2021

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 👍

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.

@groodt
Copy link
Contributor

groodt commented May 2, 2021

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?

@pradyunsg
Copy link
Member

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. :)

@groodt
Copy link
Contributor

groodt commented May 4, 2021

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?

@pfmoore
Copy link
Member

pfmoore commented May 4, 2021

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...)

@groodt
Copy link
Contributor

groodt commented May 4, 2021

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.

@pradyunsg
Copy link
Member

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.

@tomashek
Copy link

tomashek commented May 5, 2021

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?

@sbidoul
Copy link
Member Author

sbidoul commented Sep 17, 2022

Superseded by #11358, #11451, #11453.

@sbidoul sbidoul closed this as completed Sep 17, 2022
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Oct 18, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants