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

Support per-requirements overrides (--install-option and --global-option flags) #2208

Open
numshub opened this issue May 16, 2018 · 33 comments
Assignees
Labels
Contributor Candidate The issue has been identified/triaged and contributions are welcomed/encouraged. Type: Enhancement 💡 This is a feature or enhancement request.

Comments

@numshub
Copy link
Contributor

numshub commented May 16, 2018

The problem

Since version 7.0 pip allows the usage of --global-option and --install-option individually for each requirement in requirements.txt (https://pip.pypa.io/en/stable/reference/pip_install/#per-requirement-overrides).

It is in principle possible to use environmental variables (PIP_INSTALL_OPTION and PIP_GLOBAL_OPTION), but they are propagated to all dependencies usually ending up in a failed install.

Required feature

Honor the install-option and global-option fields in Pipfile.

Due to the way this is implemented in pip, several space-separated arguments should be tranlasted into multiple --install-option / --global-option flags.

Example

[Pipfile]
...
apackage={version = "*", install-option = "--arg1 --arg2"}
...

[requirements.txt]
...
apackage --install-option="--arg1" --install-option="--arg2"
...

@techalchemy
Copy link
Member

It would be helpful to see a use case here, I don't think any of us are eager to make fundamental changes to any parts of the spec. Since you are proposing a change to the pipfile spec you should file an issue against https://github.com/pypa/pipfile

For documentation purposes I'd be curious about the use case, but I'm probably going to close this and encourage you to file this against the pipfile repo

@numshub
Copy link
Contributor Author

numshub commented May 18, 2018

Thanks for the feedback.

I run into this issue while installing dd.
It is a typical example of a package that can optionally install cython extensions by passing a flag to pip (--fetch in this specific case).

Providing the same flag directly on the command line or as an environmental variable will fail as it propagates the flag to all dependencies (as documented here).

I will file an issue on https://github.com/pypa/pipfile as suggested.

@bjarchi
Copy link

bjarchi commented May 24, 2018

I'm not sure this is the same issue but I think it is, so here's another (possible) use case that doesn't seem to be supported with current syntax I can find documented:

The cleanest way I have found to use system-installed pyqt(5) in a venv is to install vext.pyqt5, which basically installs shims to use the system copy of pyqt5 in the virtual environment. For some reason this package does not play nice when installed from wheel - and I agree this is probably a bug in the package that should be addresssed - so in a classic venv workflow you would install with:

pip install --no-binary vext.pyqt5 vext.pyqt5

I have confirmed that using this variant of the install command works (on previous pip versions it would apparently have been --no-use-wheel). Unfortunately I cannot find any way to specify this package in my Pipfile and have it get installed when I spin up an environment. I've tried things along the line of this:
"vext.pyqt5" = "*"
and
"vext.pyqt5" = {version = "*", install-option = "--no-binary vext.pyqt5"}

I have not had any success with this in my Pipfile when I try to initially create an environment using pipenv install. I get a warning about the failed package installation, a notice that it's retrying, this appears to succeed (the command finishes w/o error), and the package is listed as installed but non-functional.

Interestingly: if I leave this out of my Pipfile initially, and then after installing the rest of the environment I use pipenv install vext.pyqt5 to install the package, that command reports a (test?) error but I get an entry added to my Pipfile and a functional package. This can be verified by, e.g., import pyqtgraph in my context.

I recognize that in this case it may be addressable by correcting some issue in the vext.pyqt5 package, but I still think it's another argument for adding this kind of argument to the Pipfile spec - and I will add this comment to an issue on the Pipfile repo if/when that happens.

Edit: seems that the vext author is aware of this as a (non)-problem since 2016 - vext-python/vext#37 - maybe I should open/reopen the issue there since it now is an issue for pipenv initialization?

I didn't want to paste the full error message above because it's long, but here's the relevant part from pipenv install vext.pyqt5:

...
  Requirement already satisfied: ruamel.yaml>=0.11.10 in /usr/local/Cellar/pipenv/2018.5.18/libexec/lib/python3.6/site-packages (from vext>=0.5.21) (0.15.37)
  Checking .pth file support in build/bdist.macosx-10.12-x86_64/wheel/
  /Users/jbarchi/.local/share/virtualenvs/spectros_algo-60Hjheru/bin/python3.6 -E -c pass
  TEST FAILED: build/bdist.macosx-10.12-x86_64/wheel/ does NOT support .pth files
  error: bad install directory or PYTHONPATH

  You are attempting to install a package to a directory that is not
  on PYTHONPATH and which Python does not read ".pth" files from.  The
  installation directory you specified (via --install-dir, --prefix, or
  the distutils default setting) was:

      build/bdist.macosx-10.12-x86_64/wheel/

  and your PYTHONPATH environment variable currently contains:

      '<snip>'

  Here are some of your options for correcting the problem:
...

@bjarchi
Copy link

bjarchi commented May 25, 2018

@techalchemy Any thoughts on this use case? I realize it is an issue with the package, but in my experience there are a number of useful packages out there that require specific pip options to install cleanly so I think there's some utility in having this ability.

Also, should I file a separate issue for the fact that the package installs functionally (albeit with apparent error) when using pipenv install package but not when using pipenv install to initially create the environment?

@uranusjr
Copy link
Member

Personally I feel at least no-binary should be supported because it is needed quite often. Maybe we can make the option better (use TOML mapping instead of specifying raw pip arguments), but we should have something.

@techalchemy
Copy link
Member

Do environment variables not work here? PIP_NO_BINARY=:vext:

@uranusjr
Copy link
Member

Aw, yes, now I think of it, PIP_NO_BINARY already covered that use case. We (somebody) should compile a list of possible install options, and see if there are alternatives for them (and if not, discuss what we can do to cover the use case). This would work well as a page in the documentation, too.

@dmitriyshashkin
Copy link

Is there a way to put environment variables into the pipfile? Specifying them manually doesn't seem like a good solution. It would be extremely easy to forget what set of variables were used and end up with a different install from the same pipfile

@uranusjr
Copy link
Member

@dmitriyshashkin Good point. Again, we’d probably need to plan this in a more comprehensive way.

@bjarchi
Copy link

bjarchi commented May 31, 2018

EDIT: Original comment preserved below, but I no longer think the vext.pyqt5 issue is related to installing with --no-binary vs. not. Reasons:

  • 0.5.21 still errors on pipenv install even with `PIP_NO_BINARY=vext.pyqt5 [or :vext.pyqt5:]
  • 0.7.0 installs OK from within pipenv shell without PIP_NO_BINARY (and works) but does not work (and errors) when installed via pipenv install
  • 0.7.0 apparently installs ok via pipenv install --sequential with the package late in my dependency spec
    • But still does not function
  • 0.7.0 installs and functions after pipenv uninstall vext.pyqt5 && pipenv install vext.pyqt5 - but only when these commands are run from within the pipenv shell
    • Error on install when pipenv install vext.pyqt5 is run from main shell (outside venv subshell) after environment is initialized.

My best analysis at this point suggests two issues: vext.pyqt5 may not be properly declaring dependencies (hence error when not installed using --sequential), and it seems to be doing something that requires the environment to be active in order to install correctly.

At this point I'm not sure if this merits its own issue. The whole point of the vext system is to selectively break the barrier between venv and system for specific packages, pipenv/Pipfile seem to be the next evolutionary step in environment management, and (this) vext package doesn't play well with the normal install procedures.

At this point my options seem to be either --site-packages + PIP_IGNORE_INSTALLED or keeping template Pipfile/Pipfile.lock in VCS and instructing users to copy them locally before the two-stage install. I would appreciate advice as to whether I should open an issue to track this specific behavior.

-- Original comment--

Do environment variables not work here? PIP_NO_BINARY=:vext:

I admit I was not aware of this option, but unfortunately I just tried it and it does not appear to work in this case.

Snippet (using fish)

$ set -x PIP_NO_BINARY ":vext.pyqt5:"
$ pipenv install
...
Updated Pipfile.lock (e7a3de)!
Installing dependencies from Pipfile.lock (e7a3de)…
  🐍   ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 20/20 — 00:00:17
An error occurred while installing vext.pyqt5==0.7.0! Will try again.
Installing initially–failed dependencies…
Success installing vext.pyqt5==0.7.0! 0/1 — 00:00:00
  ☤  ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 1/1 — 00:00:00
To activate this project's virtualenv, run the following:
...

This is the same output I got before, and while it appears to succeed on the second try it does not result in a functionally installed package (as evidenced by >>>import pyqtgraph failing with a failure to find Qt).

Unfortunately vext.pyqt5 was recently bumped from 0.5.21 to 0.7.0, and with 0.7.0 it doesn't seem like anything I do results in a functional interface anymore - although it no longer has the error on binary install? It may be that vext is more trouble than it's worth.

@uranusjr uranusjr added the Category: Future Issue is planned for the future. label Jun 6, 2018
@jcushman
Copy link

I just wanted to add another example of why it's very useful to specify the equivalent of --no-binary in the pipfile.

There's an issue right now with the package "hiredis" where a new maintainer joined the project and added binary wheels for a three-year-old release, so the pipfile.lock hashes stopped matching. This is all probably fine and good (and I don't mean to criticize that particular maintainer for being helpful!), but for a while it was unclear whether the binary wheels were legitimate -- and it's still not 100% clear, as the original maintainer is asking people to confirm that the wheels match the source.

So while that issue sorts itself out, I would like to keep the original hashes and make sure that hiredis installs from source across all deployments. The pipfile is by far the preferable place to make sure that happens -- doing it otherwise basically requires wrapping pipenv in a custom script.

@gabrielcs
Copy link

gabrielcs commented Sep 11, 2018

One more use case: to install LightGBM with GPU support. Following @numshub's syntax it would look like:
lightgbm={version="*", install-option="--gpu"}

@timbess
Copy link

timbess commented Oct 30, 2018

Do environment variables not work here? PIP_NO_BINARY=:vext:

So it's okay for pipenv install to blow up and not work unless they know to set PIP_NO_BINARY every time they install a project? This makes pipenv a lot less useful to me. The big selling point was that you can just open a project and run pipenv install to get everything working.

Say what you will about javascript, but I've never seen anyone have to do NPM_NO_BINARY=:all: NPM_GPU=1 NPM_FETCH=1 npm install.

As a side node, --no-binary is pretty important when installing scientific libraries as well. Pip supports such a wide range of options that it makes sense to me that there would be a way to pass arbitrary options to pip.

@techalchemy
Copy link
Member

Making a post asking us about whether it’s ok for pipenv to blow up is not very productive. Obviously if a command fails instead of succeeds, as a user, you just had a negative experience.

On the other hand, someone needs to actually think about the solution, approach, and implementation and propose that in an enhancement proposal PR to the peeps folder at the root of the repository. If you want my opinion, I personally find the UX aspect persuasive enough to be willing to review implementation details. Not sure if Kenneth wil agree that environment variables are as burdensome as you say.

Consider this: anything we implement now, we will be stuck with forever. We err on the side of not implementing things that have solutions or workarounds unless the UI/UX is sufficiently bad. As a maintainer, I have to pay for poorly thought out implementations in maintenance overhead later

@timbess
Copy link

timbess commented Oct 31, 2018

I intended it more as a rhetorical question to demonstrate that environment variables aren't a viable solution for these issues. If it's required to be set to build successfully, it should be somehow represented in the configuration.

@rgov
Copy link

rgov commented Jan 7, 2019

I did not see an issue in the Pipfile repo to hash out the spec, so I filed: pypa/pipfile#115

My use case: The Protobuf package contains a C++ extension which has a crashing bug. I could work around it by building from master with the --cpp_implementation build option.

@PatTheMav
Copy link

PatTheMav commented Apr 9, 2019

Here's another use case that I can't specify in the Pipfile:

To make uWSGI work with PyPy, both need to use the same libraries. uWSGI will use system libraries, whereas portable PyPy will use its own (e.g. OpenSSL 1.1.1 vs the system's OpenSSL 1.1.0j). As PyPy is loaded as a library into the uWSGI process, this will fail due to library mismatches.

The easiest fix is to run UWSGI_PROFILE=pypyonly pip install uwsgi --no-binary uwsgi which makes pip install uWSGI from sources, using the pypyonly profile (which excludes additional libraries). The Wheel variant is always built using another profile, so UWSGI_PROFILE is not applied.

@cdhagmann
Copy link

cdhagmann commented Apr 17, 2019

Here's another use case:
pip install python-ldap \ --global-option=build_ext \ --global-option="-I$(xcrun --show-sdk-path)/usr/include/sasl"

This works to install python-ldap on MacOS

@crifan
Copy link

crifan commented May 10, 2019

my use case:

pip3 install pycurl==7.43.0.1 --global-option="--with-nss" --upgrade --no-cache-dir

so using pipenv to install, expect support something like this:

PIP_INSTALL_OPTION="--global-option='--with-nss' --upgrade --no-cache-dir" pipenv install pycurl==7.43.0.1

@felix-ht
Copy link

felix-ht commented Jun 4, 2019

my usecase to install gdal:
pip install GDAL==$(gdal-config --version) --global-option=build_ext --global-option=-I/usr/include/gdal

@thehesiod
Copy link

btw, perhaps one way around this is by loading .env during pipenv install ? Then you can specify things like PIP_NO_BINARY, however that would not be module specific

@clusterrun
Copy link

my usecase to install dulwich

It allows skipping the installation of C bindings by using the --pure option:
pip install dulwich --global-option="--pure"

@mpbrown
Copy link

mpbrown commented Oct 22, 2019

My use case is installing django-compressor

On Windows, django-compressor's dependencies throw Visual C++ extension errors even though the required extensions are installed. Issue: rcssmin and rjsmin do not install These install options allow it to install without c extensions.

pip install rcssmin --install-option="--without-c-extensions"
pip install rjsmin --install-option="--without-c-extensions"

Without install options for pipenv, we are forced to use a requirements.txt file. Thus we are currently using pipenv only for managing a virtual environment rather than managing packages, making our install documentation more complicated than pipenv aspires to be.

@polidore
Copy link

polidore commented Jul 7, 2020

just went through this installing lightgbm with gpu support.

@soar
Copy link

soar commented Apr 9, 2021

Any news?

1 similar comment
@mvtm-dn
Copy link

mvtm-dn commented Apr 21, 2021

Any news?

@guillaumedsde
Copy link

Hi 👋

Another use case for this feature would be the ability to statically compile psycopg2.

@matteius
Copy link
Member

matteius commented Sep 7, 2022

You will see in the next pipenv release the support for passing additional arguments into pip install. From reading the use cases in this thread I believe that will solve for it: #5283

@matteius matteius added the Status: Awaiting Update ⏳ This issue requires more information before assistance can be provided. label Sep 7, 2022
@rummik
Copy link

rummik commented Oct 27, 2022

You will see in the next pipenv release the support for passing additional arguments into pip install. From reading the use cases in this thread I believe that will solve for it: #5283

Unfortunately, that still doesn't seem to provide a way to supply arguments to pip from package definitions in the Pipfile, otherwise it would be a usable workaround for pipenv not having an equivalent to the per-requirement options in requirements.txt (in particular --install-option and --global-option, but it looks like may be more since this issue was opened)

See: https://pip.pypa.io/en/stable/reference/requirements-file-format/#per-requirement-options

@matteius
Copy link
Member

matteius commented Nov 5, 2022

@rummik Thanks for the explanation.

@matteius matteius added Type: Enhancement 💡 This is a feature or enhancement request. Contributor Candidate The issue has been identified/triaged and contributions are welcomed/encouraged. and removed Status: Awaiting Update ⏳ This issue requires more information before assistance can be provided. Category: Future Issue is planned for the future. labels Nov 5, 2022
@matteius matteius self-assigned this Nov 5, 2022
@bernd-k1337
Copy link

@matteius Is there any progress or other way to use the --global-option?

@matteius
Copy link
Member

@bernd-k1337 sorry, I had kind of lost track of this issue -- I see I self assigned it, but perhaps others in the community could take this on -- I was chatting with @CNDW recently, and perhaps this would be of interest to him, or if not, maybe someone else could take it on: if no one gets to it by October (Hacktoberfest) I'll make a bigger push to do something myself.

@CNDW
Copy link

CNDW commented Jun 28, 2023

I can take a look at this one once I get some free time this week 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Contributor Candidate The issue has been identified/triaged and contributions are welcomed/encouraged. Type: Enhancement 💡 This is a feature or enhancement request.
Projects
None yet
Development

No branches or pull requests