Repository: esheldon/pymangle (language: python)

Issue:
Setup numpy
This PR add ``numpy`` as a build requirements and import it into a custom ``build_ext`` class (I was inspired by [this answer](http://stackoverflow.com/a/21621689/1860757)).

I have also added a tox file that runs tests for python 2.7, 3.4, 3.5 and 3.6 with and without installing ``numpy`` before building ``pymangle``. The test for now is simply to import pymangle and make sure that the ``Mangle`` class and the ``__version__`` can be accessed.

All the tests pass, which means that ``pymangle`` can now build also on systems where numpy is not already installed.
Setup numpy
This PR add ``numpy`` as a build requirements and import it into a custom ``build_ext`` class (I was inspired by [this answer](http://stackoverflow.com/a/21621689/1860757)).

I have also added a tox file that runs tests for python 2.7, 3.4, 3.5 and 3.6 with and without installing ``numpy`` before building ``pymangle``. The test for now is simply to import pymangle and make sure that the ``Mangle`` class and the ``__version__`` can be accessed.

All the tests pass, which means that ``pymangle`` can now build also on systems where numpy is not already installed.
Add numpy to setup_requires
Could you add `numpy` to `setup_requires` and wrap the extension build inside a custom `build_ext` class? Right now `pymangle` can only be installed if numpy is already installed. This breaks many workflows and makes installing tools that depend on `pymangle` in CI environments quite complicated. 


Discussion / hints:

Fix patch:
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..990256a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+.tox
+MANIFEST
+.cache
+pymangle.egg-info
+pymangle/*pyc
+__pycache__
diff --git a/pymangle/mangle.py b/pymangle/mangle.py
index 71105e7..f20d3ea 100644
--- a/pymangle/mangle.py
+++ b/pymangle/mangle.py
@@ -16,7 +16,7 @@
 # we also grab the doc strings from the C code as needed,
 # only writing new ones in the over-ridden methods
 
-from __future__ import print_function
+from __future__ import print_function, absolute_import
 
 from numpy import array
 from . import _mangle
diff --git a/setup.py b/setup.py
index 84a8116..469aedd 100644
--- a/setup.py
+++ b/setup.py
@@ -1,22 +1,30 @@
-import setuptools
-import numpy
-
-sources = [
-    "pymangle/_mangle.c",
-    "pymangle/mangle.c",
-    "pymangle/cap.c",
-    "pymangle/polygon.c",
-    "pymangle/pixel.c",
-    "pymangle/point.c",
-    "pymangle/stack.c",
-    "pymangle/rand.c",
-]
-
-ext = setuptools.Extension(
-    "pymangle._mangle",
-    sources,
-    include_dirs=[numpy.get_include()],
-)
+import glob
+
+from setuptools import setup
+from setuptools.extension import Extension
+from setuptools.command import build_ext
+
+
+ext = Extension("pymangle._mangle", ["pymangle/_mangle.c",
+                                     "pymangle/mangle.c",
+                                     "pymangle/cap.c",
+                                     "pymangle/polygon.c",
+                                     "pymangle/pixel.c",
+                                     "pymangle/point.c",
+                                     "pymangle/stack.c",
+                                     "pymangle/rand.c"])
+
+
+class BuildExt(build_ext.build_ext):
+    '''Custom build_ext command to hide the numpy import
+    Inspired by http://stackoverflow.com/a/21621689/1860757'''
+    def finalize_options(self):
+        '''add numpy includes to the include dirs'''
+        build_ext.build_ext.finalize_options(self)
+        import numpy as np
+        self.include_dirs.append(np.get_include())
+        self.include_dirs.extend(glob.glob("pymangle/*h"))
+
 
 exec(open('pymangle/version.py').read())
 
@@ -25,14 +33,16 @@
 with open('README.md') as fobj:
     long_description = fobj.read()
 
-setuptools.setup(
-    name="pymangle",
-    packages=['pymangle'],
-    description=description,
-    long_description=long_description,
-    long_description_content_type='text/markdown',
-    version=__version__,
-    license="GPL",
-    ext_modules=[ext],
-    include_dirs=numpy.get_include(),
-)
+setup(name="pymangle",
+      packages=['pymangle'],
+      description=description,
+      long_description=long_description,
+      long_description_content_type='text/markdown',
+      version=__version__,
+      license="GPL",
+      install_requires=['numpy'],
+      ext_modules=[ext],
+      setup_requires=['numpy'],
+      cmdclass={'build_ext': BuildExt},
+      include_package_data=True,
+      )
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000..9695c31
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,12 @@
+[tox]
+envlist = py{27,34,35,36}-{np,nonp}
+skip_missing_interpreters = true
+
+[testenv]
+
+deps = 
+    pytest
+    np: numpy
+
+commands = 
+    py.test {posargs}


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 88696bc..f805d34 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -13,7 +13,7 @@ jobs:
       matrix:
         pyver: [3.6, 3.7, 3.8]
 
-    runs-on: "ubuntu-latest"
+    runs-on: 'ubuntu-latest'
 
     steps:
       - uses: actions/checkout@v2
@@ -29,16 +29,15 @@ jobs:
         shell: bash -l {0}
         run: |
           conda config --set always_yes yes
-          conda install --quiet setuptools numpy flake8
+          conda install --quiet setuptools flake8
 
           python -m pip install -e .
 
       - name: lint
         shell: bash -l {0}
         run: |
-            flake8 pymangle
+          flake8 pymangle
       - name: test
         shell: bash -l {0}
         run: |
           python -c 'import pymangle; pymangle.test.test()'
-
diff --git a/tests/test_import.py b/tests/test_import.py
new file mode 100644
index 0000000..6427412
--- /dev/null
+++ b/tests/test_import.py
@@ -0,0 +1,9 @@
+"test that pymangle is correctly imported"
+
+import pymangle
+
+
+def test_Mangle():
+    '''Check that is imported and that the Mangle class exists'''
+    pymangle.Mangle
+    pymangle.__version__