mirror of https://github.com/pypa/pip
Merge pull request #11073 from wimglenn/issue-9330
``pip config`` normalizes names, converting underscores into dashes
This commit is contained in:
commit
bab5bfce50
|
@ -88,7 +88,7 @@ The contents of this file are reStructuredText formatted text that
|
||||||
will be used as the content of the news file entry. You do not need to
|
will be used as the content of the news file entry. You do not need to
|
||||||
reference the issue or PR numbers in the entry, since ``towncrier``
|
reference the issue or PR numbers in the entry, since ``towncrier``
|
||||||
will automatically add a reference to all of the affected issues when
|
will automatically add a reference to all of the affected issues when
|
||||||
rendering the NEWS file.
|
rendering the NEWS file. There must be a newline at the end of the file.
|
||||||
|
|
||||||
In order to maintain a consistent style in the ``NEWS.rst`` file, it is
|
In order to maintain a consistent style in the ``NEWS.rst`` file, it is
|
||||||
preferred to keep the news entry to the point, in sentence case, shorter than
|
preferred to keep the news entry to the point, in sentence case, shorter than
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
``pip config`` now normalizes names by converting underscores into dashes.
|
|
@ -142,13 +142,19 @@ class Configuration:
|
||||||
|
|
||||||
def get_value(self, key: str) -> Any:
|
def get_value(self, key: str) -> Any:
|
||||||
"""Get a value from the configuration."""
|
"""Get a value from the configuration."""
|
||||||
|
orig_key = key
|
||||||
|
key = _normalize_name(key)
|
||||||
try:
|
try:
|
||||||
return self._dictionary[key]
|
return self._dictionary[key]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise ConfigurationError(f"No such key - {key}")
|
# disassembling triggers a more useful error message than simply
|
||||||
|
# "No such key" in the case that the key isn't in the form command.option
|
||||||
|
_disassemble_key(key)
|
||||||
|
raise ConfigurationError(f"No such key - {orig_key}")
|
||||||
|
|
||||||
def set_value(self, key: str, value: Any) -> None:
|
def set_value(self, key: str, value: Any) -> None:
|
||||||
"""Modify a value in the configuration."""
|
"""Modify a value in the configuration."""
|
||||||
|
key = _normalize_name(key)
|
||||||
self._ensure_have_load_only()
|
self._ensure_have_load_only()
|
||||||
|
|
||||||
assert self.load_only
|
assert self.load_only
|
||||||
|
@ -167,11 +173,13 @@ class Configuration:
|
||||||
|
|
||||||
def unset_value(self, key: str) -> None:
|
def unset_value(self, key: str) -> None:
|
||||||
"""Unset a value in the configuration."""
|
"""Unset a value in the configuration."""
|
||||||
|
orig_key = key
|
||||||
|
key = _normalize_name(key)
|
||||||
self._ensure_have_load_only()
|
self._ensure_have_load_only()
|
||||||
|
|
||||||
assert self.load_only
|
assert self.load_only
|
||||||
if key not in self._config[self.load_only]:
|
if key not in self._config[self.load_only]:
|
||||||
raise ConfigurationError(f"No such key - {key}")
|
raise ConfigurationError(f"No such key - {orig_key}")
|
||||||
|
|
||||||
fname, parser = self._get_parser_to_modify()
|
fname, parser = self._get_parser_to_modify()
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
"""Tests for all things related to the configuration
|
"""Tests for all things related to the configuration
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
@ -87,6 +88,25 @@ class TestConfigurationLoading(ConfigurationMixin):
|
||||||
err.value
|
err.value
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_no_such_key_error_message_no_command(self) -> None:
|
||||||
|
self.configuration.load_only = kinds.GLOBAL
|
||||||
|
self.configuration.load()
|
||||||
|
expected_msg = (
|
||||||
|
"Key does not contain dot separated section and key. "
|
||||||
|
"Perhaps you wanted to use 'global.index-url' instead?"
|
||||||
|
)
|
||||||
|
pat = f"^{re.escape(expected_msg)}$"
|
||||||
|
with pytest.raises(ConfigurationError, match=pat):
|
||||||
|
self.configuration.get_value("index-url")
|
||||||
|
|
||||||
|
def test_no_such_key_error_message_missing_option(self) -> None:
|
||||||
|
self.configuration.load_only = kinds.GLOBAL
|
||||||
|
self.configuration.load()
|
||||||
|
expected_msg = "No such key - global.index-url"
|
||||||
|
pat = f"^{re.escape(expected_msg)}$"
|
||||||
|
with pytest.raises(ConfigurationError, match=pat):
|
||||||
|
self.configuration.get_value("global.index-url")
|
||||||
|
|
||||||
|
|
||||||
class TestConfigurationPrecedence(ConfigurationMixin):
|
class TestConfigurationPrecedence(ConfigurationMixin):
|
||||||
# Tests for methods to that determine the order of precedence of
|
# Tests for methods to that determine the order of precedence of
|
||||||
|
@ -185,12 +205,8 @@ class TestConfigurationModification(ConfigurationMixin):
|
||||||
def test_no_specific_given_modification(self) -> None:
|
def test_no_specific_given_modification(self) -> None:
|
||||||
self.configuration.load()
|
self.configuration.load()
|
||||||
|
|
||||||
try:
|
with pytest.raises(ConfigurationError):
|
||||||
self.configuration.set_value("test.hello", "10")
|
self.configuration.set_value("test.hello", "10")
|
||||||
except ConfigurationError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
assert False, "Should have raised an error."
|
|
||||||
|
|
||||||
def test_site_modification(self) -> None:
|
def test_site_modification(self) -> None:
|
||||||
self.configuration.load_only = kinds.SITE
|
self.configuration.load_only = kinds.SITE
|
||||||
|
@ -241,3 +257,16 @@ class TestConfigurationModification(ConfigurationMixin):
|
||||||
# get the path to user config file
|
# get the path to user config file
|
||||||
assert mymock.call_count == 1
|
assert mymock.call_count == 1
|
||||||
assert mymock.call_args[0][0] == (get_configuration_files()[kinds.GLOBAL][-1])
|
assert mymock.call_args[0][0] == (get_configuration_files()[kinds.GLOBAL][-1])
|
||||||
|
|
||||||
|
def test_normalization(self) -> None:
|
||||||
|
# underscores and dashes can be used interchangeably.
|
||||||
|
# internally, underscores get converted into dashes before reading/writing file
|
||||||
|
self.configuration.load_only = kinds.GLOBAL
|
||||||
|
self.configuration.load()
|
||||||
|
self.configuration.set_value("global.index_url", "example.org")
|
||||||
|
assert self.configuration.get_value("global.index_url") == "example.org"
|
||||||
|
assert self.configuration.get_value("global.index-url") == "example.org"
|
||||||
|
self.configuration.unset_value("global.index-url")
|
||||||
|
pat = r"^No such key - global\.index-url$"
|
||||||
|
with pytest.raises(ConfigurationError, match=pat):
|
||||||
|
self.configuration.get_value("global.index-url")
|
||||||
|
|
Loading…
Reference in New Issue