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

Add support for disabling installation from pre-built wheels #956

Merged
merged 3 commits into from
Jan 19, 2024

Conversation

zanieb
Copy link
Member

@zanieb zanieb commented Jan 17, 2024

Adds support for disabling installation from pre-built wheels i.e. the package must be built from source locally.
We will still always use pre-built wheels for metadata during resolution.

Available via --no-binary and --no-binary-package <name> flags in pip install and pip sync. There is no flag for pip compile since no installation happens there.

--no-binary

    Don't install pre-built wheels.
    
    When enabled, all installed packages will be installed from a source distribution. 
    The resolver will still use pre-built wheels for metadata.


--no-binary-package <NO_BINARY_PACKAGE>

    Don't install pre-built wheels for a specific package.
    
    When enabled, the specified packages will be installed from a source distribution. 
    The resolver will still use pre-built wheels for metadata.

When packages are already installed, the --no-binary flag will have no affect without the --reinstall flag. In the future, I'd like to change this by tracking if a local distribution is from a pre-built wheel or a locally-built wheel. However, this is significantly more complex and different than pip's behavior so deferring for now.

For reference, pip's flag works as follows:

--no-binary <format_control>

    Do not use binary packages. Can be supplied multiple times, and each time adds to the
    existing value. Accepts either ":all:" to disable all binary packages, ":none:" to empty the
    set (notice the colons), or one or more package names with commas between them (no colons).
    Note that some packages are tricky to compile and may fail to install when this option is
    used on them.

Note we are not matching the exact pip interface here because it seems complicated to use. I think we may want to consider adjusting our interface for this behavior since we're not entirely compatible anyway e.g. I think --force-build and --force-build-package are clearer names. We could also consider matching the pip interface or only allowing --no-binary <package> for compatibility. We can of course do whatever we want in our own install interfaces later.

Additionally, we may want to further consider the semantics of --no-binary. For example, if I run pip install pydantic --no-binary I expect just Pydantic to be installed without binaries but by default we will build all of Pydantic's dependencies too.

This work was prompted by #895, as it is much easier to measure performance gains from building source distributions if we have a flag to ensure we actually build source distributions. Additionally, this is a flag I have used frequently in production to debug packages that ship Cythonized wheels.

@zanieb zanieb changed the title Add --no-binary and --no-binary-package <name> Add support for disabling installation from pre-built wheels Jan 17, 2024
@zanieb zanieb added the enhancement New feature or improvement to existing functionality label Jan 17, 2024
@@ -155,3 +159,33 @@ impl Display for BuildKind {
}
}
}

#[derive(Debug)]
pub enum NoBinary {
Copy link
Member Author

@zanieb zanieb Jan 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do correct me if there's somewhere better for this.

I tried to put it alongside Reinstall but it's needed in the resolver as well so I put it in this shared crate.

It's still re-exported in the installer.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems okay -- we don't have a much better / obvious answer.


/// Install a package without using pre-built wheels.
#[test]
fn install_no_binary() -> Result<()> {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests are slow (~5s). Maybe I should use a scenario that builds faster?

Copy link
Member Author

@zanieb zanieb Jan 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd also be ideal to have coverage for e.g. installing a wheel via direct URL with --no-binary (which should fail)

Comment on lines -162 to -163
// Find the most-compatible wheel
for (wheel, file) in files.wheels {
Copy link
Member Author

@zanieb zanieb Jan 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The following made conditional and indented without change.

@zanieb zanieb requested a review from charliermarsh January 18, 2024 14:43
@charliermarsh
Copy link
Member

Will review today!

@@ -2,9 +2,10 @@ pub use downloader::{Downloader, Reporter as DownloadReporter};
pub use editable::{BuiltEditable, ResolvedEditable};
pub use installer::{Installer, Reporter as InstallReporter};
pub use plan::{Plan, Planner, Reinstall};
// TODO(zanieb): Just import this properly everywhere else
pub use puffin_traits::NoBinary;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this stale / can it be removed? It looks like you are importing from puffin_traits in the various files.

Copy link
Member Author

@zanieb zanieb Jan 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah commentary at #956 (comment)

We should probably remove it and fix the imports that use this crate.

Copy link
Member

@charliermarsh charliermarsh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me, nice work. My only concern is that we now have --no-binary and --no-build which does the opposite. Should those somehow be a single flag...? Should they be marked as conflicting in some sense, since providing both excludes all distributions?

@zanieb
Copy link
Member Author

zanieb commented Jan 18, 2024

My only concern is that we now have --no-binary and --no-build which does the opposite. Should those somehow be a single flag...?

Well, pip has --no-binary <package,:all:,:none:> and --only-binary <package,:all:,:none:>. Perhaps we should change ours to match this interface?

I don't think we should explore some sort of "unified" flag in the pip-compatible interface. I think we can consider it in our own interface later.

Should they be marked as conflicting in some sense, since providing both excludes all distributions?

Yes I think we should mark them as conflicting.

@zanieb
Copy link
Member Author

zanieb commented Jan 18, 2024

Opening #977 for the first point.

@zanieb zanieb merged commit 33b35f7 into main Jan 19, 2024
3 checks passed
@zanieb zanieb deleted the zb/no-binary branch January 19, 2024 17:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or improvement to existing functionality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants