Repository: pypa/pip

Issue:
Name normalization issue in 10.0.0b1 yields false-positive installation warnings
* Pip version: 10.0.0b1
* Python version: 2.7.14
* Operating system: Linux

### Description:

The new pip check mode used during installation wrongly reports that packages are not being installed. This only happens for package containing a `.` (dot) in the name.

### What I've run:

```
pip install pyramid
Collecting pyramid
  Using cached pyramid-1.9.1-py2.py3-none-any.whl
Collecting zope.interface>=3.8.0 (from pyramid)
  Using cached zope.interface-4.4.3-cp36-cp36m-manylinux1_x86_64.whl
Collecting hupper (from pyramid)
  Using cached hupper-1.1-py2.py3-none-any.whl
Collecting zope.deprecation>=3.5.0 (from pyramid)
  Using cached zope.deprecation-4.3.0-py2.py3-none-any.whl
Collecting translationstring>=0.4 (from pyramid)
  Using cached translationstring-1.3-py2.py3-none-any.whl
Requirement already satisfied: setuptools in ./venv-ex/lib/python3.6/site-packages (from pyramid) (39.0.1)
Collecting WebOb>=1.7.0rc2 (from pyramid)
  Using cached WebOb-1.8.0rc1-py2.py3-none-any.whl
Collecting venusian>=1.0a3 (from pyramid)
  Using cached venusian-1.1.0-py2.py3-none-any.whl
Collecting repoze.lru>=0.4 (from pyramid)
  Using cached repoze.lru-0.7-py3-none-any.whl
Collecting plaster-pastedeploy (from pyramid)
  Using cached plaster_pastedeploy-0.5-py2.py3-none-any.whl
Collecting PasteDeploy>=1.5.0 (from pyramid)
  Using cached PasteDeploy-1.5.2-py2.py3-none-any.whl
Collecting plaster (from pyramid)
  Using cached plaster-1.0-py2.py3-none-any.whl
pyramid 1.9.1 requires repoze.lru>=0.4, which is not installed.
pyramid 1.9.1 requires zope.deprecation>=3.5.0, which is not installed.
pyramid 1.9.1 requires zope.interface>=3.8.0, which is not installed.
Installing collected packages: zope.interface, hupper, zope.deprecation, translationstring, WebOb, venusian, repoze.lru, PasteDeploy, plaster, plaster-pastedeploy, pyramid
Successfully installed PasteDeploy-1.5.2 WebOb-1.8.0rc1 hupper-1.1 plaster-1.0 plaster-pastedeploy-0.5 pyramid-1.9.1 repoze.lru-0.7 translationstring-1.3 venusian-1.1.0 zope.deprecation-4.3.0 zope.interface-4.4.3
```



Discussion:
I am working on a patch

Resolving patch:
diff --git a/src/pip/_internal/operations/check.py b/src/pip/_internal/operations/check.py
--- a/src/pip/_internal/operations/check.py
+++ b/src/pip/_internal/operations/check.py
@@ -99,4 +99,5 @@ def _simulate_installation_of(to_install, state):
     # Modify it as installing requirement_set would (assuming no errors)
     for inst_req in to_install:
         dist = make_abstract_dist(inst_req).dist(finder=None)
-        state[dist.key] = PackageDetails(dist.version, dist.requires())
+        name = canonicalize_name(dist.key)
+        state[name] = PackageDetails(dist.version, dist.requires())


Test patch:
diff --git a/tests/functional/test_install_check.py b/tests/functional/test_install_check.py
new file mode 100644
--- /dev/null
+++ b/tests/functional/test_install_check.py
@@ -0,0 +1,59 @@
+from tests.lib import create_test_package_with_setup
+
+
+def matches_expected_lines(string, expected_lines):
+    def predicate(line):
+        return line and not line.startswith('DEPRECATION')
+
+    output_lines = set(filter(predicate, string.splitlines()))
+    # Match regardless of order
+    return set(output_lines) == set(expected_lines)
+
+
+def test_check_install_warnings(script):
+    pkga_path = create_test_package_with_setup(
+        script,
+        name='pkga',
+        version='1.0',
+        install_requires=['normal-missing', 'special.missing'],
+    )
+    # Let's install pkga without its dependency
+    result = script.pip('install', '--no-index', pkga_path, '--no-deps')
+    assert "Successfully installed pkga-1.0" in result.stdout, str(result)
+
+    # Install the first missing dependency. Only an error for the
+    # second dependency should remain.
+    normal_path = create_test_package_with_setup(
+        script,
+        name='normal-missing', version='0.1',
+    )
+    result = script.pip(
+        'install', '--no-index', normal_path, '--quiet', expect_error=True
+    )
+    expected_lines = (
+        "pkga 1.0 requires special.missing, which is not installed.",
+    )
+    assert matches_expected_lines(result.stderr, expected_lines)
+    assert result.returncode == 0
+
+    # Install the second missing package and expect that there is no warning
+    # during the installation. This is special as the package name requires
+    # name normalization (as in https://github.com/pypa/pip/issues/5134)
+    missing_path = create_test_package_with_setup(
+        script,
+        name='special.missing', version='0.1',
+    )
+    result = script.pip(
+        'install', '--no-index', missing_path, '--quiet',
+    )
+    assert matches_expected_lines(result.stdout, [])
+    assert matches_expected_lines(result.stderr, [])
+    assert result.returncode == 0
+
+    # Double check that all errors are resolved in the end
+    result = script.pip('check')
+    expected_lines = (
+        "No broken requirements found.",
+    )
+    assert matches_expected_lines(result.stdout, expected_lines)
+    assert result.returncode == 0