Repository: pypa/setuptools

Issue:
bootstrap script cannot be executed without setuptools already installed
The `bootstrap.py` script cannot be used to bootstrap from an environment without setuptools.  The script imports `pip` which requires setuptools to be be installed.  This behavior was introduced in #933.


Discussion:
Thanks for sharing. Do you think it should do anything differently?
In previous versions of `setuptools` (for example 33.1.0) is was possible to use the `bootstrap.py` script to install `setuptools` into an environment which contained only Python (no `pip`, `setuptools`, or `wheel` packages installed).  This behavior was very helpful for downstream distributors who want to create packages of setuptools.  The currently behavior creates a circular dependency (`setuptools` requires `pip` which requires `setuptools`) which makes packaging difficult.  Providing a method to install `setuptools` into a bare Python environment would be very helpful.

My own needs for this is for [conda-forge](http://conda-forge.github.io/).  We create separate conda packages for `python`, `setuptools`, `pip` and `wheel` so that they can be upgraded independently.  Our build order for these packages was `python`, `setuptools`, `wheel` and then `pip`.  The new requirements on `pip` to install `setuptools` is causing some issues with this build order.
I see. The issue is that Setuptools is seeking specifically to reverse that dependency. The responsibility for installing packages is being delegated to pip, and that's a more fundamental responsibility than that of building packages, for which setuptools will play a key role.

In that sense, I'd recommend you build packages in this order - `python`, `pip`, `wheel`, `setuptools` (or maybe setuptools before wheel).

Strictly speaking, pip doesn't depend on setuptools. Setuptools is required to build some packages (from source), but not for installing wheels. Setuptools is an optional dependency.

Is it possible with this different perspective that conda-forge can be adapted to work in this new model?

Alternatively, conda-forge could be responsible for retrieving build dependencies and bootstrapping the project. If it makes sense to separate the two responsibilities that `bootstrap.py` is performing, that would be possible.
Thanks for the explanation.  I think I understand the rational behind the change and agree that it is a good step forward.  

The issue that I think conda-forge and other re-packagers may have is that pip uses setuptools to install itself. Although setuptools does not seem to be required at run-time many include it as a pip dependency.

I believe that separating the two tasks in the `bootstrap.py` script, retrieving build dependencies and bootstrapping the project, would make is easier for various projects, including conda-forge, to package setuptools.  In conda-forge we have other means to provide the build dependencies and an method to opt-out of pip providing these would be helpful.  I can put together a PR with a possible implementation if it would help.
Yes, that would be helpful and most appreciated.

Resolving patch:
diff --git a/bootstrap.py b/bootstrap.py
--- a/bootstrap.py
+++ b/bootstrap.py
@@ -7,6 +7,7 @@
 
 from __future__ import unicode_literals
 
+import argparse
 import os
 import io
 import re
@@ -17,7 +18,6 @@
 import textwrap
 import subprocess
 
-import pip
 
 minimal_egg_info = textwrap.dedent("""
     [distutils.commands]
@@ -75,6 +75,7 @@ def gen_deps():
 @contextlib.contextmanager
 def install_deps():
     "Just in time make the deps available"
+    import pip
     gen_deps()
     tmpdir = tempfile.mkdtemp()
     args = [
@@ -91,6 +92,15 @@ def install_deps():
 
 
 if __name__ == '__main__':
+    parser = argparse.ArgumentParser(description='bootstrap setuptools')
+    parser.add_argument(
+        '--skip-dep-install', action='store_true',
+        help=("Do not attempt to install setuptools dependencies. These "
+              "should be provided in the environment in another manner."))
+    args = parser.parse_args()
     ensure_egg_info()
-    with install_deps():
+    if args.skip_dep_install:
         run_egg_info()
+    else:
+        with install_deps():
+            run_egg_info()


Test patch: