diff options
Diffstat (limited to 'numpy/ma')
-rw-r--r-- | numpy/ma/README.rst (renamed from numpy/ma/README.txt) | 0 | ||||
-rw-r--r-- | numpy/ma/__init__.py | 2 | ||||
-rw-r--r-- | numpy/ma/bench.py | 4 | ||||
-rw-r--r-- | numpy/ma/core.py | 260 | ||||
-rw-r--r-- | numpy/ma/extras.py | 22 | ||||
-rw-r--r-- | numpy/ma/mrecords.py | 13 | ||||
-rw-r--r-- | numpy/ma/setup.py | 4 | ||||
-rw-r--r-- | numpy/ma/tests/test_core.py | 84 | ||||
-rw-r--r-- | numpy/ma/tests/test_deprecations.py | 6 | ||||
-rw-r--r-- | numpy/ma/tests/test_extras.py | 43 | ||||
-rw-r--r-- | numpy/ma/tests/test_mrecords.py | 8 | ||||
-rw-r--r-- | numpy/ma/tests/test_old_ma.py | 8 | ||||
-rw-r--r-- | numpy/ma/tests/test_regression.py | 8 | ||||
-rw-r--r-- | numpy/ma/tests/test_subclassing.py | 8 | ||||
-rw-r--r-- | numpy/ma/testutils.py | 2 | ||||
-rw-r--r-- | numpy/ma/timer_comparison.py | 4 |
16 files changed, 274 insertions, 202 deletions
diff --git a/numpy/ma/README.txt b/numpy/ma/README.rst index 47f20d645..47f20d645 100644 --- a/numpy/ma/README.txt +++ b/numpy/ma/README.rst diff --git a/numpy/ma/__init__.py b/numpy/ma/__init__.py index 36ceb1f6e..870cc4ef2 100644 --- a/numpy/ma/__init__.py +++ b/numpy/ma/__init__.py @@ -39,8 +39,6 @@ may now proceed to calculate the mean of the other values: .. moduleauthor:: Jarrod Millman """ -from __future__ import division, absolute_import, print_function - from . import core from .core import * diff --git a/numpy/ma/bench.py b/numpy/ma/bench.py index a9ba42dea..83cc6aea7 100644 --- a/numpy/ma/bench.py +++ b/numpy/ma/bench.py @@ -1,8 +1,6 @@ -#! /usr/bin/env python +#!/usr/bin/env python3 # -*- coding: utf-8 -*- -from __future__ import division, print_function - import timeit import numpy diff --git a/numpy/ma/core.py b/numpy/ma/core.py index bb3788c9a..fa888107f 100644 --- a/numpy/ma/core.py +++ b/numpy/ma/core.py @@ -20,20 +20,13 @@ Released for unlimited redistribution. """ # pylint: disable-msg=E1002 -from __future__ import division, absolute_import, print_function - -import sys +import builtins import operator import warnings import textwrap import re from functools import reduce -if sys.version_info[0] >= 3: - import builtins -else: - import __builtin__ as builtins - import numpy as np import numpy.core.umath as umath import numpy.core.numerictypes as ntypes @@ -41,7 +34,7 @@ from numpy import ndarray, amax, amin, iscomplexobj, bool_, _NoValue from numpy import array as narray from numpy.lib.function_base import angle from numpy.compat import ( - getargspec, formatargspec, long, basestring, unicode, bytes + getargspec, formatargspec, long, unicode, bytes ) from numpy import expand_dims from numpy.core.numeric import normalize_axis_tuple @@ -101,7 +94,7 @@ def _deprecate_argsort_axis(arr): The array which argsort was called on np.ma.argsort has a long-term bug where the default of the axis argument - is wrong (gh-8701), which now must be kept for backwards compatibiity. + is wrong (gh-8701), which now must be kept for backwards compatibility. Thankfully, this only makes a difference when arrays are 2- or more- dimensional, so we only need a warning then. """ @@ -293,10 +286,7 @@ def _extremum_fill_value(obj, extremum, extremum_name): try: return extremum[dtype] except KeyError: - raise TypeError( - "Unsuitable type {} for calculating {}." - .format(dtype, extremum_name) - ) + raise TypeError(f"Unsuitable type {dtype} for calculating {extremum_name}.") dtype = _get_dtype_of(obj) return _recursive_fill_value(dtype, _scalar_fill_value) @@ -462,7 +452,7 @@ def _check_fill_value(fill_value, ndtype): fill_value = np.array(_recursive_set_fill_value(fill_value, ndtype), dtype=ndtype) else: - if isinstance(fill_value, basestring) and (ndtype.char not in 'OSVU'): + if isinstance(fill_value, str) and (ndtype.char not in 'OSVU'): # Note this check doesn't work if fill_value is not a scalar err_msg = "Cannot set fill value of string with array of dtype %s" raise TypeError(err_msg % ndtype) @@ -602,8 +592,10 @@ def filled(a, fill_value=None): ---------- a : MaskedArray or array_like An input object. - fill_value : scalar, optional - Filling value. Default is None. + fill_value : array_like, optional. + Can be scalar or non-scalar. If non-scalar, the + resulting filled array should be broadcastable + over input array. Default is None. Returns ------- @@ -623,10 +615,19 @@ def filled(a, fill_value=None): array([[999999, 1, 2], [999999, 4, 5], [ 6, 7, 8]]) + >>> x.filled(fill_value=333) + array([[333, 1, 2], + [333, 4, 5], + [ 6, 7, 8]]) + >>> x.filled(fill_value=np.arange(3)) + array([[0, 1, 2], + [0, 4, 5], + [6, 7, 8]]) """ if hasattr(a, 'filled'): return a.filled(fill_value) + elif isinstance(a, ndarray): # Should we check for contiguity ? and a.flags['CONTIGUOUS']: return a @@ -776,9 +777,9 @@ def fix_invalid(a, mask=nomask, copy=True, fill_value=None): return a def is_string_or_list_of_strings(val): - return (isinstance(val, basestring) or + return (isinstance(val, str) or (isinstance(val, list) and val and - builtins.all(isinstance(s, basestring) for s in val))) + builtins.all(isinstance(s, str) for s in val))) ############################################################################### # Ufuncs # @@ -789,7 +790,7 @@ ufunc_domain = {} ufunc_fills = {} -class _DomainCheckInterval(object): +class _DomainCheckInterval: """ Define a valid interval, so that : @@ -814,7 +815,7 @@ class _DomainCheckInterval(object): umath.less(x, self.a)) -class _DomainTan(object): +class _DomainTan: """ Define a valid interval for the `tan` function, so that: @@ -832,7 +833,7 @@ class _DomainTan(object): return umath.less(umath.absolute(umath.cos(x)), self.eps) -class _DomainSafeDivide(object): +class _DomainSafeDivide: """ Define a domain for safe division. @@ -853,7 +854,7 @@ class _DomainSafeDivide(object): return umath.absolute(a) * self.tolerance >= umath.absolute(b) -class _DomainGreater(object): +class _DomainGreater: """ DomainGreater(v)(x) is True where x <= v. @@ -869,7 +870,7 @@ class _DomainGreater(object): return umath.less_equal(x, self.critical_value) -class _DomainGreaterEqual(object): +class _DomainGreaterEqual: """ DomainGreaterEqual(v)(x) is True where x < v. @@ -885,14 +886,14 @@ class _DomainGreaterEqual(object): return umath.less(x, self.critical_value) -class _MaskedUFunc(object): +class _MaskedUFunc: def __init__(self, ufunc): self.f = ufunc self.__doc__ = ufunc.__doc__ self.__name__ = ufunc.__name__ def __str__(self): - return "Masked version of {}".format(self.f) + return f"Masked version of {self.f}" class _MaskedUnaryOperation(_MaskedUFunc): @@ -1798,8 +1799,7 @@ def flatten_mask(mask): try: for element in sequence: if hasattr(element, '__iter__'): - for f in _flatsequence(element): - yield f + yield from _flatsequence(element) else: yield element except TypeError: @@ -2375,7 +2375,7 @@ def masked_invalid(a, copy=True): ############################################################################### -class _MaskedPrintOption(object): +class _MaskedPrintOption: """ Handle the string used to represent missing data in a masked array. @@ -2526,8 +2526,7 @@ def flatten_structured_array(a): """ for elm in iter(iterable): if hasattr(elm, '__iter__'): - for f in flatten_sequence(elm): - yield f + yield from flatten_sequence(elm) else: yield elm @@ -2593,7 +2592,7 @@ def _arraymethod(funcname, onmask=True): return wrapped_method -class MaskedIterator(object): +class MaskedIterator: """ Flat iterator object to iterate over masked arrays. @@ -2700,8 +2699,6 @@ class MaskedIterator(object): return masked return d - next = __next__ - class MaskedArray(ndarray): """ @@ -2756,6 +2753,52 @@ class MaskedArray(ndarray): in any order (either C-, Fortran-contiguous, or even discontiguous), unless a copy is required, in which case it will be C-contiguous. + Examples + -------- + + The ``mask`` can be initialized with an array of boolean values + with the same shape as ``data``. + + >>> data = np.arange(6).reshape((2, 3)) + >>> np.ma.MaskedArray(data, mask=[[False, True, False], + ... [False, False, True]]) + masked_array( + data=[[0, --, 2], + [3, 4, --]], + mask=[[False, True, False], + [False, False, True]], + fill_value=999999) + + Alternatively, the ``mask`` can be initialized to homogeneous boolean + array with the same shape as ``data`` by passing in a scalar + boolean value: + + >>> np.ma.MaskedArray(data, mask=False) + masked_array( + data=[[0, 1, 2], + [3, 4, 5]], + mask=[[False, False, False], + [False, False, False]], + fill_value=999999) + + >>> np.ma.MaskedArray(data, mask=True) + masked_array( + data=[[--, --, --], + [--, --, --]], + mask=[[ True, True, True], + [ True, True, True]], + fill_value=999999, + dtype=int64) + + .. note:: + The recommended practice for initializing ``mask`` with a scalar + boolean value is to use ``True``/``False`` rather than + ``np.True_``/``np.False_``. The reason is :attr:`nomask` + is represented internally as ``np.False_``. + + >>> np.False_ is np.ma.nomask + True + """ __array_priority__ = 15 @@ -2817,8 +2860,8 @@ class MaskedArray(ndarray): elif isinstance(data, (tuple, list)): try: # If data is a sequence of masked array - mask = np.array([getmaskarray(m) for m in data], - dtype=mdtype) + mask = np.array([getmaskarray(np.asanyarray(m, dtype=mdtype)) + for m in data], dtype=mdtype) except ValueError: # If data is nested mask = nomask @@ -3267,11 +3310,10 @@ class MaskedArray(ndarray): dout._fill_value.flat[0]).all(): warnings.warn( "Upon accessing multidimensional field " - "{indx:s}, need to keep dimensionality " + f"{indx!s}, need to keep dimensionality " "of fill_value at 0. Discarding " "heterogeneous fill_value and setting " - "all to {fv!s}.".format(indx=indx, - fv=dout._fill_value[0]), + f"all to {dout._fill_value[0]!s}.", stacklevel=2) dout._fill_value = dout._fill_value.flat[0] dout._isfield = True @@ -3295,7 +3337,7 @@ class MaskedArray(ndarray): raise MaskError('Cannot alter the masked element.') _data = self._data _mask = self._mask - if isinstance(indx, basestring): + if isinstance(indx, str): _data[indx] = value if _mask is nomask: self._mask = _mask = make_mask_none(self.shape, self.dtype) @@ -3653,6 +3695,14 @@ class MaskedArray(ndarray): @fill_value.setter def fill_value(self, value=None): target = _check_fill_value(value, self.dtype) + if not target.ndim == 0: + # 2019-11-12, 1.18.0 + warnings.warn( + "Non-scalar arrays for the fill value are deprecated. Use " + "arrays with scalar values instead. The filled function " + "still supports any array as `fill_value`.", + DeprecationWarning, stacklevel=2) + _fill_value = self._fill_value if _fill_value is None: # Create the attribute if it was undefined @@ -3673,9 +3723,11 @@ class MaskedArray(ndarray): Parameters ---------- - fill_value : scalar, optional - The value to use for invalid entries (None by default). - If None, the `fill_value` attribute of the array is used instead. + fill_value : array_like, optional + The value to use for invalid entries. Can be scalar or non-scalar. + If non-scalar, the resulting ndarray must be broadcastable over + input array. Default is None, in which case, the `fill_value` + attribute of the array is used instead. Returns ------- @@ -3694,6 +3746,8 @@ class MaskedArray(ndarray): >>> x = np.ma.array([1,2,3,4,5], mask=[0,0,1,0,1], fill_value=-999) >>> x.filled() array([ 1, 2, -999, 4, -999]) + >>> x.filled(fill_value=1000) + array([ 1, 2, 1000, 4, 1000]) >>> type(x.filled()) <class 'numpy.ndarray'> @@ -3874,10 +3928,6 @@ class MaskedArray(ndarray): def __str__(self): return str(self._insert_masked_print()) - if sys.version_info.major < 3: - def __unicode__(self): - return unicode(self._insert_masked_print()) - def __repr__(self): """ Literal string representation. @@ -3907,7 +3957,7 @@ class MaskedArray(ndarray): ) return _legacy_print_templates[key] % parameters - prefix = 'masked_{}('.format(name) + prefix = f"masked_{name}(" dtype_needed = ( not np.core.arrayprint.dtype_is_implied(self.dtype) or @@ -4321,17 +4371,6 @@ class MaskedArray(ndarray): raise MaskError('Cannot convert masked element to a Python int.') return int(self.item()) - def __long__(self): - """ - Convert to long. - """ - if self.size > 1: - raise TypeError("Only length-1 arrays can be converted " - "to Python scalars") - elif self._mask: - raise MaskError('Cannot convert masked element to a Python long.') - return long(self.item()) - @property def imag(self): """ @@ -4394,7 +4433,7 @@ class MaskedArray(ndarray): ---------- axis : None or int or tuple of ints, optional Axis or axes along which the count is performed. - The default (`axis` = `None`) performs the count over all + The default, None, performs the count over all the dimensions of the input array. `axis` may be negative, in which case it counts from the last to the first axis. @@ -4727,7 +4766,7 @@ class MaskedArray(ndarray): >>> x = np.ma.array([1, 2, 3]) >>> x.ids() - (166691080, 3083169284L) # may vary + (166691080, 3083169284) # may vary """ if self._mask is nomask: @@ -4774,7 +4813,7 @@ class MaskedArray(ndarray): See Also -------- - ndarray.all : corresponding function for ndarrays + numpy.ndarray.all : corresponding function for ndarrays numpy.all : equivalent function Examples @@ -4812,7 +4851,7 @@ class MaskedArray(ndarray): See Also -------- - ndarray.any : corresponding function for ndarrays + numpy.ndarray.any : corresponding function for ndarrays numpy.any : equivalent function """ @@ -4866,7 +4905,7 @@ class MaskedArray(ndarray): flatnonzero : Return indices that are non-zero in the flattened version of the input array. - ndarray.nonzero : + numpy.ndarray.nonzero : Equivalent ndarray method. count_nonzero : Counts the number of non-zero elements in the input array. @@ -4994,7 +5033,7 @@ class MaskedArray(ndarray): See Also -------- - ndarray.sum : corresponding function for ndarrays + numpy.ndarray.sum : corresponding function for ndarrays numpy.sum : equivalent function Examples @@ -5065,7 +5104,7 @@ class MaskedArray(ndarray): See Also -------- - ndarray.cumsum : corresponding function for ndarrays + numpy.ndarray.cumsum : corresponding function for ndarrays numpy.cumsum : equivalent function Examples @@ -5102,7 +5141,7 @@ class MaskedArray(ndarray): See Also -------- - ndarray.prod : corresponding function for ndarrays + numpy.ndarray.prod : corresponding function for ndarrays numpy.prod : equivalent function """ kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims} @@ -5148,7 +5187,7 @@ class MaskedArray(ndarray): See Also -------- - ndarray.cumprod : corresponding function for ndarrays + numpy.ndarray.cumprod : corresponding function for ndarrays numpy.cumprod : equivalent function """ result = self.filled(1).cumprod(axis=axis, dtype=dtype, out=out) @@ -5171,7 +5210,7 @@ class MaskedArray(ndarray): See Also -------- - ndarray.mean : corresponding function for ndarrays + numpy.ndarray.mean : corresponding function for ndarrays numpy.mean : Equivalent function numpy.ma.average: Weighted average. @@ -5260,7 +5299,7 @@ class MaskedArray(ndarray): See Also -------- - ndarray.var : corresponding function for ndarrays + numpy.ndarray.var : corresponding function for ndarrays numpy.var : Equivalent function """ kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims} @@ -5323,7 +5362,7 @@ class MaskedArray(ndarray): See Also -------- - ndarray.std : corresponding function for ndarrays + numpy.ndarray.std : corresponding function for ndarrays numpy.std : Equivalent function """ kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims} @@ -5344,7 +5383,7 @@ class MaskedArray(ndarray): See Also -------- - ndarray.around : corresponding function for ndarrays + numpy.ndarray.around : corresponding function for ndarrays numpy.around : equivalent function """ result = self._data.round(decimals=decimals, out=out).view(type(self)) @@ -5406,7 +5445,7 @@ class MaskedArray(ndarray): -------- MaskedArray.sort : Describes sorting algorithms used. lexsort : Indirect stable sort with multiple keys. - ndarray.sort : Inplace sort. + numpy.ndarray.sort : Inplace sort. Notes ----- @@ -5558,7 +5597,7 @@ class MaskedArray(ndarray): See Also -------- - ndarray.sort : Method to sort an array in-place. + numpy.ndarray.sort : Method to sort an array in-place. argsort : Indirect sort. lexsort : Indirect stable sort on multiple keys. searchsorted : Find elements in a sorted array. @@ -5850,13 +5889,13 @@ class MaskedArray(ndarray): def partition(self, *args, **kwargs): warnings.warn("Warning: 'partition' will ignore the 'mask' " - "of the {}.".format(self.__class__.__name__), + f"of the {self.__class__.__name__}.", stacklevel=2) return super(MaskedArray, self).partition(*args, **kwargs) def argpartition(self, *args, **kwargs): warnings.warn("Warning: 'argpartition' will ignore the 'mask' " - "of the {}.".format(self.__class__.__name__), + f"of the {self.__class__.__name__}.", stacklevel=2) return super(MaskedArray, self).argpartition(*args, **kwargs) @@ -5948,10 +5987,17 @@ class MaskedArray(ndarray): return result.tolist() def tostring(self, fill_value=None, order='C'): + r""" + A compatibility alias for `tobytes`, with exactly the same behavior. + + Despite its name, it returns `bytes` not `str`\ s. + + .. deprecated:: 1.19.0 """ - This function is a compatibility alias for tobytes. Despite its name it - returns bytes not strings. - """ + # 2020-03-30, Numpy 1.19.0 + warnings.warn( + "tostring() is deprecated. Use tobytes() instead.", + DeprecationWarning, stacklevel=2) return self.tobytes(fill_value, order=order) @@ -5978,7 +6024,7 @@ class MaskedArray(ndarray): See Also -------- - ndarray.tobytes + numpy.ndarray.tobytes tolist, tofile Notes @@ -6202,8 +6248,7 @@ class mvoid(MaskedArray): "Defines an iterator for mvoid" (_data, _mask) = (self._data, self._mask) if _mask is nomask: - for d in _data: - yield d + yield from _data else: for (d, m) in zip(_data, _mask): if m: @@ -6220,9 +6265,11 @@ class mvoid(MaskedArray): Parameters ---------- - fill_value : scalar, optional - The value to use for invalid entries (None by default). - If None, the `fill_value` attribute is used instead. + fill_value : array_like, optional + The value to use for invalid entries. Can be scalar or + non-scalar. If latter is the case, the filled array should + be broadcastable over input array. Default is None, in + which case the `fill_value` attribute is used instead. Returns ------- @@ -6371,10 +6418,6 @@ class MaskedConstant(MaskedArray): def __str__(self): return str(masked_print_option._display) - if sys.version_info.major < 3: - def __unicode__(self): - return unicode(masked_print_option._display) - def __repr__(self): if self is MaskedConstant.__singleton: return 'masked' @@ -6382,6 +6425,21 @@ class MaskedConstant(MaskedArray): # it's a subclass, or something is wrong, make it obvious return object.__repr__(self) + def __format__(self, format_spec): + # Replace ndarray.__format__ with the default, which supports no format characters. + # Supporting format characters is unwise here, because we do not know what type + # the user was expecting - better to not guess. + try: + return object.__format__(self, format_spec) + except TypeError: + # 2020-03-23, NumPy 1.19.0 + warnings.warn( + "Format strings passed to MaskedConstant are ignored, but in future may " + "error or produce different behavior", + FutureWarning, stacklevel=2 + ) + return object.__format__(self, "") + def __reduce__(self): """Override of MaskedArray's __reduce__. """ @@ -6418,7 +6476,7 @@ class MaskedConstant(MaskedArray): return super(MaskedConstant, self).__setattr__(attr, value) elif self is self.__singleton: raise AttributeError( - "attributes of {!r} are not writeable".format(self)) + f"attributes of {self!r} are not writeable") else: # duplicate instance - we can end up here from __array_finalize__, # where we set the __class__ attribute @@ -6523,8 +6581,8 @@ class _extrema_operation(_MaskedUFunc): if b is None: # 2016-04-13, 1.13.0 warnings.warn( - "Single-argument form of np.ma.{0} is deprecated. Use " - "np.ma.{0}.reduce instead.".format(self.__name__), + f"Single-argument form of np.ma.{self.__name__} is deprecated. Use " + f"np.ma.{self.__name__}.reduce instead.", DeprecationWarning, stacklevel=2) return self.reduce(a) return where(self.compare(a, b), a, b) @@ -6537,11 +6595,9 @@ class _extrema_operation(_MaskedUFunc): if axis is np._NoValue and target.ndim > 1: # 2017-05-06, Numpy 1.13.0: warn on axis default warnings.warn( - "In the future the default for ma.{0}.reduce will be axis=0, " - "not the current None, to match np.{0}.reduce. " - "Explicitly pass 0 or None to silence this warning.".format( - self.__name__ - ), + f"In the future the default for ma.{self.__name__}.reduce will be axis=0, " + f"not the current None, to match np.{self.__name__}.reduce. " + "Explicitly pass 0 or None to silence this warning.", MaskedArrayFutureWarning, stacklevel=2) axis = None @@ -6621,7 +6677,7 @@ ptp.__doc__ = MaskedArray.ptp.__doc__ ############################################################################## -class _frommethod(object): +class _frommethod: """ Define functions from existing MaskedArray methods. @@ -7880,10 +7936,8 @@ def asanyarray(a, dtype=None): def _pickle_warn(method): # NumPy 1.15.0, 2017-12-10 warnings.warn( - "np.ma.{method} is deprecated, use pickle.{method} instead" - .format(method=method), - DeprecationWarning, - stacklevel=3) + f"np.ma.{method} is deprecated, use pickle.{method} instead", + DeprecationWarning, stacklevel=3) def fromfile(file, dtype=float, count=-1, sep=''): @@ -7955,7 +8009,7 @@ def fromflex(fxarray): return masked_array(fxarray['_data'], mask=fxarray['_mask']) -class _convert2ma(object): +class _convert2ma: """ Convert functions from numpy to numpy.ma. diff --git a/numpy/ma/extras.py b/numpy/ma/extras.py index de1aa3af8..31648fb2e 100644 --- a/numpy/ma/extras.py +++ b/numpy/ma/extras.py @@ -8,8 +8,6 @@ A collection of utilities for `numpy.ma`. :version: $Id: extras.py 3473 2007-10-29 15:18:13Z jarrod.millman $ """ -from __future__ import division, absolute_import, print_function - __all__ = [ 'apply_along_axis', 'apply_over_axes', 'atleast_1d', 'atleast_2d', 'atleast_3d', 'average', 'clump_masked', 'clump_unmasked', @@ -214,7 +212,7 @@ def masked_all_like(arr): #####-------------------------------------------------------------------------- #---- --- Standard functions --- #####-------------------------------------------------------------------------- -class _fromnxfunction(object): +class _fromnxfunction: """ Defines a wrapper to adapt NumPy functions to masked arrays. @@ -542,7 +540,7 @@ def average(a, axis=None, weights=None, returned=False): Data to be averaged. Masked entries are not taken into account in the computation. axis : int, optional - Axis along which to average `a`. If `None`, averaging is done over + Axis along which to average `a`. If None, averaging is done over the flattened array. weights : array_like, optional The importance that each element has in the computation of the average. @@ -937,7 +935,7 @@ def compress_cols(a): raise NotImplementedError("compress_cols works for 2D arrays only.") return compress_rowcols(a, 1) -def mask_rows(a, axis=None): +def mask_rows(a, axis=np._NoValue): """ Mask rows of a 2D array that contain masked values. @@ -979,9 +977,15 @@ def mask_rows(a, axis=None): fill_value=1) """ + if axis is not np._NoValue: + # remove the axis argument when this deprecation expires + # NumPy 1.18.0, 2019-11-28 + warnings.warn( + "The axis argument has always been ignored, in future passing it " + "will raise TypeError", DeprecationWarning, stacklevel=2) return mask_rowcols(a, 0) -def mask_cols(a, axis=None): +def mask_cols(a, axis=np._NoValue): """ Mask columns of a 2D array that contain masked values. @@ -1022,6 +1026,12 @@ def mask_cols(a, axis=None): fill_value=1) """ + if axis is not np._NoValue: + # remove the axis argument when this deprecation expires + # NumPy 1.18.0, 2019-11-28 + warnings.warn( + "The axis argument has always been ignored, in future passing it " + "will raise TypeError", DeprecationWarning, stacklevel=2) return mask_rowcols(a, 1) diff --git a/numpy/ma/mrecords.py b/numpy/ma/mrecords.py index 826fb0f64..cd93a9a14 100644 --- a/numpy/ma/mrecords.py +++ b/numpy/ma/mrecords.py @@ -8,18 +8,14 @@ and the masking of individual fields. .. moduleauthor:: Pierre Gerard-Marchant """ -from __future__ import division, absolute_import, print_function - # We should make sure that no field is called '_mask','mask','_fieldmask', # or whatever restricted keywords. An idea would be to no bother in the # first place, and then rename the invalid fields with a trailing # underscore. Maybe we could just overload the parser function ? -import sys import warnings import numpy as np -from numpy.compat import basestring from numpy import ( bool_, dtype, ndarray, recarray, array as narray ) @@ -87,7 +83,7 @@ def _get_fieldmask(self): return fdmask -class MaskedRecords(MaskedArray, object): +class MaskedRecords(MaskedArray): """ Attributes @@ -260,8 +256,7 @@ class MaskedRecords(MaskedArray, object): fielddict = ndarray.__getattribute__(self, 'dtype').fields or {} optinfo = ndarray.__getattribute__(self, '_optinfo') or {} if not (attr in fielddict or attr in optinfo): - exctype, value = sys.exc_info()[:2] - raise exctype(value) + raise else: # Get the list of names fielddict = ndarray.__getattribute__(self, 'dtype').fields or {} @@ -306,7 +301,7 @@ class MaskedRecords(MaskedArray, object): _mask = ndarray.__getattribute__(self, '_mask') _data = ndarray.view(self, _localdict['_baseclass']) # We want a field - if isinstance(indx, basestring): + if isinstance(indx, str): # Make sure _sharedmask is True to propagate back to _fieldmask # Don't use _set_mask, there are some copies being made that # break propagation Don't force the mask to nomask, that wreaks @@ -333,7 +328,7 @@ class MaskedRecords(MaskedArray, object): """ MaskedArray.__setitem__(self, indx, value) - if isinstance(indx, basestring): + if isinstance(indx, str): self._mask[indx] = ma.getmaskarray(value) def __str__(self): diff --git a/numpy/ma/setup.py b/numpy/ma/setup.py index d1d6c89b5..144a961c2 100644 --- a/numpy/ma/setup.py +++ b/numpy/ma/setup.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python -from __future__ import division, print_function - +#!/usr/bin/env python3 def configuration(parent_package='',top_path=None): from numpy.distutils.misc_util import Configuration config = Configuration('ma', parent_package, top_path) diff --git a/numpy/ma/tests/test_core.py b/numpy/ma/tests/test_core.py index b72ce56aa..98fc7dd97 100644 --- a/numpy/ma/tests/test_core.py +++ b/numpy/ma/tests/test_core.py @@ -4,8 +4,6 @@ :author: Pierre Gerard-Marchant :contact: pierregm_at_uga_dot_edu """ -from __future__ import division, absolute_import, print_function - __author__ = "Pierre GF Gerard-Marchant" import sys @@ -65,7 +63,7 @@ num_dts = [np.dtype(dt_) for dt_ in '?bhilqBHILQefdgFD'] num_ids = [dt_.char for dt_ in num_dts] -class TestMaskedArray(object): +class TestMaskedArray: # Base test class for MaskedArrays. def setup(self): @@ -449,6 +447,21 @@ class TestMaskedArray(object): assert_equal(copied.mask, [0, 0, 0]) assert_equal(a.mask, [0, 1, 0]) + def test_format(self): + a = array([0, 1, 2], mask=[False, True, False]) + assert_equal(format(a), "[0 -- 2]") + assert_equal(format(masked), "--") + assert_equal(format(masked, ""), "--") + + # Postponed from PR #15410, perhaps address in the future. + # assert_equal(format(masked, " >5"), " --") + # assert_equal(format(masked, " <5"), "-- ") + + # Expect a FutureWarning for using format_spec with MaskedElement + with assert_warns(FutureWarning): + with_format_string = format(masked, " >5") + assert_equal(with_format_string, "--") + def test_str_repr(self): a = array([0, 1, 2], mask=[False, True, False]) assert_equal(str(a), '[0 -- 2]') @@ -936,7 +949,7 @@ class TestMaskedArray(object): def test_object_with_array(self): mx1 = masked_array([1.], mask=[True]) mx2 = masked_array([1., 2.]) - mx = masked_array([mx1, mx2], mask=[False, True]) + mx = masked_array([mx1, mx2], mask=[False, True], dtype=object) assert_(mx[0] is mx1) assert_(mx[1] is not mx2) assert_(np.all(mx[1].data == mx2.data)) @@ -946,7 +959,7 @@ class TestMaskedArray(object): assert_(mx2[0] == 0.) -class TestMaskedArrayArithmetic(object): +class TestMaskedArrayArithmetic: # Base test class for MaskedArrays. def setup(self): @@ -1558,7 +1571,11 @@ class TestMaskedArrayArithmetic(object): assert_equal(test.mask, [True, True]) assert_(test.fill_value == True) - # test = (a[0] == b) # doesn't work in Python2 + test = (a[0] == b) + assert_equal(test.data, [False, False]) + assert_equal(test.mask, [True, False]) + assert_(test.fill_value == True) + test = (b == a[0]) assert_equal(test.data, [False, False]) assert_equal(test.mask, [True, False]) @@ -1586,7 +1603,11 @@ class TestMaskedArrayArithmetic(object): assert_equal(test.mask, [True, True]) assert_(test.fill_value == True) - # test = (a[0] != b) # doesn't work in Python2 + test = (a[0] != b) + assert_equal(test.data, [True, True]) + assert_equal(test.mask, [True, False]) + assert_(test.fill_value == True) + test = (b != a[0]) assert_equal(test.data, [True, True]) assert_equal(test.mask, [True, False]) @@ -1615,7 +1636,11 @@ class TestMaskedArrayArithmetic(object): assert_equal(test.mask, [True, True]) assert_(test.fill_value == True) - # test = (a[0] == b) # doesn't work in Python2 + test = (a[0] == b) + assert_equal(test.data, [False, False]) + assert_equal(test.mask, [True, False]) + assert_(test.fill_value == True) + test = (b == a[0]) assert_equal(test.data, [False, False]) assert_equal(test.mask, [True, False]) @@ -1644,7 +1669,11 @@ class TestMaskedArrayArithmetic(object): assert_equal(test.mask, [True, True]) assert_(test.fill_value == True) - # test = (a[0] != b) # doesn't work in Python2 + test = (a[0] != b) + assert_equal(test.data, [True, True]) + assert_equal(test.mask, [True, False]) + assert_(test.fill_value == True) + test = (b != a[0]) assert_equal(test.data, [True, True]) assert_equal(test.mask, [True, False]) @@ -1715,7 +1744,7 @@ class TestMaskedArrayArithmetic(object): assert_equal(a.mask, [0, 0, 0, 0, 1]) -class TestMaskedArrayAttributes(object): +class TestMaskedArrayAttributes: def test_keepmask(self): # Tests the keep mask flag @@ -1891,7 +1920,7 @@ class TestMaskedArrayAttributes(object): assert_equal(m._mask, np.ma.nomask) -class TestFillingValues(object): +class TestFillingValues: def test_check_on_scalar(self): # Test _check_fill_value set to valid and invalid values @@ -2229,7 +2258,7 @@ class TestFillingValues(object): assert_equal(a["f1"].fill_value, default_fill_value("eggs")) -class TestUfuncs(object): +class TestUfuncs: # Test class for the application of ufuncs on MaskedArrays. def setup(self): @@ -2309,7 +2338,7 @@ class TestUfuncs(object): assert_raises(TypeError, operator.mul, a, "abc") assert_raises(TypeError, operator.truediv, a, "abc") - class MyClass(object): + class MyClass: __array_priority__ = a.__array_priority__ + 1 def __mul__(self, other): @@ -2323,7 +2352,7 @@ class TestUfuncs(object): assert_(a * me == "My rmul") # and that __array_priority__ is respected - class MyClass2(object): + class MyClass2: __array_priority__ = 100 def __mul__(self, other): @@ -2373,7 +2402,7 @@ class TestUfuncs(object): # also check that allclose uses ma ufuncs, to avoid warning allclose(m, 0.5) -class TestMaskedArrayInPlaceArithmetics(object): +class TestMaskedArrayInPlaceArithmetics: # Test MaskedArray Arithmetics def setup(self): @@ -2875,7 +2904,7 @@ class TestMaskedArrayInPlaceArithmetics(object): assert_equal(len(w), 0, "Failed on type=%s." % t) -class TestMaskedArrayMethods(object): +class TestMaskedArrayMethods: # Test class for miscellaneous MaskedArrays methods. def setup(self): # Base data definition. @@ -3582,7 +3611,7 @@ class TestMaskedArrayMethods(object): assert_equal(xd.data, x.diagonal().data) -class TestMaskedArrayMathMethods(object): +class TestMaskedArrayMathMethods: def setup(self): # Base data definition. @@ -3860,7 +3889,7 @@ class TestMaskedArrayMathMethods(object): assert_equal(a.max(1), [3, 6]) -class TestMaskedArrayMathMethodsComplex(object): +class TestMaskedArrayMathMethodsComplex: # Test class for miscellaneous MaskedArrays methods. def setup(self): # Base data definition. @@ -3913,7 +3942,7 @@ class TestMaskedArrayMathMethodsComplex(object): mX[:, k].compressed().std()) -class TestMaskedArrayFunctions(object): +class TestMaskedArrayFunctions: # Test class for miscellaneous functions. def setup(self): @@ -4552,7 +4581,7 @@ class TestMaskedArrayFunctions(object): assert_equal(test, masked_equal([-1, -1, -1, -1, -1], -1)) -class TestMaskedFields(object): +class TestMaskedFields: def setup(self): ilist = [1, 2, 3, 4, 5] @@ -4714,7 +4743,7 @@ class TestMaskedFields(object): assert_equal(len(rec), len(self.data['ddtype'])) -class TestMaskedObjectArray(object): +class TestMaskedObjectArray: def test_getitem(self): arr = np.ma.array([None, None]) @@ -4762,7 +4791,7 @@ class TestMaskedObjectArray(object): assert_(arr[0] is np.ma.masked) -class TestMaskedView(object): +class TestMaskedView: def setup(self): iterator = list(zip(np.arange(10), np.random.rand(10))) @@ -4840,7 +4869,7 @@ class TestMaskedView(object): assert_(not isinstance(test, MaskedArray)) -class TestOptionalArgs(object): +class TestOptionalArgs: def test_ndarrayfuncs(self): # test axis arg behaves the same as ndarray (including multiple axes) @@ -4927,7 +4956,7 @@ class TestOptionalArgs(object): assert_raises(np.AxisError, count, np.ma.array(1), axis=1) -class TestMaskedConstant(object): +class TestMaskedConstant: def _do_add_test(self, add): # sanity check assert_(add(np.ma.masked, 1) is np.ma.masked) @@ -5008,11 +5037,6 @@ class TestMaskedConstant(object): assert_raises(MaskError, operator.setitem, a_i, (), np.ma.masked) assert_raises(MaskError, int, np.ma.masked) - @pytest.mark.skipif(sys.version_info.major == 3, - reason="long doesn't exist in Python 3") - def test_coercion_long(self): - assert_raises(MaskError, long, np.ma.masked) - def test_coercion_float(self): a_f = np.zeros((), float) assert_warns(UserWarning, operator.setitem, a_f, (), np.ma.masked) @@ -5044,7 +5068,7 @@ class TestMaskedConstant(object): assert_raises(AttributeError, setattr, np.ma.masked, 'dtype', np.int64) -class TestMaskedWhereAliases(object): +class TestMaskedWhereAliases: # TODO: Test masked_object, masked_equal, ... diff --git a/numpy/ma/tests/test_deprecations.py b/numpy/ma/tests/test_deprecations.py index 72cc29aa0..14f697375 100644 --- a/numpy/ma/tests/test_deprecations.py +++ b/numpy/ma/tests/test_deprecations.py @@ -1,14 +1,12 @@ """Test deprecation and future warnings. """ -from __future__ import division, absolute_import, print_function - import numpy as np from numpy.testing import assert_warns from numpy.ma.testutils import assert_equal from numpy.ma.core import MaskedArrayFutureWarning -class TestArgsort(object): +class TestArgsort: """ gh-8701 """ def _test_base(self, argsort, cls): arr_0d = np.array(1).view(cls) @@ -37,7 +35,7 @@ class TestArgsort(object): return self._test_base(np.ma.MaskedArray.argsort, np.ma.MaskedArray) -class TestMinimumMaximum(object): +class TestMinimumMaximum: def test_minimum(self): assert_warns(DeprecationWarning, np.ma.minimum, np.ma.array([1, 2])) diff --git a/numpy/ma/tests/test_extras.py b/numpy/ma/tests/test_extras.py index 836770378..1c8610625 100644 --- a/numpy/ma/tests/test_extras.py +++ b/numpy/ma/tests/test_extras.py @@ -7,10 +7,9 @@ Adapted from the original test_ma by Pierre Gerard-Marchant :version: $Id: test_extras.py 3473 2007-10-29 15:18:13Z jarrod.millman $ """ -from __future__ import division, absolute_import, print_function - import warnings import itertools +import pytest import numpy as np from numpy.testing import ( @@ -33,7 +32,7 @@ from numpy.ma.extras import ( ) -class TestGeneric(object): +class TestGeneric: # def test_masked_all(self): # Tests masked_all @@ -141,7 +140,7 @@ class TestGeneric(object): assert_equal(test, []) -class TestAverage(object): +class TestAverage: # Several tests of average. Why so many ? Good point... def test_testAverage1(self): # Test of average. @@ -272,7 +271,7 @@ class TestAverage(object): assert_almost_equal(wav1.imag, expected1.imag) -class TestConcatenator(object): +class TestConcatenator: # Tests for mr_, the equivalent of r_ for masked arrays. def test_1d(self): @@ -316,7 +315,7 @@ class TestConcatenator(object): assert_equal(actual.data[:2], [1, 2]) -class TestNotMasked(object): +class TestNotMasked: # Tests notmasked_edges and notmasked_contiguous. def test_edges(self): @@ -386,7 +385,7 @@ class TestNotMasked(object): ]) -class TestCompressFunctions(object): +class TestCompressFunctions: def test_compress_nd(self): # Tests compress_nd @@ -552,6 +551,18 @@ class TestCompressFunctions(object): assert_(mask_rowcols(x, 0).mask.all()) assert_(mask_rowcols(x, 1).mask.all()) + @pytest.mark.parametrize("axis", [None, 0, 1]) + @pytest.mark.parametrize(["func", "rowcols_axis"], + [(np.ma.mask_rows, 0), (np.ma.mask_cols, 1)]) + def test_mask_row_cols_axis_deprecation(self, axis, func, rowcols_axis): + # Test deprecation of the axis argument to `mask_rows` and `mask_cols` + x = array(np.arange(9).reshape(3, 3), + mask=[[1, 0, 0], [0, 0, 0], [0, 0, 0]]) + + with assert_warns(DeprecationWarning): + res = func(x, axis=axis) + assert_equal(res, mask_rowcols(x, rowcols_axis)) + def test_dot(self): # Tests dot product n = np.arange(1, 7) @@ -639,7 +650,7 @@ class TestCompressFunctions(object): assert_equal(a, res) -class TestApplyAlongAxis(object): +class TestApplyAlongAxis: # Tests 2D functions def test_3d(self): a = arange(12.).reshape(2, 2, 3) @@ -661,7 +672,7 @@ class TestApplyAlongAxis(object): assert_equal(xa, [[2, 5], [8, 11]]) -class TestApplyOverAxes(object): +class TestApplyOverAxes: # Tests apply_over_axes def test_basic(self): a = arange(24).reshape(2, 3, 4) @@ -674,7 +685,7 @@ class TestApplyOverAxes(object): assert_equal(test, ctrl) -class TestMedian(object): +class TestMedian: def test_pytype(self): r = np.ma.median([[np.inf, np.inf], [np.inf, np.inf]], axis=-1) assert_equal(r, np.inf) @@ -1053,7 +1064,7 @@ class TestMedian(object): assert_(type(np.ma.median(o.astype(object))), float) -class TestCov(object): +class TestCov: def setup(self): self.data = array(np.random.rand(12)) @@ -1120,7 +1131,7 @@ class TestCov(object): x.shape[0] / frac)) -class TestCorrcoef(object): +class TestCorrcoef: def setup(self): self.data = array(np.random.rand(12)) @@ -1227,7 +1238,7 @@ class TestCorrcoef(object): control[:-1, :-1]) -class TestPolynomial(object): +class TestPolynomial: # def test_polyfit(self): # Tests polyfit @@ -1285,7 +1296,7 @@ class TestPolynomial(object): assert_almost_equal(a, a_) -class TestArraySetOps(object): +class TestArraySetOps: def test_unique_onlist(self): # Test unique on list @@ -1517,7 +1528,7 @@ class TestArraySetOps(object): assert_array_equal(setdiff1d(a, b), np.array(['c'])) -class TestShapeBase(object): +class TestShapeBase: def test_atleast_2d(self): # Test atleast_2d @@ -1573,7 +1584,7 @@ class TestShapeBase(object): assert_equal(b.mask.shape, b.data.shape) -class TestStack(object): +class TestStack: def test_stack_1d(self): a = masked_array([0, 1, 2], mask=[0, 1, 0]) diff --git a/numpy/ma/tests/test_mrecords.py b/numpy/ma/tests/test_mrecords.py index 94e772d55..c2f859273 100644 --- a/numpy/ma/tests/test_mrecords.py +++ b/numpy/ma/tests/test_mrecords.py @@ -5,8 +5,6 @@ :contact: pierregm_at_uga_dot_edu """ -from __future__ import division, absolute_import, print_function - import numpy as np import numpy.ma as ma from numpy import recarray @@ -26,7 +24,7 @@ from numpy.ma.testutils import ( from numpy.compat import pickle -class TestMRecords(object): +class TestMRecords: ilist = [1, 2, 3, 4, 5] flist = [1.1, 2.2, 3.3, 4.4, 5.5] @@ -348,7 +346,7 @@ class TestMRecords(object): dtype=mult.dtype)) -class TestView(object): +class TestView: def setup(self): (a, b) = (np.arange(10), np.random.rand(10)) @@ -386,7 +384,7 @@ class TestView(object): ############################################################################## -class TestMRecordsImport(object): +class TestMRecordsImport: _a = ma.array([1, 2, 3], mask=[0, 0, 1], dtype=int) _b = ma.array([1.1, 2.2, 3.3], mask=[0, 0, 1], dtype=float) diff --git a/numpy/ma/tests/test_old_ma.py b/numpy/ma/tests/test_old_ma.py index 7100eccbb..96c7e3609 100644 --- a/numpy/ma/tests/test_old_ma.py +++ b/numpy/ma/tests/test_old_ma.py @@ -1,5 +1,3 @@ -from __future__ import division, absolute_import, print_function - from functools import reduce import numpy as np @@ -33,7 +31,7 @@ def eq(v, w, msg=''): return result -class TestMa(object): +class TestMa: def setup(self): x = np.array([1., 1., 1., -2., pi/2.0, 4., 5., -10., 10., 1., 2., 3.]) @@ -700,7 +698,7 @@ class TestMa(object): assert_equal(b[1].shape, ()) -class TestUfuncs(object): +class TestUfuncs: def setup(self): self.d = (array([1.0, 0, -1, pi / 2] * 2, mask=[0, 1] + [0] * 6), array([1.0, 0, -1, pi / 2] * 2, mask=[1, 0] + [0] * 6),) @@ -765,7 +763,7 @@ class TestUfuncs(object): assert_(eq(nonzero(x), [0])) -class TestArrayMethods(object): +class TestArrayMethods: def setup(self): x = np.array([8.375, 7.545, 8.828, 8.5, 1.757, 5.928, diff --git a/numpy/ma/tests/test_regression.py b/numpy/ma/tests/test_regression.py index b83873a5a..7e76eb054 100644 --- a/numpy/ma/tests/test_regression.py +++ b/numpy/ma/tests/test_regression.py @@ -1,12 +1,10 @@ -from __future__ import division, absolute_import, print_function - import numpy as np from numpy.testing import ( assert_, assert_array_equal, assert_allclose, suppress_warnings ) -class TestRegression(object): +class TestRegression: def test_masked_array_create(self): # Ticket #17 x = np.ma.masked_array([0, 1, 2, 3, 0, 4, 5, 6], @@ -88,6 +86,6 @@ class TestRegression(object): ma = np.ma.MaskedArray([(1, 1.), (2, 2.), (3, 3.)], dtype='i4,f4') assert_array_equal(ma[[]], ma[:0]) - def test_masked_array_tostring_fortran(self): + def test_masked_array_tobytes_fortran(self): ma = np.ma.arange(4).reshape((2,2)) - assert_array_equal(ma.tostring(order='F'), ma.T.tostring()) + assert_array_equal(ma.tobytes(order='F'), ma.T.tobytes()) diff --git a/numpy/ma/tests/test_subclassing.py b/numpy/ma/tests/test_subclassing.py index 440b36722..caa746740 100644 --- a/numpy/ma/tests/test_subclassing.py +++ b/numpy/ma/tests/test_subclassing.py @@ -6,8 +6,6 @@ :version: $Id: test_subclassing.py 3473 2007-10-29 15:18:13Z jarrod.millman $ """ -from __future__ import division, absolute_import, print_function - import numpy as np from numpy.testing import assert_, assert_raises from numpy.ma.testutils import assert_equal @@ -80,7 +78,7 @@ msubarray = MSubArray # and overrides __array_wrap__, updating the info dict, to check that this # doesn't get destroyed by MaskedArray._update_from. But this one also needs # its own iterator... -class CSAIterator(object): +class CSAIterator: """ Flat iterator object that uses its own setter/getter (works around ndarray.flat not propagating subclass setters/getters @@ -107,8 +105,6 @@ class CSAIterator(object): def __next__(self): return next(self._dataiter).__array__().view(type(self._original)) - next = __next__ - class ComplicatedSubArray(SubArray): @@ -154,7 +150,7 @@ class ComplicatedSubArray(SubArray): return obj -class TestSubclassing(object): +class TestSubclassing: # Test suite for masked subclasses of ndarray. def setup(self): diff --git a/numpy/ma/testutils.py b/numpy/ma/testutils.py index c0deaa9f4..51ab03948 100644 --- a/numpy/ma/testutils.py +++ b/numpy/ma/testutils.py @@ -5,8 +5,6 @@ :version: $Id: testutils.py 3529 2007-11-13 08:01:14Z jarrod.millman $ """ -from __future__ import division, absolute_import, print_function - import operator import numpy as np diff --git a/numpy/ma/timer_comparison.py b/numpy/ma/timer_comparison.py index 4ad635e38..83bd7852e 100644 --- a/numpy/ma/timer_comparison.py +++ b/numpy/ma/timer_comparison.py @@ -1,5 +1,3 @@ -from __future__ import division, absolute_import, print_function - import timeit from functools import reduce @@ -15,7 +13,7 @@ np.seterr(all='ignore') pi = np.pi -class ModuleTester(object): +class ModuleTester: def __init__(self, module): self.module = module self.allequal = module.allequal |