diff --git a/.github/workflows/core.yml b/.github/workflows/core.yml index f04085bbe2..4b782cc9c7 100644 --- a/.github/workflows/core.yml +++ b/.github/workflows/core.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - python-version: [3.7, 3.9, '3.11', pypy-3.9] + python-version: [3.7, 3.9, 3.11, 3.12, pypy-3.9] cpp-version: [g++-8, clang-7] steps: - uses: actions/checkout@v2 @@ -24,7 +24,8 @@ jobs: run: | python -m pip install --upgrade pip pip install -r requirements.txt - pip install ipython nbval pytest-xdist cython wheel + pip install -r pythran/tests/requirements.txt + pip install pytest-xdist sudo apt install libopenblas-dev ${{ matrix.cpp-version }} if test ${{ matrix.python-version }} != 'pypy-3.9'; then pip install scipy ; fi - name: Setup diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index dd24bef358..356e2a83bf 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -24,7 +24,8 @@ jobs: run: | python -m pip install --upgrade pip pip install -r requirements.txt - pip install ipython nbval pytest-xdist cython scipy wheel + pip install -r pythran/tests/requirements.txt scipy + pip install pytest-xdist sudo apt install libopenblas-dev ${{ matrix.cpp-version }} - name: Setup run: | diff --git a/.github/workflows/icc.yml b/.github/workflows/icc.yml index f2efce2d80..38a9f62739 100644 --- a/.github/workflows/icc.yml +++ b/.github/workflows/icc.yml @@ -24,7 +24,8 @@ jobs: run: | python -m pip install --upgrade pip pip install -r requirements.txt - pip install ipython nbval pytest-xdist cython wheel + pip install -r pythran/tests/requirements.txt + pip install pytest-xdist if test ${{ matrix.python-version }} != '3.10' ; then pip install scipy ; fi wget -O- https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB | gpg --dearmor | sudo tee /usr/share/keyrings/oneapi-archive-keyring.gpg echo "deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list diff --git a/.github/workflows/parallel.yml b/.github/workflows/parallel.yml index 7539e07c8a..ec469b581d 100644 --- a/.github/workflows/parallel.yml +++ b/.github/workflows/parallel.yml @@ -24,7 +24,8 @@ jobs: run: | python -m pip install --upgrade pip pip install -r requirements.txt - pip install ipython nbval pytest-xdist cython scipy wheel + pip install -r pythran/tests/requirements.txt scipy + pip install pytest-xdist sudo apt install libopenblas-dev ${{ matrix.cpp-version }} - name: Setup run: | diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 169d0c7af0..05447e2e3e 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -28,7 +28,8 @@ jobs: run: | python -m pip install --upgrade pip pip install -r requirements.txt - pip install scipy wheel pythran-openblas pytest + pip install -r pythran/tests/requirements.txt scipy + pip install pythran-openblas pytest - name: Setup run: | python setup.py install diff --git a/docs/DEVGUIDE.rst b/docs/DEVGUIDE.rst index ad2b84a1fe..36bc1a7664 100644 --- a/docs/DEVGUIDE.rst +++ b/docs/DEVGUIDE.rst @@ -68,8 +68,12 @@ Validation ---------- ``pythran`` uses the ``unittest`` module and the `pytest -`_ package to manage test cases. The whole -validation suite is run through the command:: +`_ package to manage test cases. + +All requirements are listed in ``pythran/tests/requirements.txt``. + + +The whole validation suite is run through the command:: $> python -m pytest pythran/tests diff --git a/pythran/config.py b/pythran/config.py index d119a68c94..bfaaa69339 100644 --- a/pythran/config.py +++ b/pythran/config.py @@ -246,26 +246,20 @@ def parse_define(define): extension['define_macros'].append('PYTHRAN_BLAS_NONE') if user_blas not in reserved_blas_entries: - if sys.version_info < (3, 12): - # `numpy.distutils` not present for Python >= 3.12 - try: - import numpy.distutils.system_info as numpy_sys - # Numpy can pollute stdout with checks - with silent(): - numpy_blas = numpy_sys.get_info(user_blas) - # required to cope with atlas missing extern "C" - extension['define_macros'].append('PYTHRAN_BLAS_{}' - .format(user_blas.upper())) - extension['libraries'].extend(numpy_blas.get('libraries', [])) - extension['library_dirs'].extend( - numpy_blas.get('library_dirs', [])) - extension['include_dirs'].extend( - numpy_blas.get('include_dirs', [])) - except Exception as exc: - raise RuntimeError( - "The likely cause of this failure is an incompatibility " - "between `setuptools` and `numpy.distutils. " - ) from exc + try: + import numpy.distutils.system_info as numpy_sys + # Numpy can pollute stdout with checks + with silent(): + numpy_blas = numpy_sys.get_info(user_blas) + extension['libraries'].extend(numpy_blas.get('libraries', [])) + extension['library_dirs'].extend( + numpy_blas.get('library_dirs', [])) + # `numpy.distutils` not present for Python >= 3.12 + except ImportError: + blas = numpy.show_config('dicts')["Build Dependencies"]["blas"] + libblas = {'openblas64': 'openblas'}.get(blas['name'], blas['name']) + extension["libraries"].append(libblas) + # final macro normalization extension["define_macros"] = [ diff --git a/pythran/dist.py b/pythran/dist.py index 0a3abffee9..fc975a9bf9 100644 --- a/pythran/dist.py +++ b/pythran/dist.py @@ -13,14 +13,17 @@ import os.path import os -from distutils.command.build_ext import build_ext as LegacyBuildExt +try: + from distutils.command.build_ext import build_ext as LegacyBuildExt +except ImportError: + from setuptools.command.build_ext import build_ext as LegacyBuildExt try: # `numpy.distutils` is deprecated, and won't be present on Python >=3.12 # If it is installed, we need to use it though, so try-import it: from numpy.distutils.extension import Extension except ImportError: - from distutils.extension import Extension + from setuptools.extension import Extension diff --git a/pythran/tests/requirements.txt b/pythran/tests/requirements.txt new file mode 100644 index 0000000000..2b2e3b9020 --- /dev/null +++ b/pythran/tests/requirements.txt @@ -0,0 +1,4 @@ +ipython +nbval +cython +wheel diff --git a/pythran/tests/test_distutils.py b/pythran/tests/test_distutils.py index 2e194e94d8..90eb570cc7 100644 --- a/pythran/tests/test_distutils.py +++ b/pythran/tests/test_distutils.py @@ -29,7 +29,10 @@ class TestDistutils(unittest.TestCase): def test_setup_build(self): check_call([python, 'setup.py', 'build'], cwd=os.path.join(cwd, 'test_distutils')) - check_call([python, '-m', 'pip', 'install', '.', '--prefix=demo_install'], + + extra_args = ['--no-build-isolation',] + check_call([python, '-m', 'pip', 'install', '.', + '--prefix=demo_install'] + extra_args, cwd=os.path.join(cwd, 'test_distutils')) base = os.path.join(cwd, 'test_distutils', 'demo_install',) @@ -81,7 +84,10 @@ def test_setup_wheel_install(self): def test_setup_build2(self): check_call([python, 'setup.py', 'build'], cwd=os.path.join(cwd, 'test_distutils_packaged')) - check_call([python, '-m', 'pip', 'install', '.', '--prefix=demo_install2'], + + extra_args = ['--no-build-isolation',] + check_call([python, '-m', 'pip', 'install', '.', + '--prefix=demo_install2'] + extra_args, cwd=os.path.join(cwd, 'test_distutils_packaged')) base = os.path.join(cwd, 'test_distutils_packaged', 'demo_install2',) @@ -116,19 +122,30 @@ def test_setup_bdist_install2(self): self.assertIsNotNone(demo_so) shutil.rmtree(dist_path) + @unittest.skipIf(sys.version_info >= (3, 12), "setup install is deprecated") def test_setup_build3(self): check_call([python, 'setup.py', 'build'], cwd=os.path.join(cwd, 'test_distutils_numpy')) - check_call([python, 'setup.py', 'install', '--prefix=demo_install3'], - cwd=os.path.join(cwd, 'test_distutils_numpy')) base = os.path.join(cwd, 'test_distutils_numpy', 'demo_install3',) libdir = os.path.join(base, 'lib') - if not os.path.isdir(libdir): - libdir = os.path.join(base, 'lib64') - check_call([python, '-c', 'import a'], - cwd=os.path.join(libdir, python_version, 'site-packages', - 'demo3')) + lib64dir = os.path.join(base, 'lib64') + + local_env = os.environ.copy() + local_env['PYTHONPATH'] = os.pathsep.join(( + os.path.join(lib64dir, python_version, + 'site-packages'), + os.path.join(libdir, python_version, + 'site-packages'), + local_env.get('PYTHONPATH', ''), + )) + + check_call([python, 'setup.py', 'install', '--prefix=demo_install3'], + cwd=os.path.join(cwd, 'test_distutils_numpy'), + env=local_env) + + check_call([python, '-c', 'import demo3.a'], + cwd=cwd, env=local_env) check_call([python, 'setup.py', 'clean'], cwd=os.path.join(cwd, 'test_distutils_numpy')) shutil.rmtree(os.path.join(cwd, 'test_distutils_numpy', 'demo_install3')) diff --git a/pythran/tests/test_distutils_numpy/setup.py b/pythran/tests/test_distutils_numpy/setup.py index 962afe5010..15af0f49dd 100644 --- a/pythran/tests/test_distutils_numpy/setup.py +++ b/pythran/tests/test_distutils_numpy/setup.py @@ -1,5 +1,10 @@ -from numpy.distutils.core import setup -from numpy.distutils.command.build_ext import build_ext as npy_build_ext +try: + from numpy.distutils.core import setup + from numpy.distutils.command.build_ext import build_ext as npy_build_ext +except ImportError: + from distutils.core import setup + from distutils.command.build_ext import build_ext as npy_build_ext + from pythran.dist import PythranExtension, PythranBuildExt module1 = PythranExtension('demo3.a', sources = ['demo3/a.py']) diff --git a/pythran/toolchain.py b/pythran/toolchain.py index d5e73d58ca..879b9f20ad 100644 --- a/pythran/toolchain.py +++ b/pythran/toolchain.py @@ -22,13 +22,17 @@ from pythran.utils import cxxid import pythran.frontend as frontend -from distutils.errors import CompileError -from distutils import sysconfig +try: + from distutils.errors import CompileError + from distutils import sysconfig +except ImportError: + from setuptools.errors import CompileError + from setuptools._distutils import sysconfig try: # `numpy.distutils is deprecated, may not be present, or broken from numpy.distutils.core import setup except Exception: - from distutils.core import setup + from setuptools import setup from tempfile import mkdtemp, NamedTemporaryFile import gast as ast diff --git a/requirements.txt b/requirements.txt index 080b2a85c9..fd6a738e51 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ ply>=3.4 +setuptools gast~=0.5.0 numpy beniget~=0.4.0