Pip: Invalid `use-feature` value breaks pip

Created on 31 Jul 2020  路  12Comments  路  Source: pypa/pip

Environment

  • pip version: 20.2
  • Python version: 3.7.7
  • OS: Fedora 30

Description
I made a bad guess for the syntax of how to enable two pip features permanently, and rendered pip completely broken with a simple pip config set command.

Expected behavior
One or both of the following:

  • a syntax check when doing pip config set would reject an invalid value
  • the invalid configuration value would be a warning and still let pip continue

How to Reproduce

  1. Enable a non-existing feature using pip config set global.use-feature <feature>
  2. Try to use any pip subcommand (or just pip)
  3. Pip crashes with an error message

Output

$ pip config set global.use-feature 2020-resolver,fast-deps
Writing to /home/akaihola/.config/pip/pip.conf
$ pip
An error occurred during configuration: option use-feature: invalid choice: '2020-resolver,fast-deps' (choose from '2020-resolver', 'fast-deps')
$ pip config unset --user global.use-feature
An error occurred during configuration: option use-feature: invalid choice: '2020-resolver,fast-deps' (choose from '2020-resolver', 'fast-deps')

The work-around:

$ rm $HOME/.config/pip/pip.conf
configuration bug enhancement

Most helpful comment

I just checked, it seems like --isolated only applies to distutils config files (a historical artifact that I don鈥檛 think many ever used), not pip config files.

All pip configuration files are always loaded; you can see the function that gets those files received no flags at all:

https://github.com/pypa/pip/blob/ea10d0e253f497c9fc08097f14cdba6b94b45541/src/pip/_internal/configuration.py#L76-L96

We should have a discussion on this 馃檨 But also independent to this issue.

All 12 comments

The error originates from:https://github.com/pypa/pip/blob/930aa5c70855a150a98503119d18536f91dfcc61/src/pip/_internal/cli/parser.py#L150-L155

Perhaps we can do option.check_value(key, val), which essentially is the syntax check mentioned in the first bullet point of the expected behaviour, when setting a value via pip config set

This will avoid us from setting invalid values for valid options, and avoid such scenarios, by showing the error during pip config set

$ pip config set global.use-feature 2020-resolver,fast-deps
ERROR: An error occurred during configuration: option use-feature: invalid choice: '2020-resolver,fast-deps' (choose from '2020-resolver', 'fast-deps')

I will let other maintainers chime in with their suggestions before putting together a PR for the same.

Also, it seems that the proper way to enable multiple features is:

pip config set --user global.use-feature "                                 
  2020-resolver     
  fast-deps"

I couldn't find a way to embed the newlines on the command line in bash, but opening a double quote and hitting Enter does continue to accept additional lines of input until a closing double quote, and this results in a good pip.conf file:

[global]
use-feature = 
      2020-resolver
      fast-deps

You don鈥檛 have to use newlines; any space would do (pip just splits with str.split()).

Thanks for filing this issue @akaihola! ^>^

@deveshks's suggestion sounds good to me.

The only concern I have is: should we error out or is printing a warning sufficient? I don't think anyone depends on pip's behavior around how pip config set works with invalid values, so I don't have backwards compatibility concerns here.

@pradyunsg regarding pip config set: If there is just a warning, but the invalid values are still inserted pip.conf, it will currently render pip completely unusable. The only way to make it work again is to find the correct pip.conf file and fix it by hand. Also, you won't even be able to ask pip config debug where pip.conf might be located.

That is, of course, unless pip is simultaneously modified to not crash but just warn about and ignore invalid values it reads from pip.conf. That would solve the biggest issue, and IMO be already a huge improvement.

So in my mind a warning is sufficient, provided that it's displayed both for pip config set given invalid values on the command line, and also for any other pip invocations when invalid values in pip.conf are ignored.

FWIW most interactive applications I am aware of have an option to run without the config, which may helps the users debug situations like this. Personally I +1 on pip config set guarding the field integrity, but that might not be sufficient in case pip upgrades and introduces/removes options so that the config could trigger an error. The worst case is when the error is with the global config file which the user cannot touch.

FWIW most interactive applications I am aware of have an option to run without the config, which may helps the users debug situations like this.

Would pip --isolated help here?

@uranusjr, pip --isolated doesn't seem to help, at least in a virtualenv:

$ pip config set --site global.use-feature invalid                     
Writing to /home/akaihola/.virtualenvs/tmp-b2918f420593727/pip.conf
$ pip config list                                 
An error occurred during configuration: option use-feature: invalid choice: 'invalid' (choose from '2020-resolver', 'fast-deps')
$ pip config debug           
An error occurred during configuration: option use-feature: invalid choice: 'invalid' (choose from '2020-resolver', 'fast-deps')
$ pip --isolated config list                                   
An error occurred during configuration: option use-feature: invalid choice: 'invalid' (choose from '2020-resolver', 'fast-deps')
$ pip --isolated config debug
An error occurred during configuration: option use-feature: invalid choice: 'invalid' (choose from '2020-resolver', 'fast-deps')

@akaihola Weird, this seems to contradict its help message. I鈥檒l take a look at it (independent to this issue). Thanks!

@uranusjr,

--isolatedRun pip in an isolated mode, ignoring environment variables and user configuration.`

Maybe it just skips whatever configuration has been set using --user, but not the ones set using --site in a virtualenv?

I just checked, it seems like --isolated only applies to distutils config files (a historical artifact that I don鈥檛 think many ever used), not pip config files.

All pip configuration files are always loaded; you can see the function that gets those files received no flags at all:

https://github.com/pypa/pip/blob/ea10d0e253f497c9fc08097f14cdba6b94b45541/src/pip/_internal/configuration.py#L76-L96

We should have a discussion on this 馃檨 But also independent to this issue.

All pip configuration files are always loaded;

Not true. :P

https://github.com/pypa/pip/blob/ea10d0e253f497c9fc08097f14cdba6b94b45541/src/pip/_internal/configuration.py#L380

The user configuration files are not loaded when --isolated is passed. Why is it that way? IDK, and I wrote this bit of code [^1].


Was this page helpful?
0 / 5 - 0 ratings