Repository: numpy/numpy

Issue:
MaskedArray record: TypeError: len() of unsized object (Trac #2116)
_Original ticket http://projects.scipy.org/numpy/ticket/2116 on 2012-04-26 by trac user mwtoews, assigned to @pierregm._

I'm getting a inconsistent error while trying to get the length of a record from a masked array, but only when the mask is enabled. See the example:

```
import numpy as np

my_dtype = [('a','i'),('b','f')]
mar = np.ma.zeros(5, my_dtype)

# Length of the first record; no error raised
assert len(mar[0]) == 2

# Change mask for one of the fields
print(mar[0])          # (0, 0.0)
mar.mask[0][0] = True
print(mar[0])          # (--, 0.0)

# Repeat same command as above to reveal this bug
assert len(mar[0]) == 2
```

Raises the error:

```
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
TypeError: len() of unsized object
```

I am using !NumPy version 1.6.1 obtained from http://www.lfd.uci.edu/~gohlke/pythonlibs/#numpy and the version of Python is 2.5.1 [MSC v.1310 32 bit (Intel)].



Discussion:

Resolving patch:
diff --git a/numpy/ma/core.py b/numpy/ma/core.py
--- a/numpy/ma/core.py
+++ b/numpy/ma/core.py
@@ -5593,6 +5593,9 @@ def __iter__(self):
                 else:
                     yield d
 
+    def __len__(self):
+        return self._data.__len__()
+
     def filled(self, fill_value=None):
         """
         Return a copy with masked fields filled with a given value.
@@ -5930,9 +5933,10 @@ class _frommethod:
         Name of the method to transform.
 
     """
-    def __init__(self, methodname):
+    def __init__(self, methodname, reversed=False):
         self.__name__ = methodname
         self.__doc__ = self.getdoc()
+        self.reversed = reversed
     #
     def getdoc(self):
         "Return the doc of the function (from the doc of the method)."
@@ -5944,6 +5948,11 @@ def getdoc(self):
             return doc
     #
     def __call__(self, a, *args, **params):
+        if self.reversed:
+            args = list(args)
+            arr = args[0]
+            args[0] = a
+            a = arr
         # Get the method from the array (if possible)
         method_name = self.__name__
         method = getattr(a, method_name, None)
@@ -5960,7 +5969,7 @@ def __call__(self, a, *args, **params):
 all = _frommethod('all')
 anomalies = anom = _frommethod('anom')
 any = _frommethod('any')
-compress = _frommethod('compress')
+compress = _frommethod('compress', reversed=True)
 cumprod = _frommethod('cumprod')
 cumsum = _frommethod('cumsum')
 copy = _frommethod('copy')


Test patch:
diff --git a/numpy/ma/tests/test_core.py b/numpy/ma/tests/test_core.py
--- a/numpy/ma/tests/test_core.py
+++ b/numpy/ma/tests/test_core.py
@@ -3330,6 +3330,19 @@ def test_on_ndarray(self):
         test = reshape(a, (2, 2))
         assert_equal(test, m.reshape(2, 2))
 
+    def test_compress(self):
+        # Test compress function on ndarray and masked array
+        # Address Github #2495.
+        arr = np.arange(8)
+        arr.shape = 4,2
+        cond = np.array([True, False, True, True])
+        control = arr[[0, 2, 3]]
+        test = np.ma.compress(cond, arr, axis=0)
+        assert_equal(test, control)
+        marr = np.ma.array(arr)
+        test = np.ma.compress(cond, marr, axis=0)
+        assert_equal(test, control)
+
 #------------------------------------------------------------------------------
 
 class TestMaskedFields(TestCase):
@@ -3476,6 +3489,10 @@ def test_setitem(self):
         a[0]['a'] = 2
         assert_equal(a.mask, control)
 
+    def test_element_len(self):
+        # check that len() works for mvoid (Github issue #576)
+        for rec in self.data['base']:
+            assert_equal(len(rec), len(self.data['ddtype']))
 
 #------------------------------------------------------------------------------