From 8a6c9e1f81dff4f95f705cb7067c6159f8a46af8 Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Thu, 27 Oct 2022 14:56:30 +0200 Subject: [PATCH 1/6] DOC: Update TESTS.rst to use the correct names Not actually sure that setup_module() is what was wanted here, but it works? Mention a bit more about actual pytest fixtures. --- doc/TESTS.rst.txt | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/doc/TESTS.rst.txt b/doc/TESTS.rst.txt index 0d8137f4a7e1..9c5e8571ff64 100644 --- a/doc/TESTS.rst.txt +++ b/doc/TESTS.rst.txt @@ -178,30 +178,33 @@ Similarly for methods:: Easier setup and teardown functions / methods --------------------------------------------- -Testing looks for module-level or class-level setup and teardown functions by -name; thus:: +Testing looks for module-level or class method-level setup and teardown +functions by name; thus:: - def setup(): + def setup_module(): """Module-level setup""" print('doing setup') - def teardown(): + def teardown_module(): """Module-level teardown""" print('doing teardown') class TestMe: - def setup(): + def setup_method(self): """Class-level setup""" print('doing setup') - def teardown(): + def teardown_method(): """Class-level teardown""" print('doing teardown') Setup and teardown functions to functions and methods are known as "fixtures", -and their use is not encouraged. +and they should be used sparingly. +``pytest`` supports more general fixture at various scopes which may be used +automatically via special arguments. For example, the special argument name +``tmpdir`` is used in test to create a temporary directory. Parametric tests ---------------- From a0e877e7a7c25bbd3e8c88b3a0618b6a4a4cc714 Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Thu, 27 Oct 2022 14:57:14 +0200 Subject: [PATCH 2/6] TST,MAINT: Replace most `setup` with `setup_method` (also teardown) In some cases, the replacement is clearly not what is intended, in those (where setup was called explicitly), I mostly renamed `setup` to `_setup`. The `test_ccompile_opt` is a bit confusing, so left it right now (this will probably fail) --- numpy/core/tests/test_arrayprint.py | 4 +- numpy/core/tests/test_defchararray.py | 20 ++++---- numpy/core/tests/test_deprecations.py | 8 ++-- numpy/core/tests/test_half.py | 2 +- numpy/core/tests/test_indexing.py | 2 +- numpy/core/tests/test_memmap.py | 4 +- numpy/core/tests/test_multiarray.py | 18 +++---- numpy/core/tests/test_numeric.py | 26 +++++----- numpy/core/tests/test_numerictypes.py | 2 +- numpy/core/tests/test_overrides.py | 2 +- numpy/core/tests/test_records.py | 2 +- numpy/core/tests/test_umath.py | 4 +- numpy/core/tests/test_umath_complex.py | 8 ++-- .../tests/test_ccompiler_opt_conf.py | 4 +- numpy/distutils/tests/test_exec_command.py | 2 +- numpy/distutils/tests/test_system_info.py | 4 +- numpy/f2py/tests/test_assumed_shape.py | 4 +- numpy/lib/tests/test__datasource.py | 24 +++++----- numpy/lib/tests/test_function_base.py | 2 +- numpy/lib/tests/test_histograms.py | 4 +- numpy/lib/tests/test_io.py | 4 +- numpy/lib/tests/test_recfunctions.py | 14 +++--- numpy/ma/tests/test_core.py | 24 +++++----- numpy/ma/tests/test_extras.py | 4 +- numpy/ma/tests/test_mrecords.py | 2 +- numpy/ma/tests/test_old_ma.py | 47 ++++++++++--------- numpy/ma/tests/test_subclassing.py | 38 ++++++++++++++- numpy/matrixlib/tests/test_masked_matrix.py | 2 +- numpy/random/tests/test_generator_mt19937.py | 12 ++--- numpy/random/tests/test_random.py | 10 ++-- numpy/random/tests/test_randomstate.py | 10 ++-- numpy/testing/tests/test_utils.py | 14 +++--- 32 files changed, 182 insertions(+), 145 deletions(-) diff --git a/numpy/core/tests/test_arrayprint.py b/numpy/core/tests/test_arrayprint.py index 25826d8eda3c..1f5b7abdd33c 100644 --- a/numpy/core/tests/test_arrayprint.py +++ b/numpy/core/tests/test_arrayprint.py @@ -498,10 +498,10 @@ def test_refcount(self): class TestPrintOptions: """Test getting and setting global print options.""" - def setup(self): + def setup_method(self): self.oldopts = np.get_printoptions() - def teardown(self): + def teardown_method(self): np.set_printoptions(**self.oldopts) def test_basic(self): diff --git a/numpy/core/tests/test_defchararray.py b/numpy/core/tests/test_defchararray.py index 59fc54722397..64124903ce87 100644 --- a/numpy/core/tests/test_defchararray.py +++ b/numpy/core/tests/test_defchararray.py @@ -132,7 +132,7 @@ def fail(): class TestWhitespace: - def setup(self): + def setup_method(self): self.A = np.array([['abc ', '123 '], ['789 ', 'xyz ']]).view(np.chararray) self.B = np.array([['abc', '123'], @@ -147,7 +147,7 @@ def test1(self): assert_(not np.any(self.A != self.B)) class TestChar: - def setup(self): + def setup_method(self): self.A = np.array('abc1', dtype='c').view(np.chararray) def test_it(self): @@ -155,7 +155,7 @@ def test_it(self): assert_equal(self.A.upper()[:2].tobytes(), b'AB') class TestComparisons: - def setup(self): + def setup_method(self): self.A = np.array([['abc', '123'], ['789', 'xyz']]).view(np.chararray) self.B = np.array([['efg', '123 '], @@ -188,21 +188,21 @@ def test_type(self): class TestComparisonsMixed1(TestComparisons): """Ticket #1276""" - def setup(self): - TestComparisons.setup(self) + def setup_method(self): + TestComparisons.setup_method(self) self.B = np.array([['efg', '123 '], ['051', 'tuv']], np.unicode_).view(np.chararray) class TestComparisonsMixed2(TestComparisons): """Ticket #1276""" - def setup(self): - TestComparisons.setup(self) + def setup_method(self): + TestComparisons.setup_method(self) self.A = np.array([['abc', '123'], ['789', 'xyz']], np.unicode_).view(np.chararray) class TestInformation: - def setup(self): + def setup_method(self): self.A = np.array([[' abc ', ''], ['12345', 'MixedCase'], ['123 \t 345 \0 ', 'UPPER']]).view(np.chararray) @@ -308,7 +308,7 @@ def fail(): class TestMethods: - def setup(self): + def setup_method(self): self.A = np.array([[' abc ', ''], ['12345', 'MixedCase'], ['123 \t 345 \0 ', 'UPPER']], @@ -581,7 +581,7 @@ def fail(): class TestOperations: - def setup(self): + def setup_method(self): self.A = np.array([['abc', '123'], ['789', 'xyz']]).view(np.chararray) self.B = np.array([['efg', '456'], diff --git a/numpy/core/tests/test_deprecations.py b/numpy/core/tests/test_deprecations.py index 2b7864433291..d443edd135d2 100644 --- a/numpy/core/tests/test_deprecations.py +++ b/numpy/core/tests/test_deprecations.py @@ -32,7 +32,7 @@ class _DeprecationTestCase: message = '' warning_cls = DeprecationWarning - def setup(self): + def setup_method(self): self.warn_ctx = warnings.catch_warnings(record=True) self.log = self.warn_ctx.__enter__() @@ -46,7 +46,7 @@ def setup(self): warnings.filterwarnings("always", message=self.message, category=self.warning_cls) - def teardown(self): + def teardown_method(self): self.warn_ctx.__exit__() def assert_deprecated(self, function, num=1, ignore_others=False, @@ -297,7 +297,7 @@ class vdt(np.void): class TestTestDeprecated: def test_assert_deprecated(self): test_case_instance = _DeprecationTestCase() - test_case_instance.setup() + test_case_instance.setup_method() assert_raises(AssertionError, test_case_instance.assert_deprecated, lambda: None) @@ -306,7 +306,7 @@ def foo(): warnings.warn("foo", category=DeprecationWarning, stacklevel=2) test_case_instance.assert_deprecated(foo) - test_case_instance.teardown() + test_case_instance.teardown_method() class TestNonNumericConjugate(_DeprecationTestCase): diff --git a/numpy/core/tests/test_half.py b/numpy/core/tests/test_half.py index 1b6fd21e14bb..78bd068bb06c 100644 --- a/numpy/core/tests/test_half.py +++ b/numpy/core/tests/test_half.py @@ -17,7 +17,7 @@ def assert_raises_fpe(strmatch, callable, *args, **kwargs): "Did not raise floating point %s error" % strmatch) class TestHalf: - def setup(self): + def setup_method(self): # An array of all possible float16 values self.all_f16 = np.arange(0x10000, dtype=uint16) self.all_f16.dtype = float16 diff --git a/numpy/core/tests/test_indexing.py b/numpy/core/tests/test_indexing.py index efcb92c2e6d1..7f22be5031bf 100644 --- a/numpy/core/tests/test_indexing.py +++ b/numpy/core/tests/test_indexing.py @@ -826,7 +826,7 @@ class TestMultiIndexingAutomated: """ - def setup(self): + def setup_method(self): self.a = np.arange(np.prod([3, 1, 5, 6])).reshape(3, 1, 5, 6) self.b = np.empty((3, 0, 5, 6)) self.complex_indices = ['skip', Ellipsis, diff --git a/numpy/core/tests/test_memmap.py b/numpy/core/tests/test_memmap.py index e4f0a6b3f665..914f86f1480e 100644 --- a/numpy/core/tests/test_memmap.py +++ b/numpy/core/tests/test_memmap.py @@ -15,14 +15,14 @@ ) class TestMemmap: - def setup(self): + def setup_method(self): self.tmpfp = NamedTemporaryFile(prefix='mmap') self.shape = (3, 4) self.dtype = 'float32' self.data = arange(12, dtype=self.dtype) self.data.resize(self.shape) - def teardown(self): + def teardown_method(self): self.tmpfp.close() self.data = None if IS_PYPY: diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index cacfd5bfc827..e5dee24c00ec 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -74,7 +74,7 @@ def _aligned_zeros(shape, dtype=float, order="C", align=None): class TestFlags: - def setup(self): + def setup_method(self): self.a = np.arange(10) def test_writeable(self): @@ -275,7 +275,7 @@ def test_int(self): class TestAttributes: - def setup(self): + def setup_method(self): self.one = np.arange(10) self.two = np.arange(20).reshape(4, 5) self.three = np.arange(60, dtype=np.float64).reshape(2, 5, 6) @@ -652,7 +652,7 @@ def test_structured_non_void(self): class TestZeroRank: - def setup(self): + def setup_method(self): self.d = np.array(0), np.array('x', object) def test_ellipsis_subscript(self): @@ -756,7 +756,7 @@ def test_real_imag(self): class TestScalarIndexing: - def setup(self): + def setup_method(self): self.d = np.array([0, 1])[0] def test_ellipsis_subscript(self): @@ -5672,7 +5672,7 @@ def test_mmap_close(self): mm.close() class TestFlat: - def setup(self): + def setup_method(self): a0 = np.arange(20.0) a = a0.reshape(4, 5) a0.shape = (4, 5) @@ -5995,7 +5995,7 @@ class TestStats: funcs = [_mean, _var, _std] - def setup(self): + def setup_method(self): np.random.seed(range(3)) self.rmat = np.random.random((4, 5)) self.cmat = self.rmat + 1j * self.rmat @@ -6422,7 +6422,7 @@ def test_vdot_uncontiguous(self): class TestDot: - def setup(self): + def setup_method(self): np.random.seed(128) self.A = np.random.rand(4, 2) self.b1 = np.random.rand(2, 1) @@ -7214,7 +7214,7 @@ def test_3d_tensor(self): class TestChoose: - def setup(self): + def setup_method(self): self.x = 2*np.ones((3,), dtype=int) self.y = 3*np.ones((3,), dtype=int) self.x2 = 2*np.ones((2, 3), dtype=int) @@ -7244,7 +7244,7 @@ def test_output_dtype(self, ops): class TestRepeat: - def setup(self): + def setup_method(self): self.m = np.array([1, 2, 3, 4, 5, 6]) self.m_rect = self.m.reshape((2, 3)) diff --git a/numpy/core/tests/test_numeric.py b/numpy/core/tests/test_numeric.py index 0b03c65760f4..692e4e0c6be0 100644 --- a/numpy/core/tests/test_numeric.py +++ b/numpy/core/tests/test_numeric.py @@ -347,7 +347,7 @@ def test_bitwise_xor(self): class TestBoolArray: - def setup(self): + def setup_method(self): # offset for simd tests self.t = np.array([True] * 41, dtype=bool)[1::] self.f = np.array([False] * 41, dtype=bool)[1::] @@ -434,7 +434,7 @@ def test_logical_and_or_xor(self): class TestBoolCmp: - def setup(self): + def setup_method(self): self.f = np.ones(256, dtype=np.float32) self.ef = np.ones(self.f.size, dtype=bool) self.d = np.ones(128, dtype=np.float64) @@ -1813,7 +1813,7 @@ def assert_array_strict_equal(x, y): class TestClip: - def setup(self): + def setup_method(self): self.nr = 5 self.nc = 3 @@ -2442,10 +2442,10 @@ class TestAllclose: rtol = 1e-5 atol = 1e-8 - def setup(self): + def setup_method(self): self.olderr = np.seterr(invalid='ignore') - def teardown(self): + def teardown_method(self): np.seterr(**self.olderr) def tst_allclose(self, x, y): @@ -2527,7 +2527,7 @@ class TestIsclose: rtol = 1e-5 atol = 1e-8 - def setup(self): + def _setup(self): atol = self.atol rtol = self.rtol arr = np.array([100, 1000]) @@ -2573,7 +2573,7 @@ def setup(self): ] def test_ip_isclose(self): - self.setup() + self._setup() tests = self.some_close_tests results = self.some_close_results for (x, y), result in zip(tests, results): @@ -2595,17 +2595,17 @@ def tst_isclose_allclose(self, x, y): assert_array_equal(np.isclose(x, y).all(), np.allclose(x, y), msg % (x, y)) def test_ip_all_isclose(self): - self.setup() + self._setup() for (x, y) in self.all_close_tests: self.tst_all_isclose(x, y) def test_ip_none_isclose(self): - self.setup() + self._setup() for (x, y) in self.none_close_tests: self.tst_none_isclose(x, y) def test_ip_isclose_allclose(self): - self.setup() + self._setup() tests = (self.all_close_tests + self.none_close_tests + self.some_close_tests) for (x, y) in tests: @@ -2671,7 +2671,7 @@ def test_timedelta(self): class TestStdVar: - def setup(self): + def setup_method(self): self.A = np.array([1, -1, 1, -1]) self.real_var = 1 @@ -2724,7 +2724,7 @@ def test_scalars(self): class TestCreationFuncs: # Test ones, zeros, empty and full. - def setup(self): + def setup_method(self): dtypes = {np.dtype(tp) for tp in itertools.chain(*np.sctypes.values())} # void, bytes, str variable_sized = {tp for tp in dtypes if tp.str.endswith('0')} @@ -2795,7 +2795,7 @@ def test_for_reference_leak(self): class TestLikeFuncs: '''Test ones_like, zeros_like, empty_like and full_like''' - def setup(self): + def setup_method(self): self.data = [ # Array scalars (np.array(3.), None), diff --git a/numpy/core/tests/test_numerictypes.py b/numpy/core/tests/test_numerictypes.py index 73ff4764d664..e5ff52332ee6 100644 --- a/numpy/core/tests/test_numerictypes.py +++ b/numpy/core/tests/test_numerictypes.py @@ -357,7 +357,7 @@ def test_scalar_wins3(self): # doesn't go up to 'f16' on purpose assert_(res == 'f8') class TestMultipleFields: - def setup(self): + def setup_method(self): self.ary = np.array([(1, 2, 3, 4), (5, 6, 7, 8)], dtype='i4,f4,i2,c8') def _bad_call(self): diff --git a/numpy/core/tests/test_overrides.py b/numpy/core/tests/test_overrides.py index 36970dbc02ed..10564502772e 100644 --- a/numpy/core/tests/test_overrides.py +++ b/numpy/core/tests/test_overrides.py @@ -431,7 +431,7 @@ def __array_function__(self, func, types, args, kwargs): class TestArrayLike: - def setup(self): + def setup_method(self): class MyArray(): def __init__(self, function=None): self.function = function diff --git a/numpy/core/tests/test_records.py b/numpy/core/tests/test_records.py index 4d4b4b5158de..a76ae2d99978 100644 --- a/numpy/core/tests/test_records.py +++ b/numpy/core/tests/test_records.py @@ -337,7 +337,7 @@ def test_tofile_fromfile(self): class TestRecord: - def setup(self): + def setup_method(self): self.data = np.rec.fromrecords([(1, 2, 3), (4, 5, 6)], dtype=[("col1", " Date: Thu, 27 Oct 2022 15:34:03 +0200 Subject: [PATCH 3/6] TST: Try using setup_class for `_Test_CCompilerOpt` --- numpy/distutils/tests/test_ccompiler_opt.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/numpy/distutils/tests/test_ccompiler_opt.py b/numpy/distutils/tests/test_ccompiler_opt.py index 1ca8bc09bf93..657ebdb68512 100644 --- a/numpy/distutils/tests/test_ccompiler_opt.py +++ b/numpy/distutils/tests/test_ccompiler_opt.py @@ -78,7 +78,7 @@ class _Test_CCompilerOpt: arch = None # x86_64 cc = None # gcc - def setup(self): + def setup_class(self): FakeCCompilerOpt.conf_nocache = True self._opt = None @@ -780,7 +780,7 @@ class TestCCompilerOpt_{class_name}(_Test_CCompilerOpt, unittest.TestCase): cc = '{cc}' def __init__(self, methodName="runTest"): unittest.TestCase.__init__(self, methodName) - self.setup() + self.setup_class() """).format( class_name=arch + '_' + cc, arch=arch, cc=cc ) From 01116800c70c2bfd474eeadb56c433f95ea776c7 Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Thu, 27 Oct 2022 15:36:44 +0200 Subject: [PATCH 4/6] TST: Rename setup to setup_method in f2py utils (inherited into Tests) --- numpy/f2py/tests/test_assumed_shape.py | 2 +- numpy/f2py/tests/util.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/numpy/f2py/tests/test_assumed_shape.py b/numpy/f2py/tests/test_assumed_shape.py index 4da79ec0212f..d4664cf88cbe 100644 --- a/numpy/f2py/tests/test_assumed_shape.py +++ b/numpy/f2py/tests/test_assumed_shape.py @@ -43,7 +43,7 @@ def setup_method(self): self.sources.append(self.f2cmap_file.name) self.options = ["--f2cmap", self.f2cmap_file.name] - super().setup() + super().setup_method() def teardown_method(self): os.unlink(self.f2cmap_file.name) diff --git a/numpy/f2py/tests/util.py b/numpy/f2py/tests/util.py index ae81bbfc4cc3..620ea9110563 100644 --- a/numpy/f2py/tests/util.py +++ b/numpy/f2py/tests/util.py @@ -334,7 +334,7 @@ class F2PyTest: module = None module_name = None - def setup(self): + def setup_method(self): if sys.platform == "win32": pytest.skip("Fails with MinGW64 Gfortran (Issue #9673)") From 878f97a965f55dcb8009ea2defdfe69f49fdc6fa Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Thu, 27 Oct 2022 22:05:07 +0200 Subject: [PATCH 5/6] STY: Make linter happy Not new things, but in touched lines... --- numpy/distutils/tests/test_system_info.py | 1 - numpy/lib/tests/test_io.py | 1 + numpy/ma/tests/test_old_ma.py | 5 ++--- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/numpy/distutils/tests/test_system_info.py b/numpy/distutils/tests/test_system_info.py index 539badf0738e..eb7235e04620 100644 --- a/numpy/distutils/tests/test_system_info.py +++ b/numpy/distutils/tests/test_system_info.py @@ -171,7 +171,6 @@ def site_and_parse(c, site_cfg): self.c_dup_options = site_and_parse(get_class('duplicate_options'), self._sitecfg) - def teardown_method(self): # Do each removal separately try: diff --git a/numpy/lib/tests/test_io.py b/numpy/lib/tests/test_io.py index 657d114e9b39..31df17a96ce4 100644 --- a/numpy/lib/tests/test_io.py +++ b/numpy/lib/tests/test_io.py @@ -689,6 +689,7 @@ def setup_method(self): # lower chunksize for testing self.orig_chunk = np.lib.npyio._loadtxt_chunksize np.lib.npyio._loadtxt_chunksize = 1 + def teardown_method(self): np.lib.npyio._loadtxt_chunksize = self.orig_chunk diff --git a/numpy/ma/tests/test_old_ma.py b/numpy/ma/tests/test_old_ma.py index 083e51125f3b..8465b11531d8 100644 --- a/numpy/ma/tests/test_old_ma.py +++ b/numpy/ma/tests/test_old_ma.py @@ -78,9 +78,8 @@ def test_testBasic2d(self, s): assert_(isMaskedArray(xm)) assert_equal(shape(xm), s) assert_equal(xm.shape, s) - assert_equal(xm.size, reduce(lambda x, y:x * y, s)) - assert_equal(count(xm), - len(m1) - reduce(lambda x, y:x + y, m1)) + assert_equal(xm.size, reduce(lambda x, y: x * y, s)) + assert_equal(count(xm), len(m1) - reduce(lambda x, y: x + y, m1)) assert_(eq(xm, xf)) assert_(eq(filled(xm, 1.e20), xf)) assert_(eq(x, xm)) From 9b31dafdc62f29ecd639577c97763fc17371895f Mon Sep 17 00:00:00 2001 From: Charles Harris Date: Thu, 27 Oct 2022 18:35:39 -0600 Subject: [PATCH 6/6] BUG: Copy test_subclassing.py from main. --- numpy/ma/tests/test_subclassing.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/numpy/ma/tests/test_subclassing.py b/numpy/ma/tests/test_subclassing.py index f8dd2500114f..64c66eeb9d6b 100644 --- a/numpy/ma/tests/test_subclassing.py +++ b/numpy/ma/tests/test_subclassing.py @@ -7,6 +7,7 @@ """ import numpy as np +from numpy.lib.mixins import NDArrayOperatorsMixin from numpy.testing import assert_, assert_raises from numpy.ma.testutils import assert_equal from numpy.ma.core import ( @@ -147,6 +148,33 @@ def __array_wrap__(self, obj, context=None): return obj +class WrappedArray(NDArrayOperatorsMixin): + """ + Wrapping a MaskedArray rather than subclassing to test that + ufunc deferrals are commutative. + See: https://github.com/numpy/numpy/issues/15200) + """ + __array_priority__ = 20 + + def __init__(self, array, **attrs): + self._array = array + self.attrs = attrs + + def __repr__(self): + return f"{self.__class__.__name__}(\n{self._array}\n{self.attrs}\n)" + + def __array__(self): + return np.asarray(self._array) + + def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): + if method == '__call__': + inputs = [arg._array if isinstance(arg, self.__class__) else arg + for arg in inputs] + return self.__class__(ufunc(*inputs, **kwargs), **self.attrs) + else: + return NotImplemented + + class TestSubclassing: # Test suite for masked subclasses of ndarray.