diff --git a/docs/html/topics/configuration.md b/docs/html/topics/configuration.md
index e4aafcd2b..8b54db56c 100644
--- a/docs/html/topics/configuration.md
+++ b/docs/html/topics/configuration.md
@@ -19,8 +19,8 @@ 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.
+The files are written using standard INI format.
pip has 3 "levels" of configuration files:
@@ -28,11 +28,15 @@ pip has 3 "levels" of configuration files:
- `user`: per-user configuration file.
- `site`: per-environment configuration file; i.e. per-virtualenv.
+Additionally, environment variables can be specified which will override any of the above.
+
### Location
pip's configuration files are located in fairly standard locations. This
location is different on different operating systems, and has some additional
-complexity for backwards compatibility reasons.
+complexity for backwards compatibility reasons. Note that if user config files
+exist in both the legacy and current locations, values in the current file
+will override values in the legacy file.
```{tab} Unix
@@ -88,9 +92,10 @@ Site
### `PIP_CONFIG_FILE`
Additionally, the environment variable `PIP_CONFIG_FILE` can be used to specify
-a configuration file that's loaded first, and whose values are overridden by
-the values set in the aforementioned files. Setting this to {any}`os.devnull`
-disables the loading of _all_ configuration files.
+a configuration file that's loaded last, and whose values override the values
+set in the aforementioned files. Setting this to {any}`os.devnull`
+disables the loading of _all_ configuration files. Note that if a file exists
+at the location that this is set to, the user config file will not be loaded.
(config-precedence)=
@@ -99,10 +104,10 @@ disables the loading of _all_ configuration files.
When multiple configuration files are found, pip combines them in the following
order:
-- `PIP_CONFIG_FILE`, if given.
- Global
- User
- Site
+- `PIP_CONFIG_FILE`, if given.
Each file read overrides any values read from previous files, so if the
global timeout is specified in both the global file and the per-user file
diff --git a/news/11815.doc.rst b/news/11815.doc.rst
new file mode 100644
index 000000000..8e7e8d21b
--- /dev/null
+++ b/news/11815.doc.rst
@@ -0,0 +1 @@
+Fix explanation of how PIP_CONFIG_FILE works
diff --git a/src/pip/_internal/configuration.py b/src/pip/_internal/configuration.py
index 96f824955..124a7ca5d 100644
--- a/src/pip/_internal/configuration.py
+++ b/src/pip/_internal/configuration.py
@@ -327,33 +327,35 @@ class Configuration:
def iter_config_files(self) -> Iterable[Tuple[Kind, List[str]]]:
"""Yields variant and configuration files associated with it.
- This should be treated like items of a dictionary.
+ This should be treated like items of a dictionary. The order
+ here doesn't affect what gets overridden. That is controlled
+ by OVERRIDE_ORDER. However this does control the order they are
+ displayed to the user. It's probably most ergononmic to display
+ things in the same order as OVERRIDE_ORDER
"""
# SMELL: Move the conditions out of this function
- # environment variables have the lowest priority
- config_file = os.environ.get("PIP_CONFIG_FILE", None)
- if config_file is not None:
- yield kinds.ENV, [config_file]
- else:
- yield kinds.ENV, []
-
+ env_config_file = os.environ.get("PIP_CONFIG_FILE", None)
config_files = get_configuration_files()
- # at the base we have any global configuration
yield kinds.GLOBAL, config_files[kinds.GLOBAL]
- # per-user configuration next
+ # per-user config is not loaded when env_config_file exists
should_load_user_config = not self.isolated and not (
- config_file and os.path.exists(config_file)
+ env_config_file and os.path.exists(env_config_file)
)
if should_load_user_config:
# The legacy config file is overridden by the new config file
yield kinds.USER, config_files[kinds.USER]
- # finally virtualenv configuration first trumping others
+ # virtualenv config
yield kinds.SITE, config_files[kinds.SITE]
+ if env_config_file is not None:
+ yield kinds.ENV, [env_config_file]
+ else:
+ yield kinds.ENV, []
+
def get_values_in_config(self, variant: Kind) -> Dict[str, Any]:
"""Get values present in a config file"""
return self._config[variant]