text: # pylint: disable-msg=W0611, W0612, W0511,R0201
  """Tests suite for MaskedArray & subclassing.
  
  :author: Pierre Gerard-Marchant
  :contact: pierregm_at_uga_dot_edu
  :version: $Id: test_subclassing.py 3473 2007-10-29 15:18:13Z jarrod.millman $
  
  """
  from __future__ import division, absolute_import, print_function
  
  __author__ = "Pierre GF Gerard-Marchant ($Author: jarrod.millman $)"
  __version__ = '1.0'
  __revision__ = "$Revision: 3473 $"
  __date__ = '$Date: 2007-10-29 17:18:13 +0200 (Mon, 29 Oct 2007) $'
  
  import numpy as np
  from numpy.testing import *
  from numpy.ma.testutils import *
  from numpy.ma.core import *
  
  
  class SubArray(np.ndarray):
      # Defines a generic np.ndarray subclass, that stores some metadata
      # in the  dictionary `info`.
      def __new__(cls,arr,info={}):
          x = np.asanyarray(arr).view(cls)
          x.info = info.copy()
          return x
  
      def __array_finalize__(self, obj):
          if callable(getattr(super(SubArray, self),
                              '__array_finalize__', None)):
              super(SubArray, self).__array_finalize__(obj)
          self.info = getattr(obj, 'info', {}).copy()
          return
  
      def __add__(self, other):
          result = super(SubArray, self).__add__(other)
          result.info['added'] = result.info.get('added', 0) + 1
          return result
  
      def __iadd__(self, other):
          result = super(SubArray, self).__iadd__(other)
          result.info['iadded'] = result.info.get('iadded', 0) + 1
          return result
  
  
  subarray = SubArray
  
  
  class MSubArray(SubArray, MaskedArray):
  
      def __new__(cls, data, info={}, mask=nomask):
          subarr = SubArray(data, info)
          _data = MaskedArray.__new__(cls, data=subarr, mask=mask)
          _data.info = subarr.info
          return _data
  
      def _get_series(self):
          _view = self.view(MaskedArray)
          _view._sharedmask = False
          return _view
      _series = property(fget=_get_series)
  
  msubarray = MSubArray
  
  
  class MMatrix(MaskedArray, np.matrix,):
  
      def __new__(cls, data, mask=nomask):
          mat = np.matrix(data)
          _data = MaskedArray.__new__(cls, data=mat, mask=mask)
          return _data
  
      def __array_finalize__(self, obj):
          np.matrix.__array_finalize__(self, obj)
          MaskedArray.__array_finalize__(self, obj)
          return
  
      def _get_series(self):
          _view = self.view(MaskedArray)
          _view._sharedmask = False
          return _view
      _series = property(fget=_get_series)
  
  mmatrix = MMatrix
  
  
  # Also a subclass that overrides __str__, __repr__ and __setitem__, disallowing
  # setting to non-class values (and thus np.ma.core.masked_print_option)
  # 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):
      """
      Flat iterator object that uses its own setter/getter
      (works around ndarray.flat not propagating subclass setters/getters
      see https://github.com/numpy/numpy/issues/4564)
      roughly following MaskedIterator
      """
      def __init__(self, a):
          self._original = a
          self._dataiter = a.view(np.ndarray).flat
  
      def __iter__(self):
          return self
  
      def __getitem__(self, indx):
          out = self._dataiter.__getitem__(indx)
          if not isinstance(out, np.ndarray):
              out = out.__array__()
          out = out.view(type(self._original))
          return out
  
      def __setitem__(self, index, value):
          self._dataiter[index] = self._original._validate_input(value)
  
      def __next__(self):
          return next(self._dataiter).__array__().view(type(self._original))
  
      next = __next__
  
  
  class ComplicatedSubArray(SubArray):
  
      def __str__(self):
          return 'myprefix {0} mypostfix'.format(self.view(SubArray))
  
      def __repr__(self):
          # Return a repr that does not start with 'name('
          return '<{0} {1}>'.format(self.__class__.__name__, self)
  
      def _validate_input(self, value):
          if not isinstance(value, ComplicatedSubArray):
              raise ValueError("Can only set to MySubArray values")
          return value
  
      def __setitem__(self, item, value):
          # validation ensures direct assignment with ndarray or
          # masked_print_option will fail
          super(ComplicatedSubArray, self).__setitem__(
              item, self._validate_input(value))
  
      def __getitem__(self, item):
          # ensure getter returns our own class also for scalars
          value = super(ComplicatedSubArray, self).__getitem__(item)
          if not isinstance(value, np.ndarray):  # scalar
              value = value.__array__().view(ComplicatedSubArray)
          return value
  
      @property
      def flat(self):
          return CSAIterator(self)
  
      @flat.setter
      def flat(self, value):
          y = self.ravel()
          y[:] = value
  
      def __array_wrap__(self, obj, context=None):
          obj = super(ComplicatedSubArray, self).__array_wrap__(obj, context)
          if context is not None and context[0] is np.multiply:
              obj.info['multiplied'] = obj.info.get('multiplied', 0) + 1
  
          return obj
  
  
  class TestSubclassing(TestCase):
      # Test suite for masked subclasses of ndarray.
  
      def setUp(self):
          x = np.arange(5)
          mx = mmatrix(x, mask=[0, 1, 0, 0, 0])
          self.data = (x, mx)
  
      def test_data_subclassing(self):
          # Tests whether the subclass is kept.
          x = np.arange(5)
          m = [0, 0, 1, 0, 0]
          xsub = SubArray(x)
          xmsub = masked_array(xsub, mask=m)
          self.assertTrue(isinstance(xmsub, MaskedArray))
          assert_equal(xmsub._data, xsub)
          self.assertTrue(isinstance(xmsub._data, SubArray))
  
      def test_maskedarray_subclassing(self):
          # Tests subclassing MaskedArray
          (x, mx) = self.data
          self.assertTrue(isinstance(mx._data, np.matrix))
  
      def test_masked_unary_operations(self):
          # Tests masked_unary_operation
          (x, mx) = self.data
          with np.errstate(divide='ignore'):
              self.assertTrue(isinstance(log(mx), mmatrix))
              assert_equal(log(x), np.log(x))
  
      def test_masked_binary_operations(self):
          # Tests masked_binary_operation
          (x, mx) = self.data
          # Result should be a mmatrix
          self.assertTrue(isinstance(add(mx, mx), mmatrix))
          self.assertTrue(isinstance(add(mx, x), mmatrix))
          # Result should work
          assert_equal(add(mx, x), mx+x)
          self.assertTrue(isinstance(add(mx, mx)._data, np.matrix))
          self.assertTrue(isinstance(add.outer(mx, mx), mmatrix))
          self.assertTrue(isinstance(hypot(mx, mx), mmatrix))
          self.assertTrue(isinstance(hypot(mx, x), mmatrix))
  
      def test_masked_binary_operations2(self):
          # Tests domained_masked_binary_operation
          (x, mx) = self.data
          xmx = masked_array(mx.data.__array__(), mask=mx.mask)
          self.assertTrue(isinstance(divide(mx, mx), mmatrix))
          self.assertTrue(isinstance(divide(mx, x), mmatrix))
          assert_equal(divide(mx, mx), divide(xmx, xmx))
  
      def test_attributepropagation(self):
          x = array(arange(5), mask=[0]+[1]*4)
          my = masked_array(subarray(x))
          ym = msubarray(x)
          #
          z = (my+1)
          self.assertTrue(isinstance(z, MaskedArray))
          self.assertTrue(not isinstance(z, MSubArray))
          self.assertTrue(isinstance(z._data, SubArray))
          assert_equal(z._data.info, {})
          #
          z = (ym+1)
          self.assertTrue(isinstance(z, MaskedArray))
          self.assertTrue(isinstance(z, MSubArray))
          self.assertTrue(isinstance(z._data, SubArray))
          self.assertTrue(z._data.info['added'] > 0)
          # Test that inplace methods from data get used (gh-4617)
          ym += 1
          self.assertTrue(isinstance(ym, MaskedArray))
          self.assertTrue(isinstance(ym, MSubArray))
          self.assertTrue(isinstance(ym._data, SubArray))
          self.assertTrue(ym._data.info['iadded'] > 0)
          #
          ym._set_mask([1, 0, 0, 0, 1])
          assert_equal(ym._mask, [1, 0, 0, 0, 1])
          ym._series._set_mask([0, 0, 0, 0, 1])
          assert_equal(ym._mask, [0, 0, 0, 0, 1])
          #
          xsub = subarray(x, info={'name':'x'})
          mxsub = masked_array(xsub)
          self.assertTrue(hasattr(mxsub, 'info'))
          assert_equal(mxsub.info, xsub.info)
  
      def test_subclasspreservation(self):
          # Checks that masked_array(...,subok=True) preserves the class.
          x = np.arange(5)
          m = [0, 0, 1, 0, 0]
          xinfo = [(i, j) for (i, j) in zip(x, m)]
          xsub = MSubArray(x, mask=m, info={'xsub':xinfo})
          #
          mxsub = masked_array(xsub, subok=False)
          self.assertTrue(not isinstance(mxsub, MSubArray))
          self.assertTrue(isinstance(mxsub, MaskedArray))
          assert_equal(mxsub._mask, m)
          #
          mxsub = asarray(xsub)
          self.assertTrue(not isinstance(mxsub, MSubArray))
          self.assertTrue(isinstance(mxsub, MaskedArray))
          assert_equal(mxsub._mask, m)
          #
          mxsub = masked_array(xsub, subok=True)
          self.assertTrue(isinstance(mxsub, MSubArray))
          assert_equal(mxsub.info, xsub.info)
          assert_equal(mxsub._mask, xsub._mask)
          #
          mxsub = asanyarray(xsub)
          self.assertTrue(isinstance(mxsub, MSubArray))
          assert_equal(mxsub.info, xsub.info)
          assert_equal(mxsub._mask, m)
  
      def test_subclass_items(self):
          """test that getter and setter go via baseclass"""
          x = np.arange(5)
          xcsub = ComplicatedSubArray(x)
          mxcsub = masked_array(xcsub, mask=[True, False, True, False, False])
          # getter should  return a ComplicatedSubArray, even for single item
          # first check we wrote ComplicatedSubArray correctly
          self.assertTrue(isinstance(xcsub[1], ComplicatedSubArray))
          self.assertTrue(isinstance(xcsub[1:4], ComplicatedSubArray))
          # now that it propagates inside the MaskedArray
          self.assertTrue(isinstance(mxcsub[1], ComplicatedSubArray))
          self.assertTrue(mxcsub[0] is masked)
          self.assertTrue(isinstance(mxcsub[1:4].data, ComplicatedSubArray))
          # also for flattened version (which goes via MaskedIterator)
          self.assertTrue(isinstance(mxcsub.flat[1].data, ComplicatedSubArray))
          self.assertTrue(mxcsub[0] is masked)
          self.assertTrue(isinstance(mxcsub.flat[1:4].base, ComplicatedSubArray))
  
          # setter should only work with ComplicatedSubArray input
          # first check we wrote ComplicatedSubArray correctly
          assert_raises(ValueError, xcsub.__setitem__, 1, x[4])
          # now that it propagates inside the MaskedArray
          assert_raises(ValueError, mxcsub.__setitem__, 1, x[4])
          assert_raises(ValueError, mxcsub.__setitem__, slice(1, 4), x[1:4])
          mxcsub[1] = xcsub[4]
          mxcsub[1:4] = xcsub[1:4]
          # also for flattened version (which goes via MaskedIterator)
          assert_raises(ValueError, mxcsub.flat.__setitem__, 1, x[4])
          assert_raises(ValueError, mxcsub.flat.__setitem__, slice(1, 4), x[1:4])
          mxcsub.flat[1] = xcsub[4]
          mxcsub.flat[1:4] = xcsub[1:4]
  
      def test_subclass_repr(self):
          """test that repr uses the name of the subclass
          and 'array' for np.ndarray"""
          x = np.arange(5)
          mx = masked_array(x, mask=[True, False, True, False, False])
          self.assertTrue(repr(mx).startswith('masked_array'))
          xsub = SubArray(x)
          mxsub = masked_array(xsub, mask=[True, False, True, False, False])
          self.assertTrue(repr(mxsub).startswith(
              'masked_{0}(data = [-- 1 -- 3 4]'.format(SubArray.__name__)))
  
      def test_subclass_str(self):
          """test str with subclass that has overridden str, setitem"""
          # first without override
          x = np.arange(5)
          xsub = SubArray(x)
          mxsub = masked_array(xsub, mask=[True, False, True, False, False])
          self.assertTrue(str(mxsub) == '[-- 1 -- 3 4]')
  
          xcsub = ComplicatedSubArray(x)
          assert_raises(ValueError, xcsub.__setitem__, 0,
                        np.ma.core.masked_print_option)
          mxcsub = masked_array(xcsub, mask=[True, False, True, False, False])
          self.assertTrue(str(mxcsub) == 'myprefix [-- 1 -- 3 4] mypostfix')
  
  
  ###############################################################################
  if __name__ == '__main__':
      run_module_suite()
  