mirror of
https://github.com/pypa/pip
synced 2023-12-13 21:30:23 +01:00
Fix for subtle config override bug
Config keys should be normalized (i.e., have underscores replaced with dashes) *before* the config dictionaries are merged. Otherwise, if you set a value in a config file and via an environment variable both the dash separated key (from the config file) and the underscore separated key (from the environment variable) end up in the config dictionary. Usually this doesn't matter because the latter key comes after the former when the dictionary is iterated over. But in cases where the two config keys hash to the same value module the size of the dictionary, the order is reversed and the wrong value takes precedance. For instance with 'index-url' there's no problem: >>> repr({'index-url': 1, 'index_url': 2}) "{'index-url': 1, 'index_url': 2}" But with 'no-index', the value from the config file overwrites the value from the environment variable: >>> repr({'no-index': 1, 'no_index': 2}) "{'no_index': 2, 'no-index': 1}"
This commit is contained in:
parent
68e18e593d
commit
7a889d800c
|
@ -46,14 +46,11 @@ class ConfigOptionParser(optparse.OptionParser):
|
|||
config = {}
|
||||
# 1. config files
|
||||
for section in ('global', self.name):
|
||||
config.update(dict(self.get_config_section(section)))
|
||||
config.update(self.normalize_keys(self.get_config_section(section)))
|
||||
# 2. environmental variables
|
||||
config.update(dict(self.get_environ_vars()))
|
||||
config.update(self.normalize_keys(self.get_environ_vars()))
|
||||
# Then set the options with those values
|
||||
for key, val in config.items():
|
||||
key = key.replace('_', '-')
|
||||
if not key.startswith('--'):
|
||||
key = '--%s' % key # only prefer long opts
|
||||
option = self.get_option(key)
|
||||
if option is not None:
|
||||
# ignore empty values
|
||||
|
@ -74,6 +71,18 @@ class ConfigOptionParser(optparse.OptionParser):
|
|||
sys.exit(3)
|
||||
defaults[option.dest] = val
|
||||
return defaults
|
||||
|
||||
def normalize_keys(self, items):
|
||||
"""Return a config dictionary with normalized keys regardless of
|
||||
whether the keys were specified in environment variables or in config
|
||||
files"""
|
||||
normalized = {}
|
||||
for key, val in items:
|
||||
key = key.replace('_', '-')
|
||||
if not key.startswith('--'):
|
||||
key = '--%s' % key # only prefer long opts
|
||||
normalized[key] = val
|
||||
return normalized
|
||||
|
||||
def get_config_section(self, name):
|
||||
"""Get a section of a configuration"""
|
||||
|
|
Loading…
Reference in a new issue