Repository: pypa/pip

Issue:
Upgrade pip using pip.exe raises an error if the requirement already satisfied
**Environment**

* pip version: 19.3.dev0, master since d2b7082932a59585ea6198cbf375758fae949c67 
* Python version: any
* OS: Windows

**Description**

Currently modifying pip on Windows using `pip.exe` [raises](https://ci.appveyor.com/project/atugushev/test-package/builds/26948397) an error and suggests to upgrade it using module invocation `python -m pip install ...`:

```
ERROR: To modify pip, please run the following command:
C:\Python36\python.exe -m pip install --upgrade pip
```

But if the requirement is already satisfied or up-to-date it still [raises](https://ci.appveyor.com/project/atugushev/test-package/builds/26948432) the same error:

```
Requirement already satisfied: pip in c:\python36\lib\site-packages (19.3.dev0)
ERROR: To modify pip, please run the following command:
C:\Python36\python.exe -m pip install pip
```

**Expected behavior**

The command shouldn't raise the error if the requirement is up-to-date:

```
> pip install pip
Requirement already satisfied: pip in c:\python36\lib\site-packages (19.3.dev0)
```

**How to Reproduce**
<!-- Describe the steps to reproduce this bug. -->

1. Get package from git+git://github.com/pypa/pip@d2b708#egg=pip
2. Then run `pip install pip`
3. An error occurs.

**Output**

```
> python -m pip install --upgrade git+git://github.com/pypa/pip@master#egg=pip==19.3.dev0
Collecting pip==19.3.dev0 from git+git://github.com/pypa/pip@master#egg=pip==19.3.dev0
  Cloning git://github.com/pypa/pip (to revision master) to c:\users\appveyor\appdata\local\temp\1\pip-install-t406pky0\pip
  Installing build dependencies: started
  Installing build dependencies: finished with status 'done'
Installing collected packages: pip
  Found existing installation: pip 18.1
    Uninstalling pip-18.1:
      Successfully uninstalled pip-18.1
  Running setup.py install for pip: started
    Running setup.py install for pip: finished with status 'done'
Successfully installed pip-19.3.dev0

> pip install pip
Requirement already satisfied: pip in c:\python36\lib\site-packages (19.3.dev0)
ERROR: To modify pip, please run the following command:
C:\Python36\python.exe -m pip install pip
```

**Additional context**

This issue came out of the discussion in PR https://github.com/pypa/pip/pull/6864#discussion_r313194948.


Discussion:
@chrahunt could you please assign this issue to me, i'd like to work on it?

Resolving patch:
diff --git a/src/pip/_internal/commands/install.py b/src/pip/_internal/commands/install.py
--- a/src/pip/_internal/commands/install.py
+++ b/src/pip/_internal/commands/install.py
@@ -362,8 +362,16 @@ def run(self, options, args):
                     )
                     resolver.resolve(requirement_set)
 
+                    try:
+                        pip_req = requirement_set.get_requirement("pip")
+                    except KeyError:
+                        modifying_pip = None
+                    else:
+                        # If we're not replacing an already installed pip,
+                        # we're not modifying it.
+                        modifying_pip = pip_req.satisfied_by is None
                     protect_pip_from_modification_on_windows(
-                        modifying_pip=requirement_set.has_requirement("pip")
+                        modifying_pip=modifying_pip
                     )
 
                     # Consider legacy and PEP517-using requirements separately
diff --git a/src/pip/_internal/utils/misc.py b/src/pip/_internal/utils/misc.py
--- a/src/pip/_internal/utils/misc.py
+++ b/src/pip/_internal/utils/misc.py
@@ -1307,6 +1307,7 @@ def hide_url(url):
 
 
 def protect_pip_from_modification_on_windows(modifying_pip):
+    # type: (bool) -> None
     """Protection of pip.exe from modification on Windows
 
     On Windows, any operation modifying pip should be run as:


Test patch:
diff --git a/tests/functional/test_install.py b/tests/functional/test_install.py
--- a/tests/functional/test_install.py
+++ b/tests/functional/test_install.py
@@ -1636,3 +1636,21 @@ def test_protect_pip_from_modification_via_sub_deps_on_windows(script):
         .format(' '.join(new_command))
     )
     assert expected_message in result.stderr, str(result)
+
+
+@pytest.mark.parametrize(
+    'install_args, expected_message', [
+        ([], 'Requirement already satisfied: pip in'),
+        (['--upgrade'], 'Requirement already up-to-date: pip in'),
+    ]
+)
+@pytest.mark.parametrize("use_module", [True, False])
+def test_install_pip_does_not_modify_pip_when_satisfied(
+        script, install_args, expected_message, use_module):
+    """
+    Test it doesn't upgrade the pip if it already satisfies the requirement.
+    """
+    result = script.pip_install_local(
+        'pip', *install_args, use_module=use_module
+    )
+    assert expected_message in result.stdout, str(result)