Repository: pypa/pip

Issue:
PIP_CONFIG_FILE overrides other configs in conflict with documentation
### Description

When PIP_CONFIG_FILE is set, values in that file override other files. However in the documentation it states:
> 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.

I presume that the intended functionality is what is described in the documentation, especially since there is a comment to that effect in `Configuration.iter_config_files`. (Namely, `# environment variables have the lowest priority`.) However, given the length of time things have been this way, maybe the docs are what's wrong.

The actual functionality is determined by override order, where `kinds.ENV` is the second highest priority. I think having the order specified in two different places is the ultimate source of the bug.

Happy to submit a PR once there's some clarity on what the right way to fix it is.

### Expected behavior

_No response_

### pip version

all

### Python version

3

### OS

any

### How to Reproduce

Have any (global, user, site) pip.conf in a standard path and run `> PIP_CONFIG_FILE=/path/to/any/other/pip.conf pip config debug`

### Output

_No response_

### Code of Conduct

- [X] I agree to follow the [PSF Code of Conduct](https://www.python.org/psf/conduct/).


Discussion:
Changing the docs to match reality seems like the right thing to do here. Thanks for catching and flagging this.
I'll try to submit a PR fixing the docs later this week. I think that having the environment variable be the final authority is pretty intuitive and consistent with how Pip and other programs use env vars.

That being said I was pulling for this not being the case, since this leaves no mechanism to have a default file that a user can override without root. Maybe I'll open a separate issue to look into creating such a mechanism.

Resolving patch:
diff --git a/src/pip/_internal/configuration.py b/src/pip/_internal/configuration.py
--- a/src/pip/_internal/configuration.py
+++ b/src/pip/_internal/configuration.py
@@ -327,33 +327,35 @@ def get_environ_vars(self) -> Iterable[Tuple[str, str]]:
     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]


Test patch: