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

Open up plat/abi/impl options to install --target #5404

Merged
merged 1 commit into from
Aug 12, 2018

Conversation

lorencarvalho
Copy link
Contributor

Summary:

  • Move dist restriction options to be re-usable (between install/download)
  • Make dist restriction options usable in install (exclusively with --target)
  • Add a check_supported_wheels bool to RequiriementSet for non-resolved (full path) dependencies

Greetings pip maintainers!

This is an implementation of the suggestions in #5355 - @pfmoore suggested that allowing a user to circumvent the local compatibility checks would be allowable only in the case of using --target, and I agree completely.

One part that may be controversial is that this diff also adds the --platform, --abi, --python & --implementation args to the install command. Though it is constrained to only if --target is being used. This is purely for convenience sake, so that users who wish to install with --target don't have to make multiple invocations of pip (e.g. pip download and then pip install --target $dir ./wheel1.whl ./wheel2.whl etc).

One thing I'm a little iffy on is the test suite, I looked at similar tests and tried to adhere to their style and convention, but I needed an additional wheel and I'm not certain how they were created (the wheels with mocked pep425 names). What I ended up doing was copying one of them and simply changing the file's name. I imagine there's a better way?


Here's some examples of the UX:

using --target and dist options:

pip install \
--target /tmp/test \
--python-version 36 \
--platform manylinux1_x86_64 \
--abi cp36m \
--implementation cp \
--only-binary :all: \
Cython numpy

output:

Collecting Cython
  Using cached https://files.pythonhosted.org/packages/19/eb/c4d9f3beafd5ac0615936860bcee41d93ca58f8734a16715da0037d2c468/Cython-0.28.2-cp36-cp36m-manylinux1_x86_64.whl
Collecting numpy
  Using cached https://files.pythonhosted.org/packages/71/90/ca61e203e0080a8cef7ac21eca199829fa8d997f7c4da3e985b49d0a107d/numpy-1.14.3-cp36-cp36m-manylinux1_x86_64.whl
Installing collected packages: Cython, numpy
Successfully installed Cython-0.28.2 numpy-1.14.3

trying to use dist options w/o specifying --target:

pip install \
--python-version 36 \
--platform manylinux1_x86_64 \
--abi cp36m \
--implementation cp \
--only-binary :all: \
Cython numpy

output:

ERROR: Can not use any platform or abi specific options unless installing via '--target'

All the usual dist-related error messages are preserved, for example, not specifying --only-binary:

pip install \
--target /tmp/test \
--python-version 36 \
--platform manylinux1_x86_64 \
--abi cp36m \
--implementation cp \
Cython numpy
ERROR: When restricting platform and interpreter constraints using --python-version, --platform, --abi, or --implementation, either --no-deps must be set, or --only-binary=:all: must be set and --no-binary must not be set (or must be set to :none:).

So as you can see, it's not a terribly drastic change in terms of behavior, but does alter the --help output of install and opens up potential avenues for users to break things in interesting ways, so I understand any reticence to the change and am very receptive to ideas on how to strike a balance between ease-of-support, ease-of-use & this functionality.

Looking forward to discussion
-Loren

@kornpow
Copy link

kornpow commented May 15, 2018

I commented on #5355 also, but wanted to repost here too. This feature sounds like exactly what I need!

Hi I have been fighting basically this issue for a while now. I am using the Resin.io service, which uses a cross-compiling build system in order to build a docker container for a Raspberry Pi device. However their build systems run on armv8l, and I'm looking to install for the armv6l for the Pi Zero W. I've knocked into this issue multiple times working with this platform. I think in terms of ARM wheels, Docker containers, and cross compilation, where there is more weirdness and incompatibilities between architectures something like the above solutions would be a great improvement.

@lorencarvalho
Copy link
Contributor Author

I tried running the test suite on a windows machine and couldn't reproduce the errors from AppVeyor, not sure what's going on there if anyone has an insight I'm all ears

@pradyunsg
Copy link
Member

Might have been a transient issue?

@pradyunsg pradyunsg closed this May 16, 2018
@pradyunsg pradyunsg reopened this May 16, 2018
@pradyunsg
Copy link
Member

(closed-opened to re-trigger the builds)

@pradyunsg pradyunsg added the S: needs triage Issues/PRs that need to be triaged label May 16, 2018
@lorencarvalho
Copy link
Contributor Author

👋 just offering a friendly ping

@pradyunsg
Copy link
Member

Hey @sixninetynine! :)

I don't have the bandwidth currently to review this PR (or any non-trivial PR for that matter). I'll get to this soon though. Sorry to keep you waiting.

@lorencarvalho
Copy link
Contributor Author

@pfmoore would love your opinion on the discussion happening in #5453 and how it relates to this PR. Specifically the notion that merely including dist options in the install command accounts for the explicitness of the request.

I'm perfectly happy removing the --target requirement (and in fact, I think it makes the diff a little cleaner), but of course I defer to the maintainers.

cc @chriskuehl & @asottile

@pfmoore
Copy link
Member

pfmoore commented May 31, 2018

Personally, I see the two use cases as different. This PR is saying "I want to manage packages for a specific platform/abi/impl, which is not the same as the current environment", whereas #5453 is about allowing the user to describe the current environment's compatibility in terms of non-default unique tags (ones that don't match any of the standard sets). As the use cases differ, I'd rather the UIs differed as well.

To put it another way, I see this PR as being about allowing certain carefully chosen commands to call pep425tags.get_supported() with non-default platform/abi/implementation values. But #5453 is about wanting pep425tags.get_platform() to return a custom value. My feeling is that a plain pip install (that installs code which will be imported into the current environment) should always ensure that what is installed matches pep425tags.get_supported() with default arguments. That's the best way we have of ensuring that what's installed is executable.

I believe there have been previous discussions about having finer-grained ways of describing your environment, fitting between manylinux (highly generic) and "linux" (basically machine-specific). There may even be a mechanism in place. I don't have specifics, unfortunately (see below - I don't really know much about this area of Linux). That sounds pretty close to what #5453 is trying to achieve.

Disclaimer: Personally, I use Windows and #5453 is not really an issue there. So I'm probably not the best person to have an opinion here. My comments above are from a general perspective of making sure we get pip's UI right, but someone with a Linux background may feel differently.

@asottile
Copy link
Contributor

I'm not sure they're all that different. I believe (correct me if I'm wrong) the primary usecase of this PR is to be able to build a site-packages from a disparate architecture / platform and deploy it (think: running pip on macos, but zipping up the site-packages and then running it in aws lambda).

On darwin, manylinux1_x86_64 would be just as different to the list of pep425tags.get_supported() as would linux_ubuntu_16_04_x86_64 on the return value of a linux_x64_64 machine.

@pfmoore
Copy link
Member

pfmoore commented May 31, 2018

@asottile Yes, but the point is that you specify a target directory, precisely because the stuff you want to zip up is incompatible with what's in site-packages. #5453 is, as I understand it, about describing what you consider to be compatible with site-packages.

@asottile
Copy link
Contributor

One of the usecases also mentioned in #5453 is identical to this one -- being able to build a virtualenv for an alternate platform direct link to the discussion also linked there

@pfmoore
Copy link
Member

pfmoore commented May 31, 2018

I see this PR as a better solution to that problem. I'm pretty strongly of the opinion that being able to do

$ pip install --platform linux foo
$ pip install --platform win_amd64 bar

which puts mutually incompatible binaries into site-packages, is wrong. Doing the same with --target is OK, because you have to deliberately choose to use the same target directory, and you can't import from the target location without deliberately choosing to do so.

Basically, I'd rather see #5453 be implemented as a configuration, that says "this environment conforms to platform tag XXX". That's my impression of how previous discussions on this topic have gone.

But as I've said, this is a Linux-related issue, and I'm not a Linux specialist, so I've said what I want to - from this point, I'll leave it to others to decide on how to proceed.

@asottile
Copy link
Contributor

I was under the impression that the same requirements that were added for pip download were explicit enough here (as to not require a more complex UX here).

That is, I think it's very explicit that running pip install --platform ... --only-binary :all: ... you're asking pip to do a very specific action -- yes most of the time for the specific usecase (that both issues touch on) you'd want to use --target.

I agree that it's possible for someone to put mutually incompatible binaries into site-packages.
But that's not different from what's being proposed here as someone could just as easily pip install --target ... --platform X && pip install --target ... --platform Y in just the same way. This is also the status quo for the very same pip download command (which itself doesn't require a --target either):

$ pip download --only-binary :all: --platform macosx_10_10_x86_64 numpy
...
Successfully downloaded numpy
$ pip download --only-binary :all: --platform manylinux1_x86_64 numpy
...
Successfully downloaded numpy
$ ls
numpy-1.14.3-cp27-cp27m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl
numpy-1.14.3-cp27-cp27m-manylinux1_x86_64.whl

What I hope to convince is that requiring --target doesn't actually solve the potential mixing problem described. But that's ok! Because a user would have to be type a very-explicit incorrect command to end up there in the first place.

An aside: if this is implemented without requiring --target this also probably partially solves #3689.

@kornpow
Copy link

kornpow commented Jun 1, 2018

Wanted to give a little more information about how I am currently getting around this problem.
Problem: Install python program from Dockerfile, where the builder of the Docker container could be ARMv8 or ARMv6, and ARMv6 is the target.

arch_test.py:
This program checks build architecture, and if it isnt armv6 it renames the wheel to trick pip install
arch_test.py.txt

Install command:

pip3 download -r /requirements.txt --only-binary=:all: --python-version 34 --implementation cp --abi cp34m --platform=linux_armv6l --extra-index-url https://www.piwheels.org/simple -v -d /usr/src/app/wheels1 && python3 arch_test.py /usr/src/app/wheels1/ && pip3 install /usr/src/app/wheels1/*

Not sure if that helps anything. I'd like to specify --platform during pip install even if it meant install to another folder and not site-packages. Then in my code I could use site.addsitedir(target_dir)

Ideal use case:

pip3 download -r /requirements.txt --only-binary=:all: --python-version 34 --implementation cp --abi cp34m --platform=linux_armv6l --extra-index-url https://www.piwheels.org/simple -v -d /usr/src/app/wheels1 && pip3 install /usr/src/app/wheel1/* --python-version 34 --implementation cp --abi cp34m --platform=linux_armv6l --target /usr/src/app/builder-packages

@lorencarvalho
Copy link
Contributor Author

lorencarvalho commented Jun 4, 2018

OK, I just want to summarize the current status of this PR and our options...

This PR, as it stands, adds the "dist" options (--platform, --implementation, --abi, --python-version) to the install subcommand only when --target is also in use. This is a simple implementation of the feature I requested in #5355. The restriction to --target was requested there and I have no qualms with it since that fits my use case.

@chriskuehl, @asottile & @sako0938 have since commented regarding a similar feature request #5453 and suggest that this feature would be more useful if not restricted only to the --target use case. The argument being that merely using the dist options alone is explicit enough of a signal to the user, and using --target unnecessarily limits the usability of the feature.

I have no qualms updating this PR to remove the restriction on --target. I also have no qualms adding the dist options to the wheel subcommand (as requested in #5453), and in fact it'd be easy since I moved the dist options to already be resuable in cmdoptions.py -- but, I'd like some more input from pip maintainers, as it seems we are at a bit of an impasse.

Thanks in advance!

@lorencarvalho
Copy link
Contributor Author

I started a thread on distutils-sig to discuss the implications of this PR and what direction to go in.

Quoting @ncoghlan :

The basic idea seems like a good one to me, and starting out with the --target restriction doesn't hurt - it's much easier to relax restrictions like that later than it is to figure out whether or not you've correctly handled all the edge cases that arise without them.

I think this sounds good, especially the point about it being easier to loosen restrictions later.

The main automatic implication I would personally expect to see is that specifying any of those options also imply "--only-binary :all:" (rather than requiring it to be passed in separately). That could wait to a follow-up PR though (since the current PR just throws an error in that case).

I think this is ok as well, given that using these commands without specifying --only-binary raises the usual (expected) error.

@lorencarvalho
Copy link
Contributor Author

@pradyunsg offering a friendly ping, given the above updates

Copy link
Member

@pradyunsg pradyunsg left a comment

Choose a reason for hiding this comment

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

Appreciate the ping. Just read up on this PR and the related discussions.

LGTM functionally, based on a visual review of the diff on GitHub's UI. I'll take it for a spin sometime today.

@@ -60,6 +61,42 @@ def getname(n):
)


def check_dist_restriction(options, check_target=False):
"""Function for determinming if custom platform options are allowed.
Copy link
Member

Choose a reason for hiding this comment

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

typo.

@@ -406,6 +443,61 @@ def only_binary():
)


def platform():
return Option(
Copy link
Member

Choose a reason for hiding this comment

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

The pattern in this file is to use functools.partial for this unless there's a mutable value involved. Staying consistent with that would be nice.

@@ -13,6 +13,7 @@
from pip._internal.exceptions import (
CommandError, InstallationError, PreviousBuildDirError,
)
from pip._internal.index import FormatControl
Copy link
Member

Choose a reason for hiding this comment

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

Unnecessary import.

As a side note, could you rebase on master? There's a bunch of CI related improvements (including reenabling checking of unused imports).

assert distinfo in result.files_created

# Test install without --target
result = script.pip(
Copy link
Member

Choose a reason for hiding this comment

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

This result isn't being used in any way. I'd suggest adding a check for the exit code immediately after.

Out the back of my head, I think expect_error lets a test pass even if there's no errors. If that's the case, the above would be needed anyway. :)

assert distinfo in result.files_created

# Test a full path requirement (without --target)
result = script.pip(
Copy link
Member

Choose a reason for hiding this comment

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

As above.

not options.ignore_dependencies
)

if dist_restriction_set and no_sdist_dependencies:
Copy link
Member

Choose a reason for hiding this comment

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

I know it wasn't there originally but adding a comment that explains why these error messages are raised would be appreciated.

])

binary_only = FormatControl(set(), {':all:'})
no_sdist_dependencies = (
Copy link
Member

Choose a reason for hiding this comment

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

naming: sdist_dependencies_allowed

@pradyunsg pradyunsg added type: feature request Request for a new feature and removed S: needs triage Issues/PRs that need to be triaged labels Jun 19, 2018
@lorencarvalho
Copy link
Contributor Author

@pradyunsg thanks for the review! updated the diff per your comments and rebased as well.

@lorencarvalho
Copy link
Contributor Author

@pradyunsg any chance this could make it into #5516 ? :)

@pradyunsg
Copy link
Member

I'm not 100% comfortable being the only one to review and merge since I'm not completely familiar with the nuances involved here. Maybe someone else from @pypa/pip-committers who's more familiar could review this.

As for making into 18.0, I don't think we'd block 18.0 for this -- I'm fine if this has to wait until 18.1. It's definitely nicer if it doesn't have to wait. :)

@BrownTruck BrownTruck added the needs rebase or merge PR has conflicts with current master label Jul 24, 2018
@pfmoore
Copy link
Member

pfmoore commented Jul 24, 2018

159 additional commits - did a rebase get done incorrectly?

@pypa-bot pypa-bot removed the needs rebase or merge PR has conflicts with current master label Jul 24, 2018
@lorencarvalho
Copy link
Contributor Author

@pfmoore haha, yep, I royally borked it up. Fixing now

@lorencarvalho lorencarvalho force-pushed the feature/platforms_for_target branch 2 times, most recently from 8bac0fb to f0777e8 Compare July 24, 2018 15:26
@BrownTruck
Copy link
Contributor

Hello!

I am an automated bot and I have noticed that this pull request is not currently able to be merged. If you are able to either merge the master branch into this pull request or rebase this pull request against master then it will eligible for code review and hopefully merging!

@BrownTruck BrownTruck added the needs rebase or merge PR has conflicts with current master label Jul 30, 2018
@lorencarvalho
Copy link
Contributor Author

@pfmoore @pradyunsg before I resolve these conflicts, what are the next steps for this PR?

@pradyunsg
Copy link
Member

I can't speak for @pfmoore -- I just haven't find the time to take a deeper dive to actually review this properly; until now.

These changes as they stand, look good to me.

@pradyunsg pradyunsg added this to the 18.1 milestone Aug 3, 2018
@pfmoore
Copy link
Member

pfmoore commented Aug 4, 2018

Changes look OK to me

Copy link
Member

@pfmoore pfmoore left a comment

Choose a reason for hiding this comment

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

Looks OK once merge conflicts resolved

@pradyunsg
Copy link
Member

Cool.

So, the next step is to fix the merge conflicts and ping us. :)

@pypa-bot pypa-bot removed the needs rebase or merge PR has conflicts with current master label Aug 5, 2018
* Move dist restriction options to be re-usable (between install/download)
* Make dist restriction options usable in `install` (exclusively with --target)
* Add a check_supported_wheels bool to RequiriementSet for non-resolved (full path) dependencies
@lorencarvalho
Copy link
Contributor Author

thanks @pradyunsg & @pfmoore
I appreciate y'all being so patient with me, sorry for any pestering :)

@pradyunsg pradyunsg merged commit 20127bf into pypa:master Aug 12, 2018
@chadrik
Copy link

chadrik commented Aug 13, 2018

This fixes exactly the issue I was just trying to solve. When can we expect a new release of pip?

Thanks for all the hard work!

@benoit-pierre
Copy link
Member

@chadrik: October.

@lorencarvalho
Copy link
Contributor Author

@chadrik you can always install from master too:

python3 -m pip install --upgrade git+git://github.com/pypa/pip.git#egg=pip

@chadrik
Copy link

chadrik commented Aug 13, 2018 via email

@pradyunsg
Copy link
Member

Thanks for the PR @sixninetynine! Much appreciated. :)

@lock
Copy link

lock bot commented Jun 1, 2019

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot added the auto-locked Outdated issues that have been locked by automation label Jun 1, 2019
@lock lock bot locked as resolved and limited conversation to collaborators Jun 1, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
auto-locked Outdated issues that have been locked by automation type: feature request Request for a new feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants