| import os |
| import shutil |
| import subprocess |
| import sys |
| import sysconfig |
| import warnings |
| from importlib.util import module_from_spec, spec_from_file_location |
|
|
| import pytest |
|
|
| import numpy as np |
| from numpy.testing import IS_EDITABLE, IS_WASM |
|
|
| try: |
| import cffi |
| except ImportError: |
| cffi = None |
|
|
| if sys.flags.optimize > 1: |
| |
| |
| cffi = None |
|
|
| try: |
| with warnings.catch_warnings(record=True) as w: |
| |
| warnings.filterwarnings('always', '', DeprecationWarning) |
| import numba |
| except (ImportError, SystemError): |
| |
| numba = None |
|
|
| try: |
| import cython |
| from Cython.Compiler.Version import version as cython_version |
| except ImportError: |
| cython = None |
| else: |
| from numpy._utils import _pep440 |
| |
| required_version = '3.0.6' |
| if _pep440.parse(cython_version) < _pep440.Version(required_version): |
| |
| cython = None |
|
|
|
|
| @pytest.mark.skipif( |
| IS_EDITABLE, |
| reason='Editable install cannot find .pxd headers' |
| ) |
| @pytest.mark.skipif( |
| sys.platform == "win32" and sys.maxsize < 2**32, |
| reason="Failing in 32-bit Windows wheel build job, skip for now" |
| ) |
| @pytest.mark.skipif(IS_WASM, reason="Can't start subprocess") |
| @pytest.mark.skipif(cython is None, reason="requires cython") |
| @pytest.mark.skipif(sysconfig.get_platform() == 'win-arm64', |
| reason='Meson unable to find MSVC linker on win-arm64') |
| @pytest.mark.slow |
| @pytest.mark.thread_unsafe( |
| reason="building cython code in a subprocess doesn't make sense to do in many " |
| "threads and sometimes crashes" |
| ) |
| def test_cython(tmp_path): |
| import glob |
| |
| srcdir = os.path.join(os.path.dirname(__file__), '..') |
| shutil.copytree(srcdir, tmp_path / 'random') |
| build_dir = tmp_path / 'random' / '_examples' / 'cython' |
| target_dir = build_dir / "build" |
| os.makedirs(target_dir, exist_ok=True) |
| |
| |
| native_file = str(build_dir / 'interpreter-native-file.ini') |
| with open(native_file, 'w') as f: |
| f.write("[binaries]\n") |
| f.write(f"python = '{sys.executable}'\n") |
| f.write(f"python3 = '{sys.executable}'") |
| if sys.platform == "win32": |
| subprocess.check_call(["meson", "setup", |
| "--buildtype=release", |
| "--vsenv", "--native-file", native_file, |
| str(build_dir)], |
| cwd=target_dir, |
| ) |
| else: |
| subprocess.check_call(["meson", "setup", |
| "--native-file", native_file, str(build_dir)], |
| cwd=target_dir |
| ) |
| subprocess.check_call(["meson", "compile", "-vv"], cwd=target_dir) |
|
|
| |
| |
|
|
| g = glob.glob(str(target_dir / "*" / "extending.pyx.c")) |
| with open(g[0]) as fid: |
| txt_to_find = 'NumPy API declarations from "numpy/__init__' |
| for line in fid: |
| if txt_to_find in line: |
| break |
| else: |
| assert False, f"Could not find '{txt_to_find}' in C file, wrong pxd used" |
| |
| suffix = sysconfig.get_config_var('EXT_SUFFIX') |
|
|
| def load(modname): |
| so = (target_dir / modname).with_suffix(suffix) |
| spec = spec_from_file_location(modname, so) |
| mod = module_from_spec(spec) |
| spec.loader.exec_module(mod) |
| return mod |
|
|
| |
| load("extending") |
| load("extending_cpp") |
| |
| extending_distributions = load("extending_distributions") |
| from numpy.random import PCG64 |
| values = extending_distributions.uniforms_ex(PCG64(0), 10, 'd') |
| assert values.shape == (10,) |
| assert values.dtype == np.float64 |
|
|
| @pytest.mark.skipif(numba is None or cffi is None, |
| reason="requires numba and cffi") |
| def test_numba(): |
| from numpy.random._examples.numba import extending |
|
|
| @pytest.mark.skipif(cffi is None, reason="requires cffi") |
| def test_cffi(): |
| from numpy.random._examples.cffi import extending |
|
|