Repository: conda/conda

Issue:
conda list misses pip-installed wheels
As of conda 4.1, `conda list` no longer captures python packages that were pip-installed and were installed from wheels.

https://www.python.org/dev/peps/pep-0427/#id14

CC @ilanschnell 



Discussion:
This is actually a real issue now because the large majority of packages on PyPI are distributed as sdists, and now on install, pip force-compiles sdists to wheels, then installs those wheels.

How about we use something like this:

```
import pkgutil
packages = [p[1] for p in pkgutil.iter_modules()]
```

The problem is that from whatever `pkgutil.iter_modules()` returns, it is hard to tell whether or nor the installed package is a conda package or not.  The point of the new `conda.egginfo` module, part from not having to call out to `pip`, is that conda knows which `.egg-info` files are "untracked" (not part of any conda package).  I think the best solution is to extend `conda.egginfo` to handle these new meta-data files also.


Resolving patch:
diff --git a/conda/egg_info.py b/conda/egg_info.py
--- a/conda/egg_info.py
+++ b/conda/egg_info.py
@@ -29,14 +29,15 @@ def get_site_packages_dir(installed_pkgs):
 
 def get_egg_info_files(sp_dir):
     for fn in os.listdir(sp_dir):
-        if not fn.endswith(('.egg', '.egg-info')):
+        if not fn.endswith(('.egg', '.egg-info', '.dist-info')):
             continue
         path = join(sp_dir, fn)
         if isfile(path):
             yield path
         elif isdir(path):
             for path2 in [join(path, 'PKG-INFO'),
-                          join(path, 'EGG-INFO', 'PKG-INFO')]:
+                          join(path, 'EGG-INFO', 'PKG-INFO'),
+                          join(path, 'METADATA')]:
                 if isfile(path2):
                     yield path2
 
@@ -54,7 +55,7 @@ def parse_egg_info(path):
             key = m.group(1).lower()
             info[key] = m.group(2)
         try:
-            return '%(name)s-%(version)s-<egg_info>' % info
+            return '%(name)s-%(version)s-<pip>' % info
         except KeyError:
             pass
     return None


Test patch:
diff --git a/tests/test_create.py b/tests/test_create.py
--- a/tests/test_create.py
+++ b/tests/test_create.py
@@ -230,11 +230,21 @@ def test_create_install_update_remove(self):
     @pytest.mark.timeout(300)
     def test_list_with_pip_egg(self):
         with make_temp_env("python=3 pip") as prefix:
-            check_call(PYTHON_BINARY + " -m pip install --egg --no-use-wheel flask==0.10.1",
+            check_call(PYTHON_BINARY + " -m pip install --egg --no-binary flask flask==0.10.1",
                        cwd=prefix, shell=True)
             stdout, stderr = run_command(Commands.LIST, prefix)
             stdout_lines = stdout.split('\n')
-            assert any(line.endswith("<egg_info>") for line in stdout_lines
+            assert any(line.endswith("<pip>") for line in stdout_lines
+                       if line.lower().startswith("flask"))
+
+    @pytest.mark.timeout(300)
+    def test_list_with_pip_wheel(self):
+        with make_temp_env("python=3 pip") as prefix:
+            check_call(PYTHON_BINARY + " -m pip install flask==0.10.1",
+                       cwd=prefix, shell=True)
+            stdout, stderr = run_command(Commands.LIST, prefix)
+            stdout_lines = stdout.split('\n')
+            assert any(line.endswith("<pip>") for line in stdout_lines
                        if line.lower().startswith("flask"))
 
     @pytest.mark.timeout(300)