diff --git a/.gitignore b/.gitignore index b0117ba..b773865 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ __pycache__/ mkl_fft/_pydfti.c mkl_fft/_pydfti.cpython*.so +mkl_fft/_pydfti.*-win_amd64.pyd mkl_fft/src/mklfft.c diff --git a/README.md b/README.md index 31f4462..8f865fd 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,7 @@ To build `mkl_fft` from sources on Linux with IntelĀ® OneMKL: - `git clone https://github.com/IntelPython/mkl_fft.git mkl_fft` - `cd mkl_fft` - `python -m pip install .` + - `pip install scipy` (optional: for using `mkl_fft.interface.scipy_fft` module) - `cd ..` - `python -c "import mkl_fft"` @@ -103,5 +104,6 @@ To build `mkl_fft` from sources on Linux with conda follow these steps: - `git clone https://github.com/IntelPython/mkl_fft.git mkl_fft` - `cd mkl_fft` - `python -m pip install .` + - `conda install scipy` (optional: for using `mkl_fft.interface.scipy_fft` module) - `cd ..` - `python -c "import mkl_fft"` diff --git a/conda-recipe-cf/meta.yaml b/conda-recipe-cf/meta.yaml index db5a16d..20c1a62 100644 --- a/conda-recipe-cf/meta.yaml +++ b/conda-recipe-cf/meta.yaml @@ -32,7 +32,7 @@ test: - pytest -v --pyargs mkl_fft requires: - pytest - - scipy + - scipy >=1.10 imports: - mkl_fft - mkl_fft.interfaces diff --git a/conda-recipe/meta.yaml b/conda-recipe/meta.yaml index d3e3951..2eeccb2 100644 --- a/conda-recipe/meta.yaml +++ b/conda-recipe/meta.yaml @@ -33,7 +33,7 @@ test: - pytest -v --pyargs mkl_fft requires: - pytest - - scipy + - scipy >=1.10 imports: - mkl_fft - mkl_fft.interfaces diff --git a/mkl_fft/interfaces/__init__.py b/mkl_fft/interfaces/__init__.py index 6056350..1988ba8 100644 --- a/mkl_fft/interfaces/__init__.py +++ b/mkl_fft/interfaces/__init__.py @@ -23,4 +23,11 @@ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -from . import numpy_fft, scipy_fft +from . import numpy_fft + +try: + import scipy.fft +except ImportError: + pass +else: + from . import scipy_fft diff --git a/mkl_fft/tests/test_interfaces.py b/mkl_fft/tests/test_interfaces.py index 0a09369..226d462 100644 --- a/mkl_fft/tests/test_interfaces.py +++ b/mkl_fft/tests/test_interfaces.py @@ -29,12 +29,26 @@ import mkl_fft.interfaces as mfi +try: + scipy_fft = mfi.scipy_fft +except AttributeError: + scipy_fft = None + +interfaces = [] +ids = [] +if scipy_fft is not None: + interfaces.append(scipy_fft) + ids.append("scipy") +interfaces.append(mfi.numpy_fft) +ids.append("numpy") + @pytest.mark.parametrize("norm", [None, "forward", "backward", "ortho"]) @pytest.mark.parametrize( "dtype", [np.float32, np.float64, np.complex64, np.complex128] ) def test_scipy_fft(norm, dtype): + pytest.importorskip("scipy", reason="requires scipy") x = np.ones(511, dtype=dtype) w = mfi.scipy_fft.fft(x, norm=norm, workers=None, plan=None) xx = mfi.scipy_fft.ifft(w, norm=norm, workers=None, plan=None) @@ -57,6 +71,7 @@ def test_numpy_fft(norm, dtype): @pytest.mark.parametrize("norm", [None, "forward", "backward", "ortho"]) @pytest.mark.parametrize("dtype", [np.float32, np.float64]) def test_scipy_rfft(norm, dtype): + pytest.importorskip("scipy", reason="requires scipy") x = np.ones(511, dtype=dtype) w = mfi.scipy_fft.rfft(x, norm=norm, workers=None, plan=None) xx = mfi.scipy_fft.irfft( @@ -87,6 +102,7 @@ def test_numpy_rfft(norm, dtype): "dtype", [np.float32, np.float64, np.complex64, np.complex128] ) def test_scipy_fftn(norm, dtype): + pytest.importorskip("scipy", reason="requires scipy") x = np.ones((37, 83), dtype=dtype) w = mfi.scipy_fft.fftn(x, norm=norm, workers=None, plan=None) xx = mfi.scipy_fft.ifftn(w, norm=norm, workers=None, plan=None) @@ -109,6 +125,7 @@ def test_numpy_fftn(norm, dtype): @pytest.mark.parametrize("norm", [None, "forward", "backward", "ortho"]) @pytest.mark.parametrize("dtype", [np.float32, np.float64]) def test_scipy_rfftn(norm, dtype): + pytest.importorskip("scipy", reason="requires scipy") x = np.ones((37, 83), dtype=dtype) w = mfi.scipy_fft.rfftn(x, norm=norm, workers=None, plan=None) xx = mfi.scipy_fft.irfftn(w, s=x.shape, norm=norm, workers=None, plan=None) @@ -143,11 +160,13 @@ def _get_blacklisted_dtypes(): @pytest.mark.parametrize("dtype", _get_blacklisted_dtypes()) def test_scipy_no_support_for(dtype): + pytest.importorskip("scipy", reason="requires scipy") x = np.ones(16, dtype=dtype) assert_raises(NotImplementedError, mfi.scipy_fft.ifft, x) def test_scipy_fft_arg_validate(): + pytest.importorskip("scipy", reason="requires scipy") with pytest.raises(ValueError): mfi.scipy_fft.fft([1, 2, 3, 4], norm=b"invalid") @@ -155,20 +174,16 @@ def test_scipy_fft_arg_validate(): mfi.scipy_fft.fft([1, 2, 3, 4], plan="magic") -@pytest.mark.parametrize( - "func", [mfi.scipy_fft.rfft2, mfi.numpy_fft.rfft2], ids=["scipy", "numpy"] -) -def test_axes(func): +@pytest.mark.parametrize("interface", interfaces, ids=ids) +def test_axes(interface): x = np.arange(24.0).reshape(2, 3, 4) - res = func(x, axes=(1, 2)) + res = interface.rfft2(x, axes=(1, 2)) exp = np.fft.rfft2(x, axes=(1, 2)) tol = 64 * np.finfo(np.float64).eps assert np.allclose(res, exp, atol=tol, rtol=tol) -@pytest.mark.parametrize( - "interface", [mfi.scipy_fft, mfi.numpy_fft], ids=["scipy", "numpy"] -) +@pytest.mark.parametrize("interface", interfaces, ids=ids) @pytest.mark.parametrize( "func", ["fftshift", "ifftshift", "fftfreq", "rfftfreq"] ) diff --git a/mkl_fft/tests/third_party/scipy/test_basic.py b/mkl_fft/tests/third_party/scipy/test_basic.py index f05034c..c18c593 100644 --- a/mkl_fft/tests/third_party/scipy/test_basic.py +++ b/mkl_fft/tests/third_party/scipy/test_basic.py @@ -7,22 +7,26 @@ import numpy as np import pytest -import scipy from numpy.random import random from numpy.testing import assert_allclose, assert_array_almost_equal from pytest import raises as assert_raises # pylint: disable=possibly-used-before-assignment -if scipy.__version__ < "1.12": - # scipy from Intel channel is 1.10 with python 3.9 and 3.10 - pytest.skip("This test file needs scipy>=1.12", allow_module_level=True) -elif scipy.__version__ < "1.14": - # For python-3.11 and 3.12, scipy<1.14 is installed from Intel channel - # For python<=3.9, scipy<1.14 is installed from conda channel - # pylint: disable=no-name-in-module - from scipy._lib._array_api import size as xp_size +try: + import scipy +except ImportError: + pytest.skip("This test file needs scipy", allow_module_level=True) else: - from scipy._lib._array_api import xp_size + if np.lib.NumpyVersion(scipy.__version__) < "1.12.0": + # scipy from Intel channel is 1.10 with python 3.9 and 3.10 + pytest.skip("This test file needs scipy>=1.12", allow_module_level=True) + elif np.lib.NumpyVersion(scipy.__version__) < "1.14.0": + # For python-3.11 and 3.12, scipy<1.14 is installed from Intel channel + # For python<=3.9, scipy<1.14 is installed from conda channel + # pylint: disable=no-name-in-module + from scipy._lib._array_api import size as xp_size + else: + from scipy._lib._array_api import xp_size from scipy._lib._array_api import is_numpy, xp_assert_close, xp_assert_equal diff --git a/mkl_fft/tests/third_party/scipy/test_multithreading.py b/mkl_fft/tests/third_party/scipy/test_multithreading.py index ee5ec08..f948e22 100644 --- a/mkl_fft/tests/third_party/scipy/test_multithreading.py +++ b/mkl_fft/tests/third_party/scipy/test_multithreading.py @@ -8,7 +8,10 @@ import pytest from numpy.testing import assert_allclose -import mkl_fft.interfaces.scipy_fft as fft +try: + import mkl_fft.interfaces.scipy_fft as fft +except ImportError: + pytest.skip("This test file needs scipy", allow_module_level=True) @pytest.fixture(scope="module") diff --git a/pyproject.toml b/pyproject.toml index eefe397..55f31da 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,7 +59,8 @@ readme = {file = "README.md", content-type = "text/markdown"} requires-python = ">=3.9,<3.13" [project.optional-dependencies] -test = ["pytest", "scipy"] +scipy_interface = ["scipy>=1.10"] +test = ["pytest", "scipy>=1.10"] [project.urls] Download = "http://github.com/IntelPython/mkl_fft"