Repository: pypa/pip

Issue:
Why does pip wheel -r skip editable requirements?
After reading the [documentation](https://pip.pypa.io/en/stable/user_guide/#create-an-installation-bundle-with-compiled-dependencies), I'm hoping the release process for my project could look like this:

```
pip freeze -r dev-requirements.txt > release-requirements.txt
pip wheel -r release-requirements.txt --wheel-dir=release
```

Since my `dev-requirements.txt` contains editable references to several VCS controlled directories, `pip freeze` generates lines such as `-e git+git@github.com:...#egg=...`. That looks completely ok so far.

However `pip wheel` then says `Skipping bdist_wheel for ... due to being editable`, which is not good. Removing the -e in the frozen requirements does not help because `git+git@github.com:...` is not accepted as requirements lines.

So I'm wondering if the above `pip freeze` + `pip wheel` is a correct workflow (which I hope).

My main question being why pip wheel needs to skip editable packages. I found a [comment](https://github.com/pypa/pip/issues/1775#issuecomment-41638531) by @qwcode in #1775 hinting at something, but I could not understand the rationale. I my use case (ie releasing a project), it is perfectly desirable to have a wheel generated for editable requirements.



Discussion:
Well the point of installing an editable (`-e`) is to be able to edit the installed directory (without fiddling inside the site-packages). It is based on `setuptools`'s `develop` command and as such can not be installed via a wheel (at least not in a trivial way, since it does not contain any `setup.py` file).

You can however `pip wheel git+https://github.com/pypa/pip.git` or `pip wheel git+ssh://git@github.com/pypa/pip.git` (without the `-e` switch).

The `git+git@github.com:pypa/pip.git` syntax is currently not supported for non-editable install.


Resolving patch:
diff --git a/pip/commands/wheel.py b/pip/commands/wheel.py
--- a/pip/commands/wheel.py
+++ b/pip/commands/wheel.py
@@ -157,6 +157,8 @@ def run(self, options, args):
         if options.build_dir:
             options.build_dir = os.path.abspath(options.build_dir)
 
+        options.src_dir = os.path.abspath(options.src_dir)
+
         with self._build_session(options) as session:
             finder = self._build_package_finder(options, session)
             build_delete = (not (options.no_clean or options.build_dir))
diff --git a/pip/wheel.py b/pip/wheel.py
--- a/pip/wheel.py
+++ b/pip/wheel.py
@@ -759,11 +759,8 @@ def build(self, autobuilding=False):
                 if not autobuilding:
                     logger.info(
                         'Skipping %s, due to already being wheel.', req.name)
-            elif req.editable:
-                if not autobuilding:
-                    logger.info(
-                        'Skipping bdist_wheel for %s, due to being editable',
-                        req.name)
+            elif autobuilding and req.editable:
+                pass
             elif autobuilding and req.link and not req.link.is_artifact:
                 pass
             elif autobuilding and not req.source_dir:


Test patch:
diff --git a/tests/functional/test_wheel.py b/tests/functional/test_wheel.py
--- a/tests/functional/test_wheel.py
+++ b/tests/functional/test_wheel.py
@@ -74,6 +74,21 @@ def test_pip_wheel_builds_editable_deps(script, data):
     assert wheel_file_path in result.files_created, result.stdout
 
 
+@pytest.mark.network
+def test_pip_wheel_builds_editable(script, data):
+    """
+    Test 'pip wheel' builds an editable package
+    """
+    script.pip('install', 'wheel')
+    editable_path = os.path.join(data.src, 'simplewheel-1.0')
+    result = script.pip(
+        'wheel', '--no-index', '-e', editable_path
+    )
+    wheel_file_name = 'simplewheel-1.0-py%s-none-any.whl' % pyversion[0]
+    wheel_file_path = script.scratch / wheel_file_name
+    assert wheel_file_path in result.files_created, result.stdout
+
+
 @pytest.mark.network
 def test_pip_wheel_fail(script, data):
     """
diff --git a/tests/unit/test_wheel.py b/tests/unit/test_wheel.py
--- a/tests/unit/test_wheel.py
+++ b/tests/unit/test_wheel.py
@@ -380,16 +380,6 @@ def test_skip_building_wheels(self, caplog):
             assert "due to already being wheel" in caplog.text()
             assert mock_build_one.mock_calls == []
 
-    def test_skip_building_editables(self, caplog):
-        with patch('pip.wheel.WheelBuilder._build_one') as mock_build_one:
-            editable = Mock(editable=True, is_wheel=False, constraint=False)
-            reqset = Mock(requirements=Mock(values=lambda: [editable]),
-                          wheel_download_dir='/wheel/dir')
-            wb = wheel.WheelBuilder(reqset, Mock())
-            wb.build()
-            assert "due to being editable" in caplog.text()
-            assert mock_build_one.mock_calls == []
-
 
 class TestWheelCache: