def gfortran_legacy_flag_hook(cmd, ext): """ Pre-build hook to add dd gfortran legacy flag -fallow-argument-mismatch """ from .compiler_helper import try_add_flag from scipy._lib import _pep440 if isinstance(ext, dict): # build_clib compilers = ((cmd._f_compiler, ext.setdefault('extra_f77_compile_args', [])), (cmd._f_compiler, ext.setdefault('extra_f90_compile_args', []))) else: # build_ext compilers = ((cmd._f77_compiler, ext.extra_f77_compile_args), (cmd._f90_compiler, ext.extra_f90_compile_args)) for compiler, args in compilers: if compiler is None: continue if (compiler.compiler_type == "gnu95" and _pep440.parse(str(compiler.version)) >= _pep440.Version("10")): try_add_flag(args, compiler, "-fallow-argument-mismatch")
if isinstance(value, (list, tuple)): if isinstance(old_value, (list, tuple)): new_dict[key] = list(old_value) + list(value) continue elif value == old_value: continue raise ValueError("Conflicting configuration dicts: {!r} {!r}" "".format(new_dict, d)) else: new_dict[key] = value return new_dict if _pep440.parse(np.__version__) >= _pep440.Version("1.15.0.dev"): # For new enough numpy.distutils, the ACCELERATE=None environment # variable in the top-level setup.py is enough, so no need to # customize BLAS detection. print("We are in the modern numpy, get_info = old_get_info") get_info = old_get_info else: # For NumPy < 1.15.0, we need overrides. def get_info(name, notfound_action=0): print("old numpy: ", np.__version__) # Special case our custom *_opt_info. cls = {'lapack_opt': lapack_opt_info, 'blas_opt': blas_opt_info}.get(name.lower()) if cls is None: return old_get_info(name, notfound_action)
msg = """Error importing SciPy: you cannot import SciPy while being in scipy source directory; please exit the SciPy source tree first and relaunch your Python interpreter.""" raise ImportError(msg) from e from scipy.version import version as __version__ # Allow distributors to run custom init code from . import _distributor_init from scipy._lib import _pep440 # In maintenance branch, change to np_maxversion N+3 if numpy is at N # See setup.py for more details np_minversion = '1.18.5' np_maxversion = '9.9.99' if (_pep440.parse(__numpy_version__) < _pep440.Version(np_minversion) or _pep440.parse(__numpy_version__) >= _pep440.Version(np_maxversion)): import warnings warnings.warn( f"A NumPy version >={np_minversion} and <{np_maxversion}" f" is required for this version of SciPy (detected " f"version {__numpy_version__}", UserWarning) del _pep440 from scipy._lib._ccallback import LowLevelCallable from scipy._lib._testutils import PytestTester test = PytestTester(__name__) del PytestTester
else: try: from scipy.__config__ import show as show_config except ImportError as e: msg = """Error importing SciPy: you cannot import SciPy while being in scipy source directory; please exit the SciPy source tree first and relaunch your Python interpreter.""" raise ImportError(msg) from e from scipy.version import version as __version__ # Allow distributors to run custom init code from . import _distributor_init from scipy._lib import _pep440 if _pep440.parse(__numpy_version__) < _pep440.Version('1.16.5'): import warnings warnings.warn("NumPy 1.16.5 or above is required for this version of " "SciPy (detected version %s)" % __numpy_version__, UserWarning) del _pep440 from scipy._lib._ccallback import LowLevelCallable from scipy._lib._testutils import PytestTester test = PytestTester(__name__) del PytestTester # This makes "from scipy import fft" return scipy.fft, not np.fft del fft
class TestInterop(object): # # Test that FITPACK-based spl* functions can deal with BSpline objects # def setup_method(self): xx = np.linspace(0, 4. * np.pi, 41) yy = np.cos(xx) b = make_interp_spline(xx, yy) self.tck = (b.t, b.c, b.k) self.xx, self.yy, self.b = xx, yy, b self.xnew = np.linspace(0, 4. * np.pi, 21) c2 = np.c_[b.c, b.c, b.c] self.c2 = np.dstack((c2, c2)) self.b2 = BSpline(b.t, self.c2, b.k) def test_splev(self): xnew, b, b2 = self.xnew, self.b, self.b2 # check that splev works with 1-D array of coefficients # for array and scalar `x` assert_allclose(splev(xnew, b), b(xnew), atol=1e-15, rtol=1e-15) assert_allclose(splev(xnew, b.tck), b(xnew), atol=1e-15, rtol=1e-15) assert_allclose([splev(x, b) for x in xnew], b(xnew), atol=1e-15, rtol=1e-15) # With N-D coefficients, there's a quirck: # splev(x, BSpline) is equivalent to BSpline(x) with suppress_warnings() as sup: sup.filter( DeprecationWarning, "Calling splev.. with BSpline objects with c.ndim > 1 is not recommended." ) assert_allclose(splev(xnew, b2), b2(xnew), atol=1e-15, rtol=1e-15) # However, splev(x, BSpline.tck) needs some transposes. This is because # BSpline interpolates along the first axis, while the legacy FITPACK # wrapper does list(map(...)) which effectively interpolates along the # last axis. Like so: sh = tuple(range(1, b2.c.ndim)) + (0, ) # sh = (1, 2, 0) cc = b2.c.transpose(sh) tck = (b2.t, cc, b2.k) assert_allclose(splev(xnew, tck), b2(xnew).transpose(sh), atol=1e-15, rtol=1e-15) def test_splrep(self): x, y = self.xx, self.yy # test that "new" splrep is equivalent to _impl.splrep tck = splrep(x, y) t, c, k = _impl.splrep(x, y) assert_allclose(tck[0], t, atol=1e-15) assert_allclose(tck[1], c, atol=1e-15) assert_equal(tck[2], k) # also cover the `full_output=True` branch tck_f, _, _, _ = splrep(x, y, full_output=True) assert_allclose(tck_f[0], t, atol=1e-15) assert_allclose(tck_f[1], c, atol=1e-15) assert_equal(tck_f[2], k) # test that the result of splrep roundtrips with splev: # evaluate the spline on the original `x` points yy = splev(x, tck) assert_allclose(y, yy, atol=1e-15) # ... and also it roundtrips if wrapped in a BSpline b = BSpline(*tck) assert_allclose(y, b(x), atol=1e-15) @pytest.mark.xfail( _pep440.parse(np.__version__) < _pep440.Version('1.14.0'), reason='requires NumPy >= 1.14.0') def test_splrep_errors(self): # test that both "old" and "new" splrep raise for an N-D ``y`` array # with n > 1 x, y = self.xx, self.yy y2 = np.c_[y, y] with assert_raises(ValueError): splrep(x, y2) with assert_raises(ValueError): _impl.splrep(x, y2) # input below minimum size with assert_raises(TypeError, match="m > k must hold"): splrep(x[:3], y[:3]) with assert_raises(TypeError, match="m > k must hold"): _impl.splrep(x[:3], y[:3]) def test_splprep(self): x = np.arange(15).reshape((3, 5)) b, u = splprep(x) tck, u1 = _impl.splprep(x) # test the roundtrip with splev for both "old" and "new" output assert_allclose(u, u1, atol=1e-15) assert_allclose(splev(u, b), x, atol=1e-15) assert_allclose(splev(u, tck), x, atol=1e-15) # cover the ``full_output=True`` branch (b_f, u_f), _, _, _ = splprep(x, s=0, full_output=True) assert_allclose(u, u_f, atol=1e-15) assert_allclose(splev(u_f, b_f), x, atol=1e-15) def test_splprep_errors(self): # test that both "old" and "new" code paths raise for x.ndim > 2 x = np.arange(3 * 4 * 5).reshape((3, 4, 5)) with assert_raises(ValueError, match="too many values to unpack"): splprep(x) with assert_raises(ValueError, match="too many values to unpack"): _impl.splprep(x) # input below minimum size x = np.linspace(0, 40, num=3) with assert_raises(TypeError, match="m > k must hold"): splprep([x]) with assert_raises(TypeError, match="m > k must hold"): _impl.splprep([x]) # automatically calculated parameters are non-increasing # see gh-7589 x = [-50.49072266, -50.49072266, -54.49072266, -54.49072266] with assert_raises(ValueError, match="Invalid inputs"): splprep([x]) with assert_raises(ValueError, match="Invalid inputs"): _impl.splprep([x]) # given non-increasing parameter values u x = [1, 3, 2, 4] u = [0, 0.3, 0.2, 1] with assert_raises(ValueError, match="Invalid inputs"): splprep(*[[x], None, u]) def test_sproot(self): b, b2 = self.b, self.b2 roots = np.array([0.5, 1.5, 2.5, 3.5]) * np.pi # sproot accepts a BSpline obj w/ 1-D coef array assert_allclose(sproot(b), roots, atol=1e-7, rtol=1e-7) assert_allclose(sproot((b.t, b.c, b.k)), roots, atol=1e-7, rtol=1e-7) # ... and deals with trailing dimensions if coef array is N-D with suppress_warnings() as sup: sup.filter( DeprecationWarning, "Calling sproot.. with BSpline objects with c.ndim > 1 is not recommended." ) r = sproot(b2, mest=50) r = np.asarray(r) assert_equal(r.shape, (3, 2, 4)) assert_allclose(r - roots, 0, atol=1e-12) # and legacy behavior is preserved for a tck tuple w/ N-D coef c2r = b2.c.transpose(1, 2, 0) rr = np.asarray(sproot((b2.t, c2r, b2.k), mest=50)) assert_equal(rr.shape, (3, 2, 4)) assert_allclose(rr - roots, 0, atol=1e-12) def test_splint(self): # test that splint accepts BSpline objects b, b2 = self.b, self.b2 assert_allclose(splint(0, 1, b), splint(0, 1, b.tck), atol=1e-14) assert_allclose(splint(0, 1, b), b.integrate(0, 1), atol=1e-14) # ... and deals with N-D arrays of coefficients with suppress_warnings() as sup: sup.filter( DeprecationWarning, "Calling splint.. with BSpline objects with c.ndim > 1 is not recommended." ) assert_allclose(splint(0, 1, b2), b2.integrate(0, 1), atol=1e-14) # and the legacy behavior is preserved for a tck tuple w/ N-D coef c2r = b2.c.transpose(1, 2, 0) integr = np.asarray(splint(0, 1, (b2.t, c2r, b2.k))) assert_equal(integr.shape, (3, 2)) assert_allclose(integr, splint(0, 1, b), atol=1e-14) def test_splder(self): for b in [self.b, self.b2]: # pad the c array (FITPACK convention) ct = len(b.t) - len(b.c) if ct > 0: b.c = np.r_[b.c, np.zeros((ct, ) + b.c.shape[1:])] for n in [1, 2, 3]: bd = splder(b) tck_d = _impl.splder((b.t, b.c, b.k)) assert_allclose(bd.t, tck_d[0], atol=1e-15) assert_allclose(bd.c, tck_d[1], atol=1e-15) assert_equal(bd.k, tck_d[2]) assert_(isinstance(bd, BSpline)) assert_(isinstance(tck_d, tuple)) # back-compat: tck in and out def test_splantider(self): for b in [self.b, self.b2]: # pad the c array (FITPACK convention) ct = len(b.t) - len(b.c) if ct > 0: b.c = np.r_[b.c, np.zeros((ct, ) + b.c.shape[1:])] for n in [1, 2, 3]: bd = splantider(b) tck_d = _impl.splantider((b.t, b.c, b.k)) assert_allclose(bd.t, tck_d[0], atol=1e-15) assert_allclose(bd.c, tck_d[1], atol=1e-15) assert_equal(bd.k, tck_d[2]) assert_(isinstance(bd, BSpline)) assert_(isinstance(tck_d, tuple)) # back-compat: tck in and out def test_insert(self): b, b2, xx = self.b, self.b2, self.xx j = b.t.size // 2 tn = 0.5 * (b.t[j] + b.t[j + 1]) bn, tck_n = insert(tn, b), insert(tn, (b.t, b.c, b.k)) assert_allclose(splev(xx, bn), splev(xx, tck_n), atol=1e-15) assert_(isinstance(bn, BSpline)) assert_(isinstance(tck_n, tuple)) # back-compat: tck in, tck out # for N-D array of coefficients, BSpline.c needs to be transposed # after that, the results are equivalent. sh = tuple(range(b2.c.ndim)) c_ = b2.c.transpose(sh[1:] + (0, )) tck_n2 = insert(tn, (b2.t, c_, b2.k)) bn2 = insert(tn, b2) # need a transpose for comparing the results, cf test_splev assert_allclose(np.asarray(splev(xx, tck_n2)).transpose(2, 0, 1), bn2(xx), atol=1e-15) assert_(isinstance(bn2, BSpline)) assert_(isinstance(tck_n2, tuple)) # back-compat: tck in, tck out
def check_version(module, min_ver): if type(module) == MissingModule: return pytest.mark.skip(reason="{} is not installed".format(module.name)) return pytest.mark.skipif(_pep440.parse(module.__version__) < _pep440.Version(min_ver), reason="{} version >= {} required".format(module.__name__, min_ver))
def _get_mark(item, name): if _pep440.parse(pytest.__version__) >= _pep440.Version("3.6.0"): mark = item.get_closest_marker(name) else: mark = item.get_marker(name) return mark
def process_pyx(fromfile, tofile, cwd): try: from Cython.Compiler.Version import version as cython_version from scipy._lib import _pep440 # Try to find pyproject.toml pyproject_toml = join(dirname(__file__), '..', 'pyproject.toml') if not os.path.exists(pyproject_toml): raise ImportError() # Try to find the minimum version from pyproject.toml with open(pyproject_toml) as pt: for line in pt: if "cython" not in line.lower(): continue line = ''.join(line.split('=')[1:]) # get rid of "Cython>=" if ',<' in line: # There's an upper bound as well split_on = ',<' if ',<=' in line: split_on = ',<=' min_required_version, max_required_version = line.split(split_on) max_required_version, _ = max_required_version.split('"') else: min_required_version, _ = line.split('"') break else: raise ImportError() # Note: we only check lower bound, for upper bound we rely on pip # respecting pyproject.toml. Reason: we want to be able to build/test # with more recent Cython locally or on main, upper bound is for # sdist in a release. if _pep440.parse(cython_version) < _pep440.Version(min_required_version): raise Exception('Building SciPy requires Cython >= {}, found ' '{}'.format(min_required_version, cython_version)) except ImportError: pass flags = ['--fast-fail', '-3'] if tofile.endswith('.cxx'): flags += ['--cplus'] try: try: r = subprocess.call(['cython'] + flags + ["-o", tofile, fromfile], cwd=cwd) if r != 0: raise Exception('Cython failed') except OSError as e: # There are ways of installing Cython that don't result in a cython # executable on the path, see gh-2397. r = subprocess.call([sys.executable, '-c', 'import sys; from Cython.Compiler.Main import ' 'setuptools_main as main; sys.exit(main())'] + flags + ["-o", tofile, fromfile], cwd=cwd) if r != 0: raise Exception("Cython either isn't installed or it failed.") from e except OSError as e: raise OSError('Cython needs to be installed') from e