mirror of https://github.com/pypa/pip
Merge pull request #11487 from pelson/feature/base-prefix-config
This commit is contained in:
commit
56e5fa3c0f
|
@ -19,13 +19,14 @@ and how they are related to pip's various command line options.
|
|||
|
||||
## Configuration Files
|
||||
|
||||
Configuration files can change the default values for command line option.
|
||||
They are written using a standard INI style configuration files.
|
||||
Configuration files can change the default values for command line options.
|
||||
They are written using standard INI style configuration files.
|
||||
|
||||
pip has 3 "levels" of configuration files:
|
||||
pip has 4 "levels" of configuration files:
|
||||
|
||||
- `global`: system-wide configuration file, shared across users.
|
||||
- `user`: per-user configuration file.
|
||||
- `global`: system-wide configuration file, shared across all users.
|
||||
- `user`: per-user configuration file, shared across all environments.
|
||||
- `base` : per-base environment configuration file, shared across all virtualenvs with the same base. (available since pip 23.0)
|
||||
- `site`: per-environment configuration file; i.e. per-virtualenv.
|
||||
|
||||
### Location
|
||||
|
@ -47,6 +48,9 @@ User
|
|||
|
||||
The legacy "per-user" configuration file is also loaded, if it exists: {file}`$HOME/.pip/pip.conf`.
|
||||
|
||||
Base
|
||||
: {file}`\{sys.base_prefix\}/pip.conf`
|
||||
|
||||
Site
|
||||
: {file}`$VIRTUAL_ENV/pip.conf`
|
||||
```
|
||||
|
@ -63,6 +67,9 @@ User
|
|||
|
||||
The legacy "per-user" configuration file is also loaded, if it exists: {file}`$HOME/.pip/pip.conf`.
|
||||
|
||||
Base
|
||||
: {file}`\{sys.base_prefix\}/pip.conf`
|
||||
|
||||
Site
|
||||
: {file}`$VIRTUAL_ENV/pip.conf`
|
||||
```
|
||||
|
@ -81,6 +88,9 @@ User
|
|||
|
||||
The legacy "per-user" configuration file is also loaded, if it exists: {file}`%HOME%\\pip\\pip.ini`
|
||||
|
||||
Base
|
||||
: {file}`\{sys.base_prefix\}\\pip.ini`
|
||||
|
||||
Site
|
||||
: {file}`%VIRTUAL_ENV%\\pip.ini`
|
||||
```
|
||||
|
@ -102,6 +112,7 @@ order:
|
|||
- `PIP_CONFIG_FILE`, if given.
|
||||
- Global
|
||||
- User
|
||||
- Base
|
||||
- Site
|
||||
|
||||
Each file read overrides any values read from previous files, so if the
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
In the case of virtual environments, configuration files are now also included from the base installation.
|
|
@ -36,12 +36,20 @@ ENV_NAMES_IGNORED = "version", "help"
|
|||
kinds = enum(
|
||||
USER="user", # User Specific
|
||||
GLOBAL="global", # System Wide
|
||||
SITE="site", # [Virtual] Environment Specific
|
||||
BASE="base", # Base environment specific (e.g. for all venvs with the same base)
|
||||
SITE="site", # Environment Specific (e.g. per venv)
|
||||
ENV="env", # from PIP_CONFIG_FILE
|
||||
ENV_VAR="env-var", # from Environment Variables
|
||||
)
|
||||
OVERRIDE_ORDER = kinds.GLOBAL, kinds.USER, kinds.SITE, kinds.ENV, kinds.ENV_VAR
|
||||
VALID_LOAD_ONLY = kinds.USER, kinds.GLOBAL, kinds.SITE
|
||||
OVERRIDE_ORDER = (
|
||||
kinds.GLOBAL,
|
||||
kinds.USER,
|
||||
kinds.BASE,
|
||||
kinds.SITE,
|
||||
kinds.ENV,
|
||||
kinds.ENV_VAR,
|
||||
)
|
||||
VALID_LOAD_ONLY = kinds.USER, kinds.GLOBAL, kinds.BASE, kinds.SITE
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
|
@ -70,6 +78,7 @@ def get_configuration_files() -> Dict[Kind, List[str]]:
|
|||
os.path.join(path, CONFIG_BASENAME) for path in appdirs.site_config_dirs("pip")
|
||||
]
|
||||
|
||||
base_config_file = os.path.join(sys.base_prefix, CONFIG_BASENAME)
|
||||
site_config_file = os.path.join(sys.prefix, CONFIG_BASENAME)
|
||||
legacy_config_file = os.path.join(
|
||||
os.path.expanduser("~"),
|
||||
|
@ -78,6 +87,7 @@ def get_configuration_files() -> Dict[Kind, List[str]]:
|
|||
)
|
||||
new_config_file = os.path.join(appdirs.user_config_dir("pip"), CONFIG_BASENAME)
|
||||
return {
|
||||
kinds.BASE: [base_config_file],
|
||||
kinds.GLOBAL: global_config_files,
|
||||
kinds.SITE: [site_config_file],
|
||||
kinds.USER: [legacy_config_file, new_config_file],
|
||||
|
@ -344,6 +354,8 @@ class Configuration:
|
|||
# The legacy config file is overridden by the new config file
|
||||
yield kinds.USER, config_files[kinds.USER]
|
||||
|
||||
yield kinds.BASE, config_files[kinds.BASE]
|
||||
|
||||
# finally virtualenv configuration first trumping others
|
||||
yield kinds.SITE, config_files[kinds.SITE]
|
||||
|
||||
|
|
|
@ -24,12 +24,18 @@ class TestConfigurationLoading(ConfigurationMixin):
|
|||
self.configuration.load()
|
||||
assert self.configuration.get_value("test.hello") == "2"
|
||||
|
||||
def test_site_loading(self) -> None:
|
||||
self.patch_configuration(kinds.SITE, {"test.hello": "3"})
|
||||
def test_base_loading(self) -> None:
|
||||
self.patch_configuration(kinds.BASE, {"test.hello": "3"})
|
||||
|
||||
self.configuration.load()
|
||||
assert self.configuration.get_value("test.hello") == "3"
|
||||
|
||||
def test_site_loading(self) -> None:
|
||||
self.patch_configuration(kinds.SITE, {"test.hello": "4"})
|
||||
|
||||
self.configuration.load()
|
||||
assert self.configuration.get_value("test.hello") == "4"
|
||||
|
||||
def test_environment_config_loading(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
contents = """
|
||||
[test]
|
||||
|
@ -107,6 +113,15 @@ class TestConfigurationLoading(ConfigurationMixin):
|
|||
with pytest.raises(ConfigurationError, match=pat):
|
||||
self.configuration.get_value("global.index-url")
|
||||
|
||||
def test_overrides_normalization(self) -> None:
|
||||
# Check that normalized names are used in precedence calculations.
|
||||
# Reminder: USER has higher precedence than GLOBAL.
|
||||
self.patch_configuration(kinds.USER, {"test.hello-world": "1"})
|
||||
self.patch_configuration(kinds.GLOBAL, {"test.hello_world": "0"})
|
||||
self.configuration.load()
|
||||
|
||||
assert self.configuration.get_value("test.hello_world") == "1"
|
||||
|
||||
|
||||
class TestConfigurationPrecedence(ConfigurationMixin):
|
||||
# Tests for methods to that determine the order of precedence of
|
||||
|
@ -133,6 +148,13 @@ class TestConfigurationPrecedence(ConfigurationMixin):
|
|||
|
||||
assert self.configuration.get_value("test.hello") == "0"
|
||||
|
||||
def test_site_overides_base(self) -> None:
|
||||
self.patch_configuration(kinds.BASE, {"test.hello": "2"})
|
||||
self.patch_configuration(kinds.SITE, {"test.hello": "1"})
|
||||
self.configuration.load()
|
||||
|
||||
assert self.configuration.get_value("test.hello") == "1"
|
||||
|
||||
def test_site_overides_user(self) -> None:
|
||||
self.patch_configuration(kinds.USER, {"test.hello": "2"})
|
||||
self.patch_configuration(kinds.SITE, {"test.hello": "1"})
|
||||
|
@ -147,6 +169,13 @@ class TestConfigurationPrecedence(ConfigurationMixin):
|
|||
|
||||
assert self.configuration.get_value("test.hello") == "1"
|
||||
|
||||
def test_base_overides_user(self) -> None:
|
||||
self.patch_configuration(kinds.USER, {"test.hello": "2"})
|
||||
self.patch_configuration(kinds.BASE, {"test.hello": "1"})
|
||||
self.configuration.load()
|
||||
|
||||
assert self.configuration.get_value("test.hello") == "1"
|
||||
|
||||
def test_user_overides_global(self) -> None:
|
||||
self.patch_configuration(kinds.GLOBAL, {"test.hello": "3"})
|
||||
self.patch_configuration(kinds.USER, {"test.hello": "2"})
|
||||
|
|
|
@ -588,7 +588,7 @@ class TestOptionsConfigFiles:
|
|||
for _, val in cp.iter_config_files():
|
||||
files.extend(val)
|
||||
|
||||
assert len(files) == 4
|
||||
assert len(files) == 5
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"args, expect",
|
||||
|
|
Loading…
Reference in New Issue