Repository: scikit-image/scikit-image

Issue:
scikit-image is not installable from source
## Description

I cannot install skimage from its source tarball on pypi. It fails because numpy.distutils is a build-time dependency, but setup.py does not declare it to be one.

## Way to reproduce
```bash
python -m virtualenv .venv
. .venv/bin/activate
pip install scikit-image@https://files.pythonhosted.org/packages/54/fd/c1b0bb8f6f12ef9b4ee8d7674dac82cd482886f8b5cd165631efa533e237/scikit-image-0.17.2.tar.gz
```

As a result, only platforms for which a wheel has been pre-built and posted to https://pypi.org/project/scikit-image/#files can use it. Most platforms are covered, but on python3.9 or macOS 10.12

```
pip install scikit-image
```

fails.

The workaround is to do

```
pip install numpy
pip install scikit-image
```

(`pip install numpy scikit-image` *will not work*: this form of pip installs everything in a batch at the end, after building each, which of course it can't do:

<details>

```
$ pip install numpy scikit-image@https://files.pythonhosted.org/packages/54/fd/c1b0bb8f6f12ef9b4ee8d7674dac82cd482886f8b5cd165631efa533e237/scikit-image-0.17.2.tar.gz
Collecting numpy
  Using cached numpy-1.19.1-cp36-cp36m-manylinux2010_x86_64.whl (14.5 MB)
Collecting scikit-image@ https://files.pythonhosted.org/packages/54/fd/c1b0bb8f6f12ef9b4ee8d7674dac82cd482886f8b5cd165631efa533e237/scikit-image-0.17.2.tar.gz
  Using cached scikit-image-0.17.2.tar.gz (29.8 MB)
    ERROR: Command errored out with exit status 1:
     command: /home/kousu/src/neuropoly/.venv36/bin/python -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-ab_ucb20/scikit-image/setup.py'"'"'; __file__='"'"'/tmp/pip-install-ab_ucb20/scikit-image/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' egg_info --egg-base /tmp/pip-pip-egg-info-h6tg6lsv
         cwd: /tmp/pip-install-ab_ucb20/scikit-image/
    Complete output (7 lines):
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-install-ab_ucb20/scikit-image/setup.py", line 234, in <module>
        'build_ext': openmp_build_ext(),
      File "/tmp/pip-install-ab_ucb20/scikit-image/setup.py", line 58, in openmp_build_ext
        from numpy.distutils.command.build_ext import build_ext
    ModuleNotFoundError: No module named 'numpy'
    ----------------------------------------
ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.
WARNING: You are using pip version 20.2.1; however, version 20.2.2 is available.
You should consider upgrading via the '/home/kousu/src/neuropoly/.venv36/bin/python -m pip install --upgrade pip' command.
```
</details> )

but this is weird. It means that I can't really make a package that depends on `scikit-image` where `pip install $pkg` works. Instead I need provide an install script with the workaround, or say that I can only support what your build server supports.

## Version information
```python
# Paste the output of the following python commands
>>> from __future__ import print_function
>>> import sys; print(sys.version)
3.6.6 (default, Aug  9 2020, 09:22:17) 
[GCC 10.1.0]
>>> import platform; print(platform.platform())
Linux-5.7.6-arch1-1-x86_64-with-arch
>>> import skimage; print("scikit-image version: {}".format(skimage.__version__))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'skimage'
>>> import numpy; print("numpy version: {}".format(numpy.__version__))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'numpy'
```

```python
# your output here
$ pip install scikit-image@https://files.pythonhosted.org/packages/54/fd/c1b0bb8f6f12ef9b4ee8d7674dac82cd482886f8b5cd165631efa533e237/scikit-image-0.17.2.tar.gz
Collecting scikit-image@ https://files.pythonhosted.org/packages/54/fd/c1b0bb8f6f12ef9b4ee8d7674dac82cd482886f8b5cd165631efa533e237/scikit-image-0.17.2.tar.gz
  Using cached scikit-image-0.17.2.tar.gz (29.8 MB)
    ERROR: Command errored out with exit status 1:
     command: /home/kousu/src/neuropoly/.venv36/bin/python -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-2c6ugifd/scikit-image/setup.py'"'"'; __file__='"'"'/tmp/pip-install-2c6ugifd/scikit-image/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' egg_info --egg-base /tmp/pip-pip-egg-info-m0fs0xn6
         cwd: /tmp/pip-install-2c6ugifd/scikit-image/
    Complete output (7 lines):
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-install-2c6ugifd/scikit-image/setup.py", line 234, in <module>
        'build_ext': openmp_build_ext(),
      File "/tmp/pip-install-2c6ugifd/scikit-image/setup.py", line 58, in openmp_build_ext
        from numpy.distutils.command.build_ext import build_ext
    ModuleNotFoundError: No module named 'numpy'
    ----------------------------------------
ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.
WARNING: You are using pip version 20.2.1; however, version 20.2.2 is available.
You should consider upgrading via the '/home/kousu/src/neuropoly/.venv36/bin/python -m pip install --upgrade pip' command.
```



Discussion:

Resolving patch:
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -155,9 +155,16 @@ def configuration(parent_package='', top_path=None):
 
 
 if __name__ == "__main__":
+    cmdclass = {'build_py': build_py,
+                'sdist': sdist}
     try:
+        # test if build dependencies exist.
+        # if not, some commands are still viable.
+        # note: this must be kept in sync with pyproject.toml
         from numpy.distutils.core import setup
+        import cython
         extra = {'configuration': configuration}
+        cmdclass['build_ext'] = openmp_build_ext()
     except ImportError:
         if len(sys.argv) >= 2 and ('--help' in sys.argv[1:] or
                                    sys.argv[1] in ('--help-commands',
@@ -165,12 +172,13 @@ def configuration(parent_package='', top_path=None):
                                                    'clean',
                                                    'egg_info',
                                                    'install_egg_info',
-                                                   'rotate')):
-            # For these actions, NumPy is not required.
+                                                   'rotate',
+                                                   'sdist')):
+            # For these actions, compilation is not required.
             #
-            # They are required to succeed without Numpy for example when
-            # pip is used to install scikit-image when Numpy is not yet
-            # present in the system.
+            # They are required to succeed for example when pip is
+            # used to install scikit-image when Numpy/cython are not
+            # yet present in the system.
             from setuptools import setup
             extra = {}
         else:
@@ -230,8 +238,6 @@ def configuration(parent_package='', top_path=None):
             'console_scripts': ['skivi = skimage.scripts.skivi:main'],
         },
 
-        cmdclass={'build_py': build_py,
-                  'build_ext': openmp_build_ext(),
-                  'sdist': sdist},
+        cmdclass=cmdclass,
         **extra
     )


Test patch: