2017-05-12 12:42:35 +02:00
|
|
|
"""Tests for all things related to the configuration
|
|
|
|
"""
|
|
|
|
|
2022-04-30 05:51:16 +02:00
|
|
|
import re
|
2021-02-10 11:28:55 +01:00
|
|
|
from unittest.mock import MagicMock
|
2017-05-12 12:42:35 +02:00
|
|
|
|
2021-02-10 11:38:21 +01:00
|
|
|
import pytest
|
|
|
|
|
2019-07-20 22:29:24 +02:00
|
|
|
from pip._internal.configuration import get_configuration_files, kinds
|
2017-08-31 17:48:18 +02:00
|
|
|
from pip._internal.exceptions import ConfigurationError
|
2019-07-20 22:29:24 +02:00
|
|
|
from tests.lib.configuration_helpers import ConfigurationMixin
|
2017-05-12 12:42:35 +02:00
|
|
|
|
|
|
|
|
2017-05-15 18:38:02 +02:00
|
|
|
class TestConfigurationLoading(ConfigurationMixin):
|
2021-08-30 00:43:28 +02:00
|
|
|
def test_global_loading(self) -> None:
|
2017-05-15 15:41:07 +02:00
|
|
|
self.patch_configuration(kinds.GLOBAL, {"test.hello": "1"})
|
2017-05-15 18:38:02 +02:00
|
|
|
|
2017-05-12 12:42:35 +02:00
|
|
|
self.configuration.load()
|
2017-05-15 15:41:07 +02:00
|
|
|
assert self.configuration.get_value("test.hello") == "1"
|
2017-05-12 12:42:35 +02:00
|
|
|
|
2021-08-30 00:43:28 +02:00
|
|
|
def test_user_loading(self) -> None:
|
2017-05-15 15:41:07 +02:00
|
|
|
self.patch_configuration(kinds.USER, {"test.hello": "2"})
|
2017-05-15 18:38:02 +02:00
|
|
|
|
2017-05-12 12:42:35 +02:00
|
|
|
self.configuration.load()
|
2017-05-15 15:41:07 +02:00
|
|
|
assert self.configuration.get_value("test.hello") == "2"
|
2017-05-12 12:42:35 +02:00
|
|
|
|
2022-10-05 18:19:28 +02:00
|
|
|
def test_site_loading(self) -> None:
|
2023-04-21 18:05:49 +02:00
|
|
|
self.patch_configuration(kinds.SITE, {"test.hello": "3"})
|
2022-10-05 18:19:28 +02:00
|
|
|
|
|
|
|
self.configuration.load()
|
2023-04-21 18:05:49 +02:00
|
|
|
assert self.configuration.get_value("test.hello") == "3"
|
2022-10-05 18:19:28 +02:00
|
|
|
|
2021-08-30 00:43:28 +02:00
|
|
|
def test_environment_config_loading(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
2017-05-15 18:38:02 +02:00
|
|
|
contents = """
|
2017-05-15 15:47:36 +02:00
|
|
|
[test]
|
|
|
|
hello = 4
|
2017-05-15 18:38:02 +02:00
|
|
|
"""
|
|
|
|
|
|
|
|
with self.tmpfile(contents) as config_file:
|
2020-07-22 18:01:30 +02:00
|
|
|
monkeypatch.setenv("PIP_CONFIG_FILE", config_file)
|
2017-05-15 18:38:02 +02:00
|
|
|
|
|
|
|
self.configuration.load()
|
|
|
|
assert (
|
|
|
|
self.configuration.get_value("test.hello") == "4"
|
|
|
|
), self.configuration._config
|
2017-05-15 15:47:36 +02:00
|
|
|
|
2021-08-30 00:43:28 +02:00
|
|
|
def test_environment_var_loading(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
2020-07-22 18:01:30 +02:00
|
|
|
monkeypatch.setenv("PIP_HELLO", "5")
|
2017-05-15 15:47:36 +02:00
|
|
|
|
|
|
|
self.configuration.load()
|
2017-05-15 18:38:02 +02:00
|
|
|
assert self.configuration.get_value(":env:.hello") == "5"
|
2017-05-15 15:47:36 +02:00
|
|
|
|
2017-06-24 19:24:13 +02:00
|
|
|
@pytest.mark.skipif("sys.platform == 'win32'")
|
2021-08-30 00:43:28 +02:00
|
|
|
def test_environment_var_does_not_load_lowercase(
|
|
|
|
self, monkeypatch: pytest.MonkeyPatch
|
|
|
|
) -> None:
|
2020-07-22 18:01:30 +02:00
|
|
|
monkeypatch.setenv("pip_hello", "5")
|
2017-06-24 19:24:13 +02:00
|
|
|
|
|
|
|
self.configuration.load()
|
|
|
|
with pytest.raises(ConfigurationError):
|
|
|
|
self.configuration.get_value(":env:.hello")
|
|
|
|
|
2021-08-30 00:43:28 +02:00
|
|
|
def test_environment_var_does_not_load_version(
|
|
|
|
self, monkeypatch: pytest.MonkeyPatch
|
|
|
|
) -> None:
|
2020-07-22 18:01:30 +02:00
|
|
|
monkeypatch.setenv("PIP_VERSION", "True")
|
2017-06-24 19:24:13 +02:00
|
|
|
|
|
|
|
self.configuration.load()
|
|
|
|
|
|
|
|
with pytest.raises(ConfigurationError):
|
|
|
|
self.configuration.get_value(":env:.version")
|
|
|
|
|
2021-08-30 00:43:28 +02:00
|
|
|
def test_environment_config_errors_if_malformed(
|
|
|
|
self, monkeypatch: pytest.MonkeyPatch
|
|
|
|
) -> None:
|
2018-09-19 16:21:18 +02:00
|
|
|
contents = """
|
|
|
|
test]
|
|
|
|
hello = 4
|
|
|
|
"""
|
|
|
|
with self.tmpfile(contents) as config_file:
|
2020-07-22 18:01:30 +02:00
|
|
|
monkeypatch.setenv("PIP_CONFIG_FILE", config_file)
|
2018-09-19 16:21:18 +02:00
|
|
|
with pytest.raises(ConfigurationError) as err:
|
|
|
|
self.configuration.load()
|
|
|
|
|
2018-09-30 19:34:46 +02:00
|
|
|
assert "section header" in str(err.value) # error kind
|
|
|
|
assert "1" in str(err.value) # line number
|
2018-10-03 16:53:40 +02:00
|
|
|
assert config_file in str(err.value) or repr(config_file) in str( # file name
|
2021-08-13 15:23:45 +02:00
|
|
|
err.value
|
2018-10-03 16:53:40 +02:00
|
|
|
)
|
2018-09-19 16:21:18 +02:00
|
|
|
|
2022-04-30 05:51:16 +02:00
|
|
|
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")
|
|
|
|
|
2017-05-12 12:42:35 +02:00
|
|
|
|
2017-05-15 18:38:02 +02:00
|
|
|
class TestConfigurationPrecedence(ConfigurationMixin):
|
2017-05-12 12:42:35 +02:00
|
|
|
# Tests for methods to that determine the order of precedence of
|
|
|
|
# configuration options
|
|
|
|
|
2021-08-30 00:43:28 +02:00
|
|
|
def test_env_overides_site(self) -> None:
|
2019-03-07 06:44:56 +01:00
|
|
|
self.patch_configuration(kinds.SITE, {"test.hello": "1"})
|
2017-05-15 18:38:02 +02:00
|
|
|
self.patch_configuration(kinds.ENV, {"test.hello": "0"})
|
|
|
|
self.configuration.load()
|
|
|
|
|
|
|
|
assert self.configuration.get_value("test.hello") == "0"
|
|
|
|
|
2021-08-30 00:43:28 +02:00
|
|
|
def test_env_overides_user(self) -> None:
|
2017-05-15 15:41:07 +02:00
|
|
|
self.patch_configuration(kinds.USER, {"test.hello": "2"})
|
2017-05-15 18:38:02 +02:00
|
|
|
self.patch_configuration(kinds.ENV, {"test.hello": "0"})
|
2017-05-12 12:42:35 +02:00
|
|
|
self.configuration.load()
|
|
|
|
|
2017-05-15 18:38:02 +02:00
|
|
|
assert self.configuration.get_value("test.hello") == "0"
|
2017-05-12 12:42:35 +02:00
|
|
|
|
2021-08-30 00:43:28 +02:00
|
|
|
def test_env_overides_global(self) -> None:
|
2017-05-15 18:38:02 +02:00
|
|
|
self.patch_configuration(kinds.GLOBAL, {"test.hello": "3"})
|
|
|
|
self.patch_configuration(kinds.ENV, {"test.hello": "0"})
|
2017-05-12 12:42:35 +02:00
|
|
|
self.configuration.load()
|
|
|
|
|
2017-05-15 18:38:02 +02:00
|
|
|
assert self.configuration.get_value("test.hello") == "0"
|
2017-05-12 12:42:35 +02:00
|
|
|
|
2021-08-30 00:43:28 +02:00
|
|
|
def test_site_overides_user(self) -> None:
|
2017-05-15 15:41:07 +02:00
|
|
|
self.patch_configuration(kinds.USER, {"test.hello": "2"})
|
2019-03-07 06:44:56 +01:00
|
|
|
self.patch_configuration(kinds.SITE, {"test.hello": "1"})
|
2017-05-12 12:42:35 +02:00
|
|
|
self.configuration.load()
|
|
|
|
|
2017-05-15 18:38:02 +02:00
|
|
|
assert self.configuration.get_value("test.hello") == "1"
|
2017-05-12 12:42:35 +02:00
|
|
|
|
2021-08-30 00:43:28 +02:00
|
|
|
def test_site_overides_global(self) -> None:
|
2017-05-15 18:38:02 +02:00
|
|
|
self.patch_configuration(kinds.GLOBAL, {"test.hello": "3"})
|
2019-03-07 06:44:56 +01:00
|
|
|
self.patch_configuration(kinds.SITE, {"test.hello": "1"})
|
2017-05-12 12:42:35 +02:00
|
|
|
self.configuration.load()
|
|
|
|
|
2017-05-15 15:41:07 +02:00
|
|
|
assert self.configuration.get_value("test.hello") == "1"
|
2017-05-12 12:42:35 +02:00
|
|
|
|
2021-08-30 00:43:28 +02:00
|
|
|
def test_user_overides_global(self) -> None:
|
2017-05-15 18:38:02 +02:00
|
|
|
self.patch_configuration(kinds.GLOBAL, {"test.hello": "3"})
|
2017-05-15 15:41:07 +02:00
|
|
|
self.patch_configuration(kinds.USER, {"test.hello": "2"})
|
2017-05-12 12:42:35 +02:00
|
|
|
self.configuration.load()
|
|
|
|
|
2017-05-15 15:41:07 +02:00
|
|
|
assert self.configuration.get_value("test.hello") == "2"
|
2017-05-15 18:38:02 +02:00
|
|
|
|
2021-08-30 00:43:28 +02:00
|
|
|
def test_env_not_overriden_by_environment_var(
|
|
|
|
self, monkeypatch: pytest.MonkeyPatch
|
|
|
|
) -> None:
|
2017-05-15 18:38:02 +02:00
|
|
|
self.patch_configuration(kinds.ENV, {"test.hello": "1"})
|
2020-07-22 18:01:30 +02:00
|
|
|
monkeypatch.setenv("PIP_HELLO", "5")
|
2017-05-15 18:38:02 +02:00
|
|
|
|
|
|
|
self.configuration.load()
|
|
|
|
|
|
|
|
assert self.configuration.get_value("test.hello") == "1"
|
|
|
|
assert self.configuration.get_value(":env:.hello") == "5"
|
2017-05-12 12:42:35 +02:00
|
|
|
|
2021-08-30 00:43:28 +02:00
|
|
|
def test_site_not_overriden_by_environment_var(
|
|
|
|
self, monkeypatch: pytest.MonkeyPatch
|
|
|
|
) -> None:
|
2019-03-07 06:44:56 +01:00
|
|
|
self.patch_configuration(kinds.SITE, {"test.hello": "2"})
|
2020-07-22 18:01:30 +02:00
|
|
|
monkeypatch.setenv("PIP_HELLO", "5")
|
2017-05-15 18:38:02 +02:00
|
|
|
|
|
|
|
self.configuration.load()
|
|
|
|
|
|
|
|
assert self.configuration.get_value("test.hello") == "2"
|
|
|
|
assert self.configuration.get_value(":env:.hello") == "5"
|
|
|
|
|
2021-08-30 00:43:28 +02:00
|
|
|
def test_user_not_overriden_by_environment_var(
|
|
|
|
self, monkeypatch: pytest.MonkeyPatch
|
|
|
|
) -> None:
|
2017-05-15 18:38:02 +02:00
|
|
|
self.patch_configuration(kinds.USER, {"test.hello": "3"})
|
2020-07-22 18:01:30 +02:00
|
|
|
monkeypatch.setenv("PIP_HELLO", "5")
|
2017-05-15 18:38:02 +02:00
|
|
|
|
2017-05-12 12:42:35 +02:00
|
|
|
self.configuration.load()
|
|
|
|
|
2017-05-15 15:41:07 +02:00
|
|
|
assert self.configuration.get_value("test.hello") == "3"
|
2017-05-15 18:38:02 +02:00
|
|
|
assert self.configuration.get_value(":env:.hello") == "5"
|
|
|
|
|
2021-08-30 00:43:28 +02:00
|
|
|
def test_global_not_overriden_by_environment_var(
|
|
|
|
self, monkeypatch: pytest.MonkeyPatch
|
|
|
|
) -> None:
|
2017-05-15 18:38:02 +02:00
|
|
|
self.patch_configuration(kinds.GLOBAL, {"test.hello": "4"})
|
2020-07-22 18:01:30 +02:00
|
|
|
monkeypatch.setenv("PIP_HELLO", "5")
|
2017-05-15 18:38:02 +02:00
|
|
|
|
|
|
|
self.configuration.load()
|
|
|
|
|
|
|
|
assert self.configuration.get_value("test.hello") == "4"
|
|
|
|
assert self.configuration.get_value(":env:.hello") == "5"
|
2017-05-12 12:42:35 +02:00
|
|
|
|
|
|
|
|
2017-05-15 18:38:02 +02:00
|
|
|
class TestConfigurationModification(ConfigurationMixin):
|
2017-05-12 12:42:35 +02:00
|
|
|
# Tests for methods to that modify the state of a Configuration
|
|
|
|
|
2021-08-30 00:43:28 +02:00
|
|
|
def test_no_specific_given_modification(self) -> None:
|
2017-05-12 12:42:35 +02:00
|
|
|
self.configuration.load()
|
|
|
|
|
2022-04-29 04:56:44 +02:00
|
|
|
with pytest.raises(ConfigurationError):
|
2017-05-15 15:41:07 +02:00
|
|
|
self.configuration.set_value("test.hello", "10")
|
2017-05-12 12:42:35 +02:00
|
|
|
|
2021-08-30 00:43:28 +02:00
|
|
|
def test_site_modification(self) -> None:
|
2019-03-07 06:44:56 +01:00
|
|
|
self.configuration.load_only = kinds.SITE
|
2017-05-12 12:42:35 +02:00
|
|
|
self.configuration.load()
|
|
|
|
|
|
|
|
# Mock out the method
|
|
|
|
mymock = MagicMock(spec=self.configuration._mark_as_modified)
|
2021-08-28 17:52:10 +02:00
|
|
|
# https://github.com/python/mypy/issues/2427
|
2023-11-07 10:39:01 +01:00
|
|
|
self.configuration._mark_as_modified = mymock # type: ignore[method-assign]
|
2017-05-12 12:42:35 +02:00
|
|
|
|
2017-05-15 15:41:07 +02:00
|
|
|
self.configuration.set_value("test.hello", "10")
|
2017-05-12 12:42:35 +02:00
|
|
|
|
2019-03-07 06:44:56 +01:00
|
|
|
# get the path to site config file
|
2017-05-12 12:42:35 +02:00
|
|
|
assert mymock.call_count == 1
|
2019-07-20 22:29:24 +02:00
|
|
|
assert mymock.call_args[0][0] == (get_configuration_files()[kinds.SITE][0])
|
2017-05-12 12:42:35 +02:00
|
|
|
|
2021-08-30 00:43:28 +02:00
|
|
|
def test_user_modification(self) -> None:
|
2017-05-12 12:42:35 +02:00
|
|
|
# get the path to local config file
|
2017-05-14 08:57:45 +02:00
|
|
|
self.configuration.load_only = kinds.USER
|
2017-05-12 12:42:35 +02:00
|
|
|
self.configuration.load()
|
|
|
|
|
|
|
|
# Mock out the method
|
|
|
|
mymock = MagicMock(spec=self.configuration._mark_as_modified)
|
2021-08-28 17:52:10 +02:00
|
|
|
# https://github.com/python/mypy/issues/2427
|
2023-11-07 10:39:01 +01:00
|
|
|
self.configuration._mark_as_modified = mymock # type: ignore[method-assign]
|
2017-05-12 12:42:35 +02:00
|
|
|
|
2017-05-15 15:41:07 +02:00
|
|
|
self.configuration.set_value("test.hello", "10")
|
2017-05-12 12:42:35 +02:00
|
|
|
|
|
|
|
# get the path to user config file
|
|
|
|
assert mymock.call_count == 1
|
2019-07-20 22:29:24 +02:00
|
|
|
assert mymock.call_args[0][0] == (
|
|
|
|
# Use new config file
|
|
|
|
get_configuration_files()[kinds.USER][1]
|
|
|
|
)
|
2017-05-12 12:42:35 +02:00
|
|
|
|
2021-08-30 00:43:28 +02:00
|
|
|
def test_global_modification(self) -> None:
|
2017-05-12 12:42:35 +02:00
|
|
|
# get the path to local config file
|
2017-05-14 08:57:45 +02:00
|
|
|
self.configuration.load_only = kinds.GLOBAL
|
2017-05-12 12:42:35 +02:00
|
|
|
self.configuration.load()
|
|
|
|
|
|
|
|
# Mock out the method
|
|
|
|
mymock = MagicMock(spec=self.configuration._mark_as_modified)
|
2021-08-28 17:52:10 +02:00
|
|
|
# https://github.com/python/mypy/issues/2427
|
2023-11-07 10:39:01 +01:00
|
|
|
self.configuration._mark_as_modified = mymock # type: ignore[method-assign]
|
2017-05-12 12:42:35 +02:00
|
|
|
|
2017-05-15 15:41:07 +02:00
|
|
|
self.configuration.set_value("test.hello", "10")
|
2017-05-12 12:42:35 +02:00
|
|
|
|
|
|
|
# get the path to user config file
|
|
|
|
assert mymock.call_count == 1
|
2019-07-20 22:29:24 +02:00
|
|
|
assert mymock.call_args[0][0] == (get_configuration_files()[kinds.GLOBAL][-1])
|
2022-04-29 04:56:44 +02:00
|
|
|
|
|
|
|
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()
|
2022-04-29 05:00:16 +02:00
|
|
|
self.configuration.set_value("global.index_url", "example.org")
|
2022-04-29 04:56:44 +02:00
|
|
|
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")
|