123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380 |
- from multiprocessing import Pool
- from multiprocessing.pool import Pool as PWL
- import os
- import re
- import math
- from fractions import Fraction
- import numpy as np
- from numpy.testing import assert_equal, assert_
- import pytest
- from pytest import raises as assert_raises, deprecated_call
- import scipy
- from scipy._lib._util import (_aligned_zeros, check_random_state, MapWrapper,
- getfullargspec_no_self, FullArgSpec,
- rng_integers, _validate_int, _rename_parameter,
- _contains_nan)
- def test__aligned_zeros():
- niter = 10
- def check(shape, dtype, order, align):
- err_msg = repr((shape, dtype, order, align))
- x = _aligned_zeros(shape, dtype, order, align=align)
- if align is None:
- align = np.dtype(dtype).alignment
- assert_equal(x.__array_interface__['data'][0] % align, 0)
- if hasattr(shape, '__len__'):
- assert_equal(x.shape, shape, err_msg)
- else:
- assert_equal(x.shape, (shape,), err_msg)
- assert_equal(x.dtype, dtype)
- if order == "C":
- assert_(x.flags.c_contiguous, err_msg)
- elif order == "F":
- if x.size > 0:
- # Size-0 arrays get invalid flags on NumPy 1.5
- assert_(x.flags.f_contiguous, err_msg)
- elif order is None:
- assert_(x.flags.c_contiguous, err_msg)
- else:
- raise ValueError()
- # try various alignments
- for align in [1, 2, 3, 4, 8, 16, 32, 64, None]:
- for n in [0, 1, 3, 11]:
- for order in ["C", "F", None]:
- for dtype in [np.uint8, np.float64]:
- for shape in [n, (1, 2, 3, n)]:
- for j in range(niter):
- check(shape, dtype, order, align)
- def test_check_random_state():
- # If seed is None, return the RandomState singleton used by np.random.
- # If seed is an int, return a new RandomState instance seeded with seed.
- # If seed is already a RandomState instance, return it.
- # Otherwise raise ValueError.
- rsi = check_random_state(1)
- assert_equal(type(rsi), np.random.RandomState)
- rsi = check_random_state(rsi)
- assert_equal(type(rsi), np.random.RandomState)
- rsi = check_random_state(None)
- assert_equal(type(rsi), np.random.RandomState)
- assert_raises(ValueError, check_random_state, 'a')
- if hasattr(np.random, 'Generator'):
- # np.random.Generator is only available in NumPy >= 1.17
- rg = np.random.Generator(np.random.PCG64())
- rsi = check_random_state(rg)
- assert_equal(type(rsi), np.random.Generator)
- def test_getfullargspec_no_self():
- p = MapWrapper(1)
- argspec = getfullargspec_no_self(p.__init__)
- assert_equal(argspec, FullArgSpec(['pool'], None, None, (1,), [],
- None, {}))
- argspec = getfullargspec_no_self(p.__call__)
- assert_equal(argspec, FullArgSpec(['func', 'iterable'], None, None, None,
- [], None, {}))
- class _rv_generic:
- def _rvs(self, a, b=2, c=3, *args, size=None, **kwargs):
- return None
- rv_obj = _rv_generic()
- argspec = getfullargspec_no_self(rv_obj._rvs)
- assert_equal(argspec, FullArgSpec(['a', 'b', 'c'], 'args', 'kwargs',
- (2, 3), ['size'], {'size': None}, {}))
- def test_mapwrapper_serial():
- in_arg = np.arange(10.)
- out_arg = np.sin(in_arg)
- p = MapWrapper(1)
- assert_(p._mapfunc is map)
- assert_(p.pool is None)
- assert_(p._own_pool is False)
- out = list(p(np.sin, in_arg))
- assert_equal(out, out_arg)
- with assert_raises(RuntimeError):
- p = MapWrapper(0)
- def test_pool():
- with Pool(2) as p:
- p.map(math.sin, [1, 2, 3, 4])
- def test_mapwrapper_parallel():
- in_arg = np.arange(10.)
- out_arg = np.sin(in_arg)
- with MapWrapper(2) as p:
- out = p(np.sin, in_arg)
- assert_equal(list(out), out_arg)
- assert_(p._own_pool is True)
- assert_(isinstance(p.pool, PWL))
- assert_(p._mapfunc is not None)
- # the context manager should've closed the internal pool
- # check that it has by asking it to calculate again.
- with assert_raises(Exception) as excinfo:
- p(np.sin, in_arg)
- assert_(excinfo.type is ValueError)
- # can also set a PoolWrapper up with a map-like callable instance
- with Pool(2) as p:
- q = MapWrapper(p.map)
- assert_(q._own_pool is False)
- q.close()
- # closing the PoolWrapper shouldn't close the internal pool
- # because it didn't create it
- out = p.map(np.sin, in_arg)
- assert_equal(list(out), out_arg)
- # get our custom ones and a few from the "import *" cases
- @pytest.mark.parametrize(
- 'key', ('ifft', 'diag', 'arccos', 'randn', 'rand', 'array'))
- def test_numpy_deprecation(key):
- """Test that 'from numpy import *' functions are deprecated."""
- if key in ('ifft', 'diag', 'arccos'):
- arg = [1.0, 0.]
- elif key == 'finfo':
- arg = float
- else:
- arg = 2
- func = getattr(scipy, key)
- match = r'scipy\.%s is deprecated.*2\.0\.0' % key
- with deprecated_call(match=match) as dep:
- func(arg) # deprecated
- # in case we catch more than one dep warning
- fnames = [os.path.splitext(d.filename)[0] for d in dep.list]
- basenames = [os.path.basename(fname) for fname in fnames]
- assert 'test__util' in basenames
- if key in ('rand', 'randn'):
- root = np.random
- elif key == 'ifft':
- root = np.fft
- else:
- root = np
- func_np = getattr(root, key)
- func_np(arg) # not deprecated
- assert func_np is not func
- # classes should remain classes
- if isinstance(func_np, type):
- assert isinstance(func, type)
- def test_numpy_deprecation_functionality():
- # Check that the deprecation wrappers don't break basic NumPy
- # functionality
- with deprecated_call():
- x = scipy.array([1, 2, 3], dtype=scipy.float64)
- assert x.dtype == scipy.float64
- assert x.dtype == np.float64
- x = scipy.finfo(scipy.float32)
- assert x.eps == np.finfo(np.float32).eps
- assert scipy.float64 == np.float64
- assert issubclass(np.float64, scipy.float64)
- def test_rng_integers():
- rng = np.random.RandomState()
- # test that numbers are inclusive of high point
- arr = rng_integers(rng, low=2, high=5, size=100, endpoint=True)
- assert np.max(arr) == 5
- assert np.min(arr) == 2
- assert arr.shape == (100, )
- # test that numbers are inclusive of high point
- arr = rng_integers(rng, low=5, size=100, endpoint=True)
- assert np.max(arr) == 5
- assert np.min(arr) == 0
- assert arr.shape == (100, )
- # test that numbers are exclusive of high point
- arr = rng_integers(rng, low=2, high=5, size=100, endpoint=False)
- assert np.max(arr) == 4
- assert np.min(arr) == 2
- assert arr.shape == (100, )
- # test that numbers are exclusive of high point
- arr = rng_integers(rng, low=5, size=100, endpoint=False)
- assert np.max(arr) == 4
- assert np.min(arr) == 0
- assert arr.shape == (100, )
- # now try with np.random.Generator
- try:
- rng = np.random.default_rng()
- except AttributeError:
- return
- # test that numbers are inclusive of high point
- arr = rng_integers(rng, low=2, high=5, size=100, endpoint=True)
- assert np.max(arr) == 5
- assert np.min(arr) == 2
- assert arr.shape == (100, )
- # test that numbers are inclusive of high point
- arr = rng_integers(rng, low=5, size=100, endpoint=True)
- assert np.max(arr) == 5
- assert np.min(arr) == 0
- assert arr.shape == (100, )
- # test that numbers are exclusive of high point
- arr = rng_integers(rng, low=2, high=5, size=100, endpoint=False)
- assert np.max(arr) == 4
- assert np.min(arr) == 2
- assert arr.shape == (100, )
- # test that numbers are exclusive of high point
- arr = rng_integers(rng, low=5, size=100, endpoint=False)
- assert np.max(arr) == 4
- assert np.min(arr) == 0
- assert arr.shape == (100, )
- class TestValidateInt:
- @pytest.mark.parametrize('n', [4, np.uint8(4), np.int16(4), np.array(4)])
- def test_validate_int(self, n):
- n = _validate_int(n, 'n')
- assert n == 4
- @pytest.mark.parametrize('n', [4.0, np.array([4]), Fraction(4, 1)])
- def test_validate_int_bad(self, n):
- with pytest.raises(TypeError, match='n must be an integer'):
- _validate_int(n, 'n')
- def test_validate_int_below_min(self):
- with pytest.raises(ValueError, match='n must be an integer not '
- 'less than 0'):
- _validate_int(-1, 'n', 0)
- class TestRenameParameter:
- # check that wrapper `_rename_parameter` for backward-compatible
- # keyword renaming works correctly
- # Example method/function that still accepts keyword `old`
- @_rename_parameter("old", "new")
- def old_keyword_still_accepted(self, new):
- return new
- # Example method/function for which keyword `old` is deprecated
- @_rename_parameter("old", "new", dep_version="1.9.0")
- def old_keyword_deprecated(self, new):
- return new
- def test_old_keyword_still_accepted(self):
- # positional argument and both keyword work identically
- res1 = self.old_keyword_still_accepted(10)
- res2 = self.old_keyword_still_accepted(new=10)
- res3 = self.old_keyword_still_accepted(old=10)
- assert res1 == res2 == res3 == 10
- # unexpected keyword raises an error
- message = re.escape("old_keyword_still_accepted() got an unexpected")
- with pytest.raises(TypeError, match=message):
- self.old_keyword_still_accepted(unexpected=10)
- # multiple values for the same parameter raises an error
- message = re.escape("old_keyword_still_accepted() got multiple")
- with pytest.raises(TypeError, match=message):
- self.old_keyword_still_accepted(10, new=10)
- with pytest.raises(TypeError, match=message):
- self.old_keyword_still_accepted(10, old=10)
- with pytest.raises(TypeError, match=message):
- self.old_keyword_still_accepted(new=10, old=10)
- def test_old_keyword_deprecated(self):
- # positional argument and both keyword work identically,
- # but use of old keyword results in DeprecationWarning
- dep_msg = "Use of keyword argument `old` is deprecated"
- res1 = self.old_keyword_deprecated(10)
- res2 = self.old_keyword_deprecated(new=10)
- with pytest.warns(DeprecationWarning, match=dep_msg):
- res3 = self.old_keyword_deprecated(old=10)
- assert res1 == res2 == res3 == 10
- # unexpected keyword raises an error
- message = re.escape("old_keyword_deprecated() got an unexpected")
- with pytest.raises(TypeError, match=message):
- self.old_keyword_deprecated(unexpected=10)
- # multiple values for the same parameter raises an error and,
- # if old keyword is used, results in DeprecationWarning
- message = re.escape("old_keyword_deprecated() got multiple")
- with pytest.raises(TypeError, match=message):
- self.old_keyword_deprecated(10, new=10)
- with pytest.raises(TypeError, match=message), \
- pytest.warns(DeprecationWarning, match=dep_msg):
- self.old_keyword_deprecated(10, old=10)
- with pytest.raises(TypeError, match=message), \
- pytest.warns(DeprecationWarning, match=dep_msg):
- self.old_keyword_deprecated(new=10, old=10)
- class TestContainsNaNTest:
- def test_policy(self):
- data = np.array([1, 2, 3, np.nan])
- contains_nan, nan_policy = _contains_nan(data, nan_policy="propagate")
- assert contains_nan
- assert nan_policy == "propagate"
- contains_nan, nan_policy = _contains_nan(data, nan_policy="omit")
- assert contains_nan
- assert nan_policy == "omit"
- msg = "The input contains nan values"
- with pytest.raises(ValueError, match=msg):
- _contains_nan(data, nan_policy="raise")
- msg = "nan_policy must be one of"
- with pytest.raises(ValueError, match=msg):
- _contains_nan(data, nan_policy="nan")
- def test_contains_nan_1d(self):
- data1 = np.array([1, 2, 3])
- assert not _contains_nan(data1)[0]
- data2 = np.array([1, 2, 3, np.nan])
- assert _contains_nan(data2)[0]
- data3 = np.array([np.nan, 2, 3, np.nan])
- assert _contains_nan(data3)[0]
- data4 = np.array([1, 2, "3", np.nan]) # converted to string "nan"
- assert not _contains_nan(data4)[0]
- data5 = np.array([1, 2, "3", np.nan], dtype='object')
- assert _contains_nan(data5)[0]
- def test_contains_nan_2d(self):
- data1 = np.array([[1, 2], [3, 4]])
- assert not _contains_nan(data1)[0]
- data2 = np.array([[1, 2], [3, np.nan]])
- assert _contains_nan(data2)[0]
- data3 = np.array([["1", 2], [3, np.nan]]) # converted to string "nan"
- assert not _contains_nan(data3)[0]
- data4 = np.array([["1", 2], [3, np.nan]], dtype='object')
- assert _contains_nan(data4)[0]
|