Repository: numpy/numpy

Issue:
np.array([], dtype=object) triggers error when copied with copy.deepcopy()
The following code fails with numpy 1.12.0 (this is the only version we have tested).

~~~~
>>> arr = np.array([], dtype=object)
>>> copy.deepcopy(arr)
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/IPython/core/interactiveshell.py", line 2821, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-16-e314fe8a32a6>", line 1, in <module>
    copy.deepcopy(arr)
  File "/usr/lib/python3.4/copy.py", line 166, in deepcopy
    y = copier(memo)
ValueError: Iteration of zero-sized operands is not enabled
~~~~

Note that this code already works if the dtype was not object but, e.g., int or str.
np.ma.count and np.ma.copy on list input
The `np.ma.count` and `np.ma.copy` behave strangly if the input is a `list` or `tuple` (probably also other python builtins).

```
>>> np.ma.copy([1,2,3])  # unexpected behaviour
[1, 2, 3]

>>> np.copy([1,2,3])  # expected behaviour
array([1, 2, 3])

>>> np.ma.count([1,2,3])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Programming\Anaconda\envs\test\lib\site-packages\numpy\ma\core.py", line 6389, in __call__
    return method(*args, **params)
TypeError: count() takes exactly one argument (0 given)
```

The reason for this behaviour is that `list` **has** a `count` and `copy` method and `np.ma._frommethod` tries to call it instead of `np.ma.MaskedArray.count` (and copy).



Discussion:
The error is the new iterator missing the zerosize ok flag, a bit annoying really since you usually want it.... It is gh-8125.  CC @pelson in case you have time/want to fix it up.
Probably  a regression in 1.12.
@seberg Do you mean that we should implement a zerosize flag for `nditer`?
The flag already exists. Though since you have to test for an empty iterator afterwards then, could just as well test before the iterator here probably, since its a single array there is no complexity there.


Resolving patch:
diff --git a/numpy/core/numeric.py b/numpy/core/numeric.py
--- a/numpy/core/numeric.py
+++ b/numpy/core/numeric.py
@@ -2212,7 +2212,7 @@ def binary_repr(num, width=None):
         designated form.
 
         If the `width` value is insufficient, it will be ignored, and `num` will
-        be returned in binary(`num` > 0) or two's complement (`num` < 0) form
+        be returned in binary (`num` > 0) or two's complement (`num` < 0) form
         with its width equal to the minimum number of bits needed to represent
         the number in the designated form. This behavior is deprecated and will
         later raise an error.
@@ -2282,10 +2282,16 @@ def warn_if_insufficient(width, binwdith):
 
         else:
             poswidth = len(bin(-num)[2:])
-            twocomp = 2**(poswidth + 1) + num
 
+            # See gh-8679: remove extra digit
+            # for numbers at boundaries.
+            if 2**(poswidth - 1) == -num:
+                poswidth -= 1
+
+            twocomp = 2**(poswidth + 1) + num
             binary = bin(twocomp)[2:]
             binwidth = len(binary)
+
             outwidth = max(binwidth, width)
             warn_if_insufficient(width, binwidth)
             return '1' * (outwidth - binwidth) + binary
diff --git a/numpy/f2py/crackfortran.py b/numpy/f2py/crackfortran.py
--- a/numpy/f2py/crackfortran.py
+++ b/numpy/f2py/crackfortran.py
@@ -2392,7 +2392,8 @@ def _selected_real_kind_func(p, r=0, radix=0):
         return 4
     if p < 16:
         return 8
-    if platform.machine().lower().startswith('power'):
+    machine = platform.machine().lower()
+    if machine.startswith('power') or machine.startswith('ppc64'):
         if p <= 20:
             return 16
     else:
diff --git a/numpy/ma/core.py b/numpy/ma/core.py
--- a/numpy/ma/core.py
+++ b/numpy/ma/core.py
@@ -6384,21 +6384,16 @@ def getdoc(self):
     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)
+            a, args[0] = args[0], a
+
+        marr = asanyarray(a)
         method_name = self.__name__
-        method = getattr(a, method_name, None)
-        if method is not None:
-            return method(*args, **params)
-        # Still here ? Then a is not a MaskedArray
-        method = getattr(MaskedArray, method_name, None)
-        if method is not None:
-            return method(MaskedArray(a), *args, **params)
-        # Still here ? OK, let's call the corresponding np function
-        method = getattr(np, method_name)
-        return method(a, *args, **params)
+        method = getattr(type(marr), method_name, None)
+        if method is None:
+            # use the corresponding np function
+            method = getattr(np, method_name)
+
+        return method(marr, *args, **params)
 
 
 all = _frommethod('all')
@@ -6547,9 +6542,7 @@ def compressed(x):
         Equivalent method.
 
     """
-    if not isinstance(x, MaskedArray):
-        x = asanyarray(x)
-    return x.compressed()
+    return asanyarray(x).compressed()
 
 
 def concatenate(arrays, axis=0):
@@ -7695,6 +7688,10 @@ def asanyarray(a, dtype=None):
     <class 'numpy.ma.core.MaskedArray'>
 
     """
+    # workaround for #8666, to preserve identity. Ideally the bottom line
+    # would handle this for us.
+    if isinstance(a, MaskedArray) and (dtype is None or dtype == a.dtype):
+        return a
     return masked_array(a, dtype=dtype, copy=False, keep_mask=True, subok=True)
 
 


Test patch:
diff --git a/numpy/core/tests/test_numeric.py b/numpy/core/tests/test_numeric.py
--- a/numpy/core/tests/test_numeric.py
+++ b/numpy/core/tests/test_numeric.py
@@ -1149,6 +1149,18 @@ def test_sufficient_width(self):
         assert_equal(np.binary_repr(10, width=7), '0001010')
         assert_equal(np.binary_repr(-5, width=7), '1111011')
 
+    def test_neg_width_boundaries(self):
+        # see gh-8670
+
+        # Ensure that the example in the issue does not
+        # break before proceeding to a more thorough test.
+        assert_equal(np.binary_repr(-128, width=8), '10000000')
+
+        for width in range(1, 11):
+            num = -2**(width - 1)
+            exp = '1' + (width - 1) * '0'
+            assert_equal(np.binary_repr(num, width=width), exp)
+
 
 class TestBaseRepr(TestCase):
     def test_base3(self):
diff --git a/numpy/core/tests/test_regression.py b/numpy/core/tests/test_regression.py
--- a/numpy/core/tests/test_regression.py
+++ b/numpy/core/tests/test_regression.py
@@ -2094,6 +2094,13 @@ def test_deepcopy_F_order_object_array(self):
         # Check the references hold for the copied objects.
         self.assertTrue(arr_cp[0, 1] is arr_cp[1, 1])
 
+    def test_deepcopy_empty_object_array(self):
+        # Ticket #8536.
+        # Deepcopy should succeed
+        a = np.array([], dtype=object)
+        b = copy.deepcopy(a)
+        assert_(a.shape == b.shape)
+
     def test_bool_subscript_crash(self):
         # gh-4494
         c = np.rec.array([(1, 2, 3), (4, 5, 6)])
diff --git a/numpy/core/tests/test_umath.py b/numpy/core/tests/test_umath.py
--- a/numpy/core/tests/test_umath.py
+++ b/numpy/core/tests/test_umath.py
@@ -1379,6 +1379,19 @@ def __array_wrap__(self, arr, context):
         a = A()
         self.assertRaises(RuntimeError, ncu.maximum, a, a)
 
+    def test_none_wrap(self):
+        # Tests that issue #8507 is resolved. Previously, this would segfault
+
+        class A(object):
+            def __array__(self):
+                return np.zeros(1)
+
+            def __array_wrap__(self, arr, context=None):
+                return None
+
+        a = A()
+        assert_equal(ncu.maximum(a, a), None)
+
     def test_default_prepare(self):
 
         class with_wrap(object):
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
@@ -433,6 +433,11 @@ def test_copy(self):
         assert_not_equal(y._data.ctypes.data, x._data.ctypes.data)
         assert_not_equal(y._mask.ctypes.data, x._mask.ctypes.data)
 
+    def test_copy_on_python_builtins(self):
+        # Tests copy works on python builtins (issue#8019)
+        self.assertTrue(isMaskedArray(np.ma.copy([1,2,3])))
+        self.assertTrue(isMaskedArray(np.ma.copy((1,2,3))))
+
     def test_copy_immutable(self):
         # Tests that the copy method is immutable, GitHub issue #5247
         a = np.ma.array([1, 2, 3])
@@ -1032,6 +1037,11 @@ def test_count_func(self):
         assert_(res.dtype.type is np.intp)
         assert_raises(ValueError, ott.count, axis=1)
 
+    def test_count_on_python_builtins(self):
+        # Tests count works on python builtins (issue#8019)
+        assert_equal(3, count([1,2,3]))
+        assert_equal(2, count((1,2)))
+
     def test_minmax_func(self):
         # Tests minimum and maximum.
         (x, y, a10, m1, m2, xm, ym, z, zm, xf) = self.d