[pypy-commit] pypy remove-intlong-smm: merge default

pjenvey noreply at buildbot.pypy.org
Sat Oct 12 01:29:23 CEST 2013


Author: Philip Jenvey <pjenvey at underboss.org>
Branch: remove-intlong-smm
Changeset: r67332:3cbdd1b77142
Date: 2013-10-11 16:26 -0700
http://bitbucket.org/pypy/pypy/changeset/3cbdd1b77142/

Log:	merge default

diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -52,6 +52,9 @@
 .. branch: ndarray-subtype
 Allow subclassing ndarray, i.e. matrix
 
+.. branch: ndarray-sort
+Implement ndarray in-place sorting (for numeric types, no non-native byte order)
+
 .. branch: pypy-pyarray
 Implement much of numpy's c api in cpyext, allows (slow) access to ndarray
 from c
@@ -87,6 +90,8 @@
 .. branch: no-release-gil
 .. branch: safe-win-mmap
 .. branch: boolean-indexing-cleanup
+.. branch: cpyext-best_base
+.. branch: fileops2
 
 .. branch: nobold-backtrace
 Work on improving UnionError messages and stack trace displays.
@@ -103,3 +108,5 @@
 
 .. branch: file-support-in-rpython
 make open() and friends rpython
+
+
diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py
--- a/pypy/module/cpyext/test/test_cpyext.py
+++ b/pypy/module/cpyext/test/test_cpyext.py
@@ -99,7 +99,7 @@
 class LeakCheckingTest(object):
     """Base class for all cpyext tests."""
     spaceconfig = dict(usemodules=['cpyext', 'thread', '_rawffi', 'array',
-                                   'itertools', 'rctime', 'binascii'])
+                                   'itertools', 'rctime', 'binascii', 'micronumpy'])
     spaceconfig['std.withmethodcache'] = True
 
     enable_leak_checking = True
@@ -196,7 +196,7 @@
         assert PyUnicode_GetDefaultEncoding() == 'ascii'
 
 class AppTestCpythonExtensionBase(LeakCheckingTest):
-    
+
     def setup_class(cls):
         cls.space.getbuiltinmodule("cpyext")
         from pypy.module.imp.importing import importhook
diff --git a/pypy/module/cpyext/test/test_typeobject.py b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -156,7 +156,7 @@
             def __init__(self):
                 self.foobar = 32
                 super(UnicodeSubclass2, self).__init__()
-        
+
         newobj = UnicodeSubclass2()
         assert newobj.get_val() == 42
         assert newobj.foobar == 32
@@ -358,6 +358,13 @@
         assert w_obj is None
         assert api.PyErr_Occurred() is None
 
+    def test_ndarray_ref(self, space, api):
+        w_obj = space.appexec([], """():
+            import numpypy as np
+            return np.int64(2)""")
+        ref = make_ref(space, w_obj)
+        api.Py_DecRef(ref)
+
 class AppTestSlots(AppTestCpythonExtensionBase):
     def test_some_slots(self):
         module = self.import_extension('foo', [
@@ -525,7 +532,7 @@
         assert type(it) is type(iter([]))
         assert module.tp_iternext(it) == 1
         raises(StopIteration, module.tp_iternext, it)
-        
+
     def test_bool(self):
         module = self.import_extension('foo', [
             ("newInt", "METH_VARARGS",
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -4,7 +4,7 @@
 from rpython.rtyper.lltypesystem import rffi, lltype
 from rpython.rtyper.annlowlevel import llhelper
 from pypy.interpreter.baseobjspace import W_Root, DescrMismatch
-from pypy.objspace.std.typeobject import W_TypeObject
+from pypy.objspace.std.typeobject import W_TypeObject, find_best_base
 from pypy.interpreter.typedef import GetSetProperty
 from pypy.module.cpyext.api import (
     cpython_api, cpython_struct, bootstrap_function, Py_ssize_t, Py_ssize_tP,
@@ -574,33 +574,7 @@
 def best_base(space, bases_w):
     if not bases_w:
         return None
-
-    w_winner = None
-    w_base = None
-    for w_base_i in bases_w:
-        if isinstance(w_base_i, W_ClassObject):
-            # old-style base
-            continue
-        assert isinstance(w_base_i, W_TypeObject)
-        w_candidate = solid_base(space, w_base_i)
-        if not w_winner:
-            w_winner = w_candidate
-            w_base = w_base_i
-        elif space.abstract_issubclass_w(w_winner, w_candidate):
-            pass
-        elif space.abstract_issubclass_w(w_candidate, w_winner):
-            w_winner = w_candidate
-            w_base = w_base_i
-        else:
-            raise OperationError(
-                space.w_TypeError,
-                space.wrap("multiple bases have instance lay-out conflict"))
-    if w_base is None:
-        raise OperationError(
-            space.w_TypeError,
-                space.wrap("a new-style class can't have only classic bases"))
-
-    return w_base
+    return find_best_base(space, bases_w)
 
 def inherit_slots(space, pto, w_base):
     # XXX missing: nearly everything
diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py
--- a/pypy/module/micronumpy/arrayimpl/concrete.py
+++ b/pypy/module/micronumpy/arrayimpl/concrete.py
@@ -356,6 +356,10 @@
         from pypy.module.micronumpy.arrayimpl.sort import argsort_array
         return argsort_array(self, space, w_axis)
 
+    def sort(self, space, w_axis, w_order):
+        from pypy.module.micronumpy.arrayimpl.sort import sort_array
+        return sort_array(self, space, w_axis, w_order)
+
     def base(self):
         return None
 
diff --git a/pypy/module/micronumpy/arrayimpl/sort.py b/pypy/module/micronumpy/arrayimpl/sort.py
--- a/pypy/module/micronumpy/arrayimpl/sort.py
+++ b/pypy/module/micronumpy/arrayimpl/sort.py
@@ -17,7 +17,7 @@
 
 INT_SIZE = rffi.sizeof(lltype.Signed)
 
-def make_sort_function(space, itemtype, comp_type, count=1):
+def make_argsort_function(space, itemtype, comp_type, count=1):
     TP = itemtype.T
     step = rffi.sizeof(TP)
 
@@ -137,8 +137,8 @@
         else:
             shape = arr.get_shape()
             if axis < 0:
-                axis = len(shape) + axis - 1
-            if axis < 0 or axis > len(shape):
+                axis = len(shape) + axis
+            if axis < 0 or axis >= len(shape):
                 raise OperationError(space.w_IndexError, space.wrap(
                                                     "Wrong axis %d" % axis))
             iterable_shape = shape[:axis] + [0] + shape[axis + 1:]
@@ -162,7 +162,7 @@
     return argsort
 
 def argsort_array(arr, space, w_axis):
-    cache = space.fromcache(SortCache) # that populates SortClasses
+    cache = space.fromcache(ArgSortCache) # that populates ArgSortClasses
     itemtype = arr.dtype.itemtype
     for tp in all_types:
         if isinstance(itemtype, tp[0]):
@@ -178,6 +178,166 @@
 all_types = [i for i in all_types if not '_mixin_' in i[0].__dict__]
 all_types = unrolling_iterable(all_types)
 
+def make_sort_function(space, itemtype, comp_type, count=1):
+    TP = itemtype.T
+    step = rffi.sizeof(TP)
+
+    class Repr(object):
+        def __init__(self, stride_size, size, values, start):
+            self.stride_size = stride_size
+            self.start = start
+            self.size = size
+            self.values = values
+
+        def getitem(self, item):
+            if count < 2:
+                v = raw_storage_getitem(TP, self.values, item * self.stride_size
+                                    + self.start)
+            else:
+                v = []
+                for i in range(count):
+                    _v = raw_storage_getitem(TP, self.values, item * self.stride_size
+                                    + self.start + step * i)
+                    v.append(_v)
+            if comp_type == 'int':
+                v = intmask(v)
+            elif comp_type == 'float':
+                v = float(v)
+            elif comp_type == 'complex':
+                v = [float(v[0]),float(v[1])]
+            else:
+                raise NotImplementedError('cannot reach')
+            return (v)
+
+        def setitem(self, idx, item):
+            if count < 2:
+                raw_storage_setitem(self.values, idx * self.stride_size +
+                                self.start, rffi.cast(TP, item))
+            else:
+                i = 0
+                for val in item:
+                    raw_storage_setitem(self.values, idx * self.stride_size +
+                                self.start + i*step, rffi.cast(TP, val))
+                    i += 1
+
+    class ArgArrayRepWithStorage(Repr):
+        def __init__(self, stride_size, size):
+            start = 0
+            values = alloc_raw_storage(size * stride_size,
+                                            track_allocation=False)
+            Repr.__init__(self, stride_size,
+                          size, values, start)
+
+        def __del__(self):
+            free_raw_storage(self.values, track_allocation=False)
+
+    def arg_getitem(lst, item):
+        return lst.getitem(item)
+
+    def arg_setitem(lst, item, value):
+        lst.setitem(item, value)
+
+    def arg_length(lst):
+        return lst.size
+
+    def arg_getitem_slice(lst, start, stop):
+        retval = ArgArrayRepWithStorage(lst.stride_size, stop-start)
+        for i in range(stop-start):
+            retval.setitem(i, lst.getitem(i+start))
+        return retval
+
+    if count < 2:
+        def arg_lt(a, b):
+            # handles NAN and INF
+            return a < b or b != b and a == a
+    else:
+        def arg_lt(a, b):
+            for i in range(count):
+                if b[i] != b[i] and a[i] == a[i]:
+                    return True
+                elif b[i] == b[i] and a[i] != a[i]:
+                    return False
+            for i in range(count):
+                if a[i] < b[i]:
+                    return True
+                elif a[i] > b[i]:
+                    return False
+            # Does numpy do True?
+            return False
+
+    ArgSort = make_timsort_class(arg_getitem, arg_setitem, arg_length,
+                                 arg_getitem_slice, arg_lt)
+
+    def sort(arr, space, w_axis, itemsize):
+        if w_axis is space.w_None:
+            # note that it's fine to pass None here as we're not going
+            # to pass the result around (None is the link to base in slices)
+            arr = arr.reshape(space, None, [arr.get_size()])
+            axis = 0
+        elif w_axis is None:
+            axis = -1
+        else:
+            axis = space.int_w(w_axis)
+        # create array of indexes
+        if len(arr.get_shape()) == 1:
+            r = Repr(itemsize, arr.get_size(), arr.get_storage(),
+                     arr.start)
+            ArgSort(r).sort()
+        else:
+            shape = arr.get_shape()
+            if axis < 0:
+                axis = len(shape) + axis
+            if axis < 0 or axis >= len(shape):
+                raise OperationError(space.w_IndexError, space.wrap(
+                                                    "Wrong axis %d" % axis))
+            iterable_shape = shape[:axis] + [0] + shape[axis + 1:]
+            iter = AxisIterator(arr, iterable_shape, axis, False)
+            stride_size = arr.strides[axis]
+            axis_size = arr.shape[axis]
+            while not iter.done():
+                r = Repr(stride_size, axis_size, arr.get_storage(), iter.offset)
+                ArgSort(r).sort()
+                iter.next()
+
+    return sort
+
+def sort_array(arr, space, w_axis, w_order):
+    cache = space.fromcache(SortCache) # that populates SortClasses
+    itemtype = arr.dtype.itemtype
+    if not arr.dtype.native:
+        raise OperationError(space.w_NotImplementedError,
+           space.wrap("sorting of non-native btyeorder not supported yet"))
+    for tp in all_types:
+        if isinstance(itemtype, tp[0]):
+            return cache._lookup(tp)(arr, space, w_axis,
+                                     itemtype.get_element_size())
+    # XXX this should probably be changed
+    raise OperationError(space.w_NotImplementedError,
+           space.wrap("sorting of non-numeric types " + \
+                  "'%s' is not implemented" % arr.dtype.get_name(), ))
+
+all_types = (types.all_float_types + types.all_complex_types +
+             types.all_int_types)
+all_types = [i for i in all_types if not '_mixin_' in i[0].__dict__]
+all_types = unrolling_iterable(all_types)
+
+class ArgSortCache(object):
+    built = False
+
+    def __init__(self, space):
+        if self.built:
+            return
+        self.built = True
+        cache = {}
+        for cls, it in all_types._items:
+            if it == 'complex':
+                cache[cls] = make_argsort_function(space, cls, it, 2)
+            else:
+                cache[cls] = make_argsort_function(space, cls, it)
+        self.cache = cache
+        self._lookup = specialize.memo()(lambda tp : cache[tp[0]])
+
+
 class SortCache(object):
     built = False
 
diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py
--- a/pypy/module/micronumpy/interp_numarray.py
+++ b/pypy/module/micronumpy/interp_numarray.py
@@ -629,9 +629,13 @@
         raise OperationError(space.w_NotImplementedError, space.wrap(
             "setflags not implemented yet"))
 
-    def descr_sort(self, space, w_axis=-1, w_kind='quicksort', w_order=None):
-        raise OperationError(space.w_NotImplementedError, space.wrap(
-            "sort not implemented yet"))
+    @unwrap_spec(kind=str)
+    def descr_sort(self, space, w_axis=None, kind='quicksort', w_order=None):
+        # happily ignore the kind
+        # modify the array in-place
+        if self.is_scalar():
+            return
+        return self.implementation.sort(space, w_axis, w_order)
 
     def descr_squeeze(self, space):
         raise OperationError(space.w_NotImplementedError, space.wrap(
@@ -1118,6 +1122,7 @@
     conj = interp2app(W_NDimArray.descr_conj),
 
     argsort  = interp2app(W_NDimArray.descr_argsort),
+    sort  = interp2app(W_NDimArray.descr_sort),
     astype   = interp2app(W_NDimArray.descr_astype),
     base     = GetSetProperty(W_NDimArray.descr_get_base),
     byteswap = interp2app(W_NDimArray.descr_byteswap),
diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py
--- a/pypy/module/micronumpy/test/test_numarray.py
+++ b/pypy/module/micronumpy/test/test_numarray.py
@@ -2652,55 +2652,6 @@
         assert array([1, 2, 3], '>i2')[::2].tostring() == '\x00\x01\x00\x03'
         assert array(0, dtype='i2').tostring() == '\x00\x00'
 
-    def test_argsort_dtypes(self):
-        from numpypy import array, arange
-        assert array(2.0).argsort() == 0
-        nnp = self.non_native_prefix
-        for dtype in ['int', 'float', 'int16', 'float32', 'uint64',
-                        nnp + 'i2', complex]:
-            a = array([6, 4, -1, 3, 8, 3, 256+20, 100, 101], dtype=dtype)
-            c = a.copy()
-            res = a.argsort()
-            assert (res == [2, 3, 5, 1, 0, 4, 7, 8, 6]).all(), \
-                'a,res,dtype %r,%r,%r' % (a,res,dtype)
-            assert (a == c).all() # not modified
-            a = arange(100)
-            assert (a.argsort() == a).all()
-        raises(NotImplementedError, 'arange(10,dtype="float16").argsort()')
-
-    def test_argsort_nd(self):
-        from numpypy import array
-        a = array([[4, 2], [1, 3]])
-        assert (a.argsort() == [[1, 0], [0, 1]]).all()
-        a = array(range(10) + range(10) + range(10))
-        b = a.argsort()
-        assert (b[:3] == [0, 10, 20]).all()
-        #trigger timsort 'run' mode which calls arg_getitem_slice
-        a = array(range(100) + range(100) + range(100))
-        b = a.argsort()
-        assert (b[:3] == [0, 100, 200]).all()
-        a = array([[[]]]).reshape(3,4,0)
-        b = a.argsort()
-        assert b.size == 0
-
-    def test_argsort_random(self):
-        from numpypy import array
-        from _random import Random
-        rnd = Random(1)
-        a = array([rnd.random() for i in range(512*2)]).reshape(512,2)
-        a.argsort()
-
-    def test_argsort_axis(self):
-        from numpypy import array
-        a = array([[4, 2], [1, 3]])
-        assert (a.argsort(axis=None) == [2, 1, 3, 0]).all()
-        assert (a.argsort(axis=-1) == [[1, 0], [0, 1]]).all()
-        assert (a.argsort(axis=0) == [[1, 0], [0, 1]]).all()
-        assert (a.argsort(axis=1) == [[1, 0], [0, 1]]).all()
-        a = array([[3, 2, 1], [1, 2, 3]])
-        assert (a.argsort(axis=0) == [[1, 0, 0], [0, 1, 1]]).all()
-        assert (a.argsort(axis=1) == [[2, 1, 0], [0, 1, 2]]).all()
-
 
 class AppTestRanges(BaseNumpyAppTest):
     def test_arange(self):
diff --git a/pypy/module/micronumpy/test/test_sorting.py b/pypy/module/micronumpy/test/test_sorting.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/test/test_sorting.py
@@ -0,0 +1,322 @@
+from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest
+
+class AppTestSupport(BaseNumpyAppTest):
+    def setup_class(cls):
+        import struct
+        BaseNumpyAppTest.setup_class.im_func(cls)
+        cls.w_data = cls.space.wrap(struct.pack('dddd', 1, 2, 3, 4))
+        cls.w_fdata = cls.space.wrap(struct.pack('f', 2.3))
+        cls.w_float16val = cls.space.wrap('\x00E') # 5.0 in float16
+        cls.w_float32val = cls.space.wrap(struct.pack('f', 5.2))
+        cls.w_float64val = cls.space.wrap(struct.pack('d', 300.4))
+        cls.w_ulongval = cls.space.wrap(struct.pack('L', 12))
+
+    def test_argsort_dtypes(self):
+        from numpypy import array, arange
+        assert array(2.0).argsort() == 0
+        nnp = self.non_native_prefix
+        for dtype in ['int', 'float', 'int16', 'float32', 'uint64',
+                        nnp + 'i2', complex]:
+            a = array([6, 4, -1, 3, 8, 3, 256+20, 100, 101], dtype=dtype)
+            c = a.copy()
+            res = a.argsort()
+            assert (res == [2, 3, 5, 1, 0, 4, 7, 8, 6]).all(), \
+                'a,res,dtype %r,%r,%r' % (a,res,dtype)
+            assert (a == c).all() # not modified
+            a = arange(100)
+            assert (a.argsort() == a).all()
+        raises(NotImplementedError, 'arange(10,dtype="float16").argsort()')
+
+    def test_argsort_nd(self):
+        from numpypy import array
+        a = array([[4, 2], [1, 3]])
+        assert (a.argsort() == [[1, 0], [0, 1]]).all()
+        a = array(range(10) + range(10) + range(10))
+        b = a.argsort()
+        assert (b[:3] == [0, 10, 20]).all()
+        #trigger timsort 'run' mode which calls arg_getitem_slice
+        a = array(range(100) + range(100) + range(100))
+        b = a.argsort()
+        assert (b[:3] == [0, 100, 200]).all()
+        a = array([[[]]]).reshape(3,4,0)
+        b = a.argsort()
+        assert b.size == 0
+
+    def test_argsort_random(self):
+        from numpypy import array
+        from _random import Random
+        rnd = Random(1)
+        a = array([rnd.random() for i in range(512*2)]).reshape(512,2)
+        a.argsort()
+
+    def test_argsort_axis(self):
+        from numpypy import array
+        a = array([[4, 2], [1, 3]])
+        assert (a.argsort(axis=None) == [2, 1, 3, 0]).all()
+        assert (a.argsort(axis=-1) == [[1, 0], [0, 1]]).all()
+        assert (a.argsort(axis=0) == [[1, 0], [0, 1]]).all()
+        assert (a.argsort(axis=1) == [[1, 0], [0, 1]]).all()
+        a = array([[3, 2, 1], [1, 2, 3]])
+        assert (a.argsort(axis=0) == [[1, 0, 0], [0, 1, 1]]).all()
+        assert (a.argsort(axis=1) == [[2, 1, 0], [0, 1, 2]]).all()
+
+    def test_sort_dtypes(self):
+        from numpypy import array, arange
+        for dtype in ['int', 'float', 'int16', 'float32', 'uint64',
+                        'i2', complex]:
+            a = array([6, 4, -1, 3, 8, 3, 256+20, 100, 101], dtype=dtype)
+            b = array([-1, 3, 3, 4, 6, 8, 100, 101, 256+20], dtype=dtype)
+            c = a.copy()
+            a.sort()
+            assert (a == b).all(), \
+                'a,orig,dtype %r,%r,%r' % (a,c,dtype)
+        a = arange(100)
+        c = a.copy()
+        a.sort()
+        assert (a == c).all()
+
+    def test_sort_dtypesi_nonnative(self):
+        from numpypy import array
+        nnp = self.non_native_prefix
+        for dtype in [ nnp + 'i2']:
+            a = array([6, 4, -1, 3, 8, 3, 256+20, 100, 101], dtype=dtype)
+            b = array([-1, 3, 3, 4, 6, 8, 100, 101, 256+20], dtype=dtype)
+            c = a.copy()
+            exc = raises(NotImplementedError, a.sort)
+            assert exc.value[0].find('supported') >= 0
+            #assert (a == b).all(), \
+            #    'a,orig,dtype %r,%r,%r' % (a,c,dtype)
+
+
+# tests from numpy/tests/test_multiarray.py
+    def test_sort_corner_cases(self):
+        # test ordering for floats and complex containing nans. It is only
+        # necessary to check the lessthan comparison, so sorts that
+        # only follow the insertion sort path are sufficient. We only
+        # test doubles and complex doubles as the logic is the same.
+
+        # check doubles
+        from numpypy import array, nan, zeros, complex128, arange
+        from numpy import isnan
+        a = array([nan, 1, 0])
+        b = a.copy()
+        b.sort()
+        assert (isnan(b) == isnan(a[::-1])).all()
+        assert (b[:2] == a[::-1][:2]).all()
+
+        # check complex
+        a = zeros(9, dtype=complex128)
+        a.real += [nan, nan, nan, 1, 0, 1, 1, 0, 0]
+        a.imag += [nan, 1, 0, nan, nan, 1, 0, 1, 0]
+        b = a.copy()
+        b.sort()
+        assert (isnan(b) == isnan(a[::-1])).all()
+        assert (b[:4] == a[::-1][:4]).all()
+
+        # all c scalar sorts use the same code with different types
+        # so it suffices to run a quick check with one type. The number
+        # of sorted items must be greater than ~50 to check the actual
+        # algorithm because quick and merge sort fall over to insertion
+        # sort for small arrays.
+        a = arange(101)
+        b = a[::-1].copy()
+        for kind in ['q', 'm', 'h'] :
+            msg = "scalar sort, kind=%s" % kind
+            c = a.copy();
+            c.sort(kind=kind)
+            assert (c == a).all(), msg
+            c = b.copy();
+            c.sort(kind=kind)
+            assert (c == a).all(), msg
+
+        # test complex sorts. These use the same code as the scalars
+        # but the compare fuction differs.
+        ai = a*1j + 1
+        bi = b*1j + 1
+        for kind in ['q', 'm', 'h'] :
+            msg = "complex sort, real part == 1, kind=%s" % kind
+            c = ai.copy();
+            c.sort(kind=kind)
+            assert (c == ai).all(), msg
+            c = bi.copy();
+            c.sort(kind=kind)
+            assert (c == ai).all(), msg
+        ai = a + 1j
+        bi = b + 1j
+        for kind in ['q', 'm', 'h'] :
+            msg = "complex sort, imag part == 1, kind=%s" % kind
+            c = ai.copy();
+            c.sort(kind=kind)
+            assert (c == ai).all(), msg
+            c = bi.copy();
+            c.sort(kind=kind)
+            assert (c == ai).all(), msg
+
+        # check axis handling. This should be the same for all type
+        # specific sorts, so we only check it for one type and one kind
+        a = array([[3, 2], [1, 0]])
+        b = array([[1, 0], [3, 2]])
+        c = array([[2, 3], [0, 1]])
+        d = a.copy()
+        d.sort(axis=0)
+        assert (d == b).all(), "test sort with axis=0"
+        d = a.copy()
+        d.sort(axis=1)
+        assert (d == c).all(), "test sort with axis=1"
+        d = a.copy()
+        d.sort()
+        assert (d == c).all(), "test sort with default axis"
+
+    def test_sort_corner_cases_string_records(self):
+        skip('not implemented yet')
+        from numpypy import array, dtype
+        # test string sorts.
+        s = 'aaaaaaaa'
+        a = array([s + chr(i) for i in range(101)])
+        b = a[::-1].copy()
+        for kind in ['q', 'm', 'h'] :
+            msg = "string sort, kind=%s" % kind
+            c = a.copy();
+            c.sort(kind=kind)
+            assert (c == a).all(), msg
+            c = b.copy();
+            c.sort(kind=kind)
+            assert (c == a).all(), msg
+
+
+        # test record array sorts.
+        dt =dtype([('f', float), ('i', int)])
+        a = array([(i, i) for i in range(101)], dtype = dt)
+        b = a[::-1]
+        for kind in ['q', 'h', 'm'] :
+            msg = "object sort, kind=%s" % kind
+            c = a.copy();
+            c.sort(kind=kind)
+            assert (c == a).all(), msg
+            c = b.copy();
+            c.sort(kind=kind)
+            assert (c == a).all(), msg
+
+    def test_sort_unicode(self):
+        from numpypy import array
+        # test unicode sorts.
+        s = 'aaaaaaaa'
+        try:
+            a = array([s + chr(i) for i in range(101)], dtype=unicode)
+            b = a[::-1].copy()
+        except:
+            skip('unicode type not supported yet')
+        for kind in ['q', 'm', 'h'] :
+            msg = "unicode sort, kind=%s" % kind
+            c = a.copy();
+            c.sort(kind=kind)
+            assert (c == a).all(), msg
+            c = b.copy();
+            c.sort(kind=kind)
+            assert (c == a).all(), msg
+
+    def test_sort_objects(self):
+        # test object array sorts.
+        from numpypy import empty
+        try:
+            a = empty((101,), dtype=object)
+        except:
+            skip('object type not supported yet')
+        a[:] = list(range(101))
+        b = a[::-1]
+        for kind in ['q', 'h', 'm'] :
+            msg = "object sort, kind=%s" % kind
+            c = a.copy();
+            c.sort(kind=kind)
+            assert (c == a).all(), msg
+            c = b.copy();
+            c.sort(kind=kind)
+            assert (c == a).all(), msg
+
+    def test_sort_datetime(self):
+        from numpypy import arange
+        # test datetime64 sorts.
+        try:
+            a = arange(0, 101, dtype='datetime64[D]')
+        except:
+            skip('datetime type not supported yet')
+        b = a[::-1]
+        for kind in ['q', 'h', 'm'] :
+            msg = "datetime64 sort, kind=%s" % kind
+            c = a.copy();
+            c.sort(kind=kind)
+            assert (c == a).all(), msg
+            c = b.copy();
+            c.sort(kind=kind)
+            assert (c == a).all(), msg
+
+        # test timedelta64 sorts.
+        a = arange(0, 101, dtype='timedelta64[D]')
+        b = a[::-1]
+        for kind in ['q', 'h', 'm'] :
+            msg = "timedelta64 sort, kind=%s" % kind
+            c = a.copy();
+            c.sort(kind=kind)
+            assert (c == a).all(), msg
+            c = b.copy();
+            c.sort(kind=kind)
+            assert (c == a).all(), msg
+
+    def test_sort_order(self):
+        from numpypy import array, zeros
+        from sys import byteorder
+        # Test sorting an array with fields
+        skip('not implemented yet')
+        x1 = array([21, 32, 14])
+        x2 = array(['my', 'first', 'name'])
+        x3=array([3.1, 4.5, 6.2])
+        r=zeros(3, dtype=[('id','i'),('word','S5'),('number','f')])
+        r['id'] = x1
+        r['word'] = x2
+        r['number'] = x3
+
+        r.sort(order=['id'])
+        assert (r['id'] == [14, 21, 32]).all()
+        assert (r['word'] == ['name', 'my', 'first']).all()
+        assert max(abs(r['number'] - [6.2, 3.1, 4.5])) < 1e-6
+
+        r.sort(order=['word'])
+        assert (r['id'] == [32, 21, 14]).all()
+        assert (r['word'] == ['first', 'my', 'name']).all()
+        assert max(abs(r['number'] - [4.5, 3.1, 6.2])) < 1e-6
+
+        r.sort(order=['number'])
+        assert (r['id'] == [21, 32, 14]).all()
+        assert (r['word'] == ['my', 'first', 'name']).all()
+        assert max(abs(r['number'] - [3.1, 4.5, 6.2])) < 1e-6
+
+        if byteorder == 'little':
+            strtype = '>i2'
+        else:
+            strtype = '<i2'
+        mydtype = [('name', 'S5'), ('col2', strtype)]
+        r = array([('a', 1), ('b', 255), ('c', 3), ('d', 258)],
+                     dtype= mydtype)
+        r.sort(order='col2')
+        assert (r['col2'] == [1, 3, 255, 258]).all()
+        assert (r == array([('a', 1), ('c', 3), ('b', 255), ('d', 258)],
+                                 dtype=mydtype)).all()
+
+
+# tests from numpy/tests/test_regression.py
+    def test_sort_bigendian(self):
+        skip('not implemented yet')
+        from numpypy import array, dtype
+        a = array(range(11),dtype='float64')
+        c = a.astype(dtype('<f8'))
+        c.sort()
+        assert max(abs(a-c)) < 1e-32
+
+    def test_string_sort_with_zeros(self):
+        skip('not implemented yet')
+        from numpypy import fromstring
+        """Check sort for strings containing zeros."""
+        x = fromstring("\x00\x02\x00\x01", dtype="S2")
+        y = fromstring("\x00\x01\x00\x02", dtype="S2")
+        x.sort(kind='q')
+        assert (x == y).all()
diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py
--- a/pypy/module/micronumpy/types.py
+++ b/pypy/module/micronumpy/types.py
@@ -1864,7 +1864,6 @@
         return interp_boxes.W_StringBox(arr,  0, arr.dtype)
 
     def fill(self, storage, width, box, start, stop, offset):
-        from pypy.module.micronumpy.arrayimpl.concrete import ConcreteArrayNotOwning
         for i in xrange(start, stop, width):
             self._store(storage, i, offset, box)
 
@@ -1873,6 +1872,13 @@
 class UnicodeType(BaseType, BaseStringType):
     T = lltype.UniChar
 
+    @jit.unroll_safe
+    def coerce(self, space, dtype, w_item):
+        if isinstance(w_item, interp_boxes.W_UnicodeBox):
+            return w_item
+        raise OperationError(space.w_NotImplementedError, space.wrap(
+            "coerce (probably from set_item) not implemented for unicode type"))
+
 NonNativeUnicodeType = UnicodeType
 
 class VoidType(BaseType, BaseStringType):
diff --git a/rpython/memory/gc/minimark.py b/rpython/memory/gc/minimark.py
--- a/rpython/memory/gc/minimark.py
+++ b/rpython/memory/gc/minimark.py
@@ -1201,7 +1201,6 @@
         # ^^^ a fast path of write-barrier
         #
         if source_hdr.tid & GCFLAG_HAS_CARDS != 0:
-            assert self.card_page_indices > 0
             #
             if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0:
                 # The source object may have random young pointers.
@@ -1236,6 +1235,7 @@
 
     def manually_copy_card_bits(self, source_addr, dest_addr, length):
         # manually copy the individual card marks from source to dest
+        assert self.card_page_indices > 0
         bytes = self.card_marking_bytes_for_length(length)
         #
         anybyte = 0
diff --git a/rpython/rlib/rdtoa.py b/rpython/rlib/rdtoa.py
--- a/rpython/rlib/rdtoa.py
+++ b/rpython/rlib/rdtoa.py
@@ -217,13 +217,13 @@
 
         if exp >= 0:
             exp_str = str(exp)
-            if len(exp_str) < 2:
+            if len(exp_str) < 2 and not (flags & rfloat.DTSF_CUT_EXP_0):
                 s += e + '+0' + exp_str
             else:
                 s += e + '+' + exp_str
         else:
             exp_str = str(-exp)
-            if len(exp_str) < 2:
+            if len(exp_str) < 2 and not (flags & rfloat.DTSF_CUT_EXP_0):
                 s += e + '-0' + exp_str
             else:
                 s += e + '-' + exp_str
diff --git a/rpython/rlib/rfloat.py b/rpython/rlib/rfloat.py
--- a/rpython/rlib/rfloat.py
+++ b/rpython/rlib/rfloat.py
@@ -69,6 +69,7 @@
 DTSF_SIGN      = 0x1
 DTSF_ADD_DOT_0 = 0x2
 DTSF_ALT       = 0x4
+DTSF_CUT_EXP_0 = 0x8
 
 DIST_FINITE   = 1
 DIST_NAN      = 2
diff --git a/rpython/rlib/test/test_rdtoa.py b/rpython/rlib/test/test_rdtoa.py
--- a/rpython/rlib/test/test_rdtoa.py
+++ b/rpython/rlib/test/test_rdtoa.py
@@ -29,3 +29,7 @@
 def test_dtoa_precision():
     assert dtoa(1.1, code='f', precision=2) == "1.10"
     assert dtoa(1e12, code='g', precision=12) == "1e+12"
+
+def test_flag_cut_exp_0():
+    assert dtoa(1.1e9, code="g", precision=2, flags=rfloat.DTSF_CUT_EXP_0) == "1.1e+9"
+    assert dtoa(1.1e-9, code="g", precision=2, flags=rfloat.DTSF_CUT_EXP_0) == "1.1e-9"
diff --git a/rpython/rtyper/lltypesystem/rdict.py b/rpython/rtyper/lltypesystem/rdict.py
--- a/rpython/rtyper/lltypesystem/rdict.py
+++ b/rpython/rtyper/lltypesystem/rdict.py
@@ -820,8 +820,9 @@
             entry = entries[i]
             hash = entries.hash(i)
             key = entry.key
+            value = entry.value
             j = ll_dict_lookup(dic1, key, hash)
-            _ll_dict_setitem_lookup_done(dic1, key, entry.value, hash, j)
+            _ll_dict_setitem_lookup_done(dic1, key, value, hash, j)
         i += 1
 ll_update.oopspec = 'dict.update(dic1, dic2)'
 
diff --git a/rpython/rtyper/lltypesystem/rstr.py b/rpython/rtyper/lltypesystem/rstr.py
--- a/rpython/rtyper/lltypesystem/rstr.py
+++ b/rpython/rtyper/lltypesystem/rstr.py
@@ -577,9 +577,7 @@
             return -1
 
         m = len(s2.chars)
-        if m == 0:
-            return start
-        elif m == 1:
+        if m == 1:
             return cls.ll_find_char(s1, s2.chars[0], start, end)
 
         return cls.ll_search(s1, s2, start, end, FAST_FIND)
@@ -594,9 +592,7 @@
             return -1
 
         m = len(s2.chars)
-        if m == 0:
-            return end
-        elif m == 1:
+        if m == 1:
             return cls.ll_rfind_char(s1, s2.chars[0], start, end)
 
         return cls.ll_search(s1, s2, start, end, FAST_RFIND)
@@ -611,9 +607,7 @@
             return 0
 
         m = len(s2.chars)
-        if m == 0:
-            return end - start + 1
-        elif m == 1:
+        if m == 1:
             return cls.ll_count_char(s1, s2.chars[0], start, end)
 
         res = cls.ll_search(s1, s2, start, end, FAST_COUNT)
@@ -629,6 +623,14 @@
         n = end - start
         m = len(s2.chars)
 
+        if m == 0:
+            if mode == FAST_COUNT:
+                return end - start + 1
+            elif mode == FAST_RFIND:
+                return end
+            else:
+                return start
+
         w = n - m
 
         if w < 0:
diff --git a/rpython/rtyper/test/test_rstr.py b/rpython/rtyper/test/test_rstr.py
--- a/rpython/rtyper/test/test_rstr.py
+++ b/rpython/rtyper/test/test_rstr.py
@@ -3,6 +3,7 @@
 import py
 
 from rpython.flowspace.model import summary
+from rpython.annotator.model import AnnotatorError
 from rpython.rtyper.lltypesystem.lltype import typeOf, Signed, malloc
 from rpython.rtyper.lltypesystem.rstr import LLHelpers, STR
 from rpython.rtyper.rstr import AbstractLLHelpers
@@ -361,16 +362,16 @@
             res = self.interpret(fn, [i, j])
             assert res == fn(i, j)
 
-    def test_find_TyperError(self):
+    def test_find_AnnotatorError(self):
         const = self.const
         def f():
             s = const('abc')
             s.find(s, 0, -10)
-        py.test.raises(TyperError, self.interpret, f, ())
+        py.test.raises(AnnotatorError, self.interpret, f, ())
         def f():
             s = const('abc')
             s.find(s, -10)
-        py.test.raises(TyperError, self.interpret, f, ())
+        py.test.raises(AnnotatorError, self.interpret, f, ())
 
     def test_find_empty_string(self):
         const = self.const
@@ -420,9 +421,8 @@
         const = self.const
         def f(i):
             return const("abc").rfind(const(''), i)
-        e = py.test.raises(TyperError, self.interpret, f, [-5])
-        assert str(e.value).startswith(
-            'str.rfind() start must be proven non-negative')
+        e = py.test.raises(AnnotatorError, self.interpret, f, [-5])
+        assert "rfind: not proven to have non-negative start" in str(e.value)
 
     def test_find_char(self):
         const = self.const
@@ -900,16 +900,16 @@
         res = self.interpret(fn, [])
         assert res == 1
 
-    def test_count_TyperError(self):
+    def test_count_AnnotatorError(self):
         const = self.const
         def f():
             s = const('abc')
             s.count(s, 0, -10)
-        py.test.raises(TyperError, self.interpret, f, ())
+        py.test.raises(AnnotatorError, self.interpret, f, ())
         def f():
             s = const('abc')
             s.count(s, -10)
-        py.test.raises(TyperError, self.interpret, f, ())
+        py.test.raises(AnnotatorError, self.interpret, f, ())
 
     def test_getitem_exc(self):
         const = self.const


More information about the pypy-commit mailing list