[pypy-commit] pypy numpypy-nditer: merge numpypy-ellipse-indexing into branch

mattip noreply at buildbot.pypy.org
Tue May 14 13:16:39 CEST 2013


Author: Matti Picus <matti.picus at gmail.com>
Branch: numpypy-nditer
Changeset: r64065:bda069a8a5ea
Date: 2013-05-14 11:27 +0300
http://bitbucket.org/pypy/pypy/changeset/bda069a8a5ea/

Log:	merge numpypy-ellipse-indexing into branch

diff too long, truncating to 2000 out of 3525 lines

diff --git a/lib-python/2.7/distutils/sysconfig_pypy.py b/lib-python/2.7/distutils/sysconfig_pypy.py
--- a/lib-python/2.7/distutils/sysconfig_pypy.py
+++ b/lib-python/2.7/distutils/sysconfig_pypy.py
@@ -119,13 +119,13 @@
     optional C speedup components.
     """
     if compiler.compiler_type == "unix":
-        compiler.compiler_so.extend(['-fPIC', '-Wimplicit'])
+        compiler.compiler_so.extend(['-O2', '-fPIC', '-Wimplicit'])
         compiler.shared_lib_extension = get_config_var('SO')
         if "CFLAGS" in os.environ:
-            cflags = os.environ["CFLAGS"]
-            compiler.compiler.append(cflags)
-            compiler.compiler_so.append(cflags)
-            compiler.linker_so.append(cflags)
+            cflags = os.environ["CFLAGS"].split()
+            compiler.compiler.extend(cflags)
+            compiler.compiler_so.extend(cflags)
+            compiler.linker_so.extend(cflags)
 
 
 from sysconfig_cpython import (
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
@@ -5,3 +5,5 @@
 .. this is a revision shortly after release-2.0
 .. startrev: a13c07067613
 
+.. branch: numpy-pickle
+Pickling of numpy arrays and dtypes (including record dtypes)
diff --git a/pypy/goal/getnightly.py b/pypy/goal/getnightly.py
--- a/pypy/goal/getnightly.py
+++ b/pypy/goal/getnightly.py
@@ -8,7 +8,9 @@
     arch = 'linux'
     cmd = 'wget "%s"'
     tar = "tar -x -v --wildcards --strip-components=2 -f %s '*/bin/pypy'"
-if sys.platform.startswith('darwin'):
+    if os.uname()[-1].startswith('arm'):
+        arch += '-armhf-raspbian'
+elif sys.platform.startswith('darwin'):
     arch = 'osx'
     cmd = 'curl -O "%s"'
     tar = "tar -x -v --strip-components=2 -f %s '*/bin/pypy'"
diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py
--- a/pypy/goal/targetpypystandalone.py
+++ b/pypy/goal/targetpypystandalone.py
@@ -2,6 +2,7 @@
 
 import os, sys
 
+import pypy
 from pypy.interpreter import gateway
 from pypy.interpreter.error import OperationError
 from pypy.tool.ann_override import PyPyAnnotatorPolicy
@@ -78,7 +79,41 @@
     # should be used as sparsely as possible, just to register callbacks
 
     from rpython.rlib.entrypoint import entrypoint
-    from rpython.rtyper.lltypesystem import rffi
+    from rpython.rtyper.lltypesystem import rffi, lltype
+
+    w_pathsetter = space.appexec([], """():
+    def f(path):
+        import sys
+        sys.path[:] = path
+    return f
+    """)
+
+    @entrypoint('main', [rffi.CCHARP, lltype.Signed], c_name='pypy_setup_home')
+    def pypy_setup_home(ll_home, verbose):
+        from pypy.module.sys.initpath import pypy_find_stdlib
+        if ll_home:
+            home = rffi.charp2str(ll_home)
+        else:
+            home = pypydir
+        w_path = pypy_find_stdlib(space, home)
+        if space.is_none(w_path):
+            if verbose:
+                debug("Failed to find library based on pypy_find_stdlib")
+            return 1
+        space.startup()
+        space.call_function(w_pathsetter, w_path)
+        # import site
+        try:
+            import_ = space.getattr(space.getbuiltinmodule('__builtin__'),
+                                    space.wrap('__import__'))
+            space.call_function(import_, space.wrap('site'))
+            return 0
+        except OperationError, e:
+            if verbose:
+                debug("OperationError:")
+                debug(" operror-type: " + e.w_type.getname(space))
+                debug(" operror-value: " + space.str_w(space.str(e.get_w_value(space))))
+            return 1
 
     @entrypoint('main', [rffi.CCHARP], c_name='pypy_execute_source')
     def pypy_execute_source(ll_source):
@@ -101,7 +136,8 @@
             return 1
         return 0
 
-    return entry_point, _pypy_execute_source # for tests
+    return entry_point, {'pypy_execute_source': pypy_execute_source,
+                         'pypy_setup_home': pypy_setup_home}
 
 def call_finish(space):
     space.finish()
diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py
--- a/pypy/interpreter/gateway.py
+++ b/pypy/interpreter/gateway.py
@@ -803,7 +803,6 @@
     args = inspect.getargs(func.func_code)
     if args.varargs or args.keywords:
         raise TypeError("Varargs and keywords not supported in unwrap_spec")
-    assert not func.func_defaults
     argspec = ', '.join([arg for arg in args.args[1:]])
     func_code = py.code.Source("""
     def f(w_obj, %(args)s):
@@ -812,11 +811,13 @@
     d = {}
     exec func_code.compile() in d
     f = d['f']
+    f.func_defaults = unbound_meth.func_defaults
+    f.func_doc = unbound_meth.func_doc
     f.__module__ = func.__module__
     # necessary for unique identifiers for pickling
     f.func_name = func.func_name
     if unwrap_spec is None:
-        unwrap_spec = {}
+        unwrap_spec = getattr(unbound_meth, 'unwrap_spec', {})
     else:
         assert isinstance(unwrap_spec, dict)
         unwrap_spec = unwrap_spec.copy()
diff --git a/pypy/interpreter/mixedmodule.py b/pypy/interpreter/mixedmodule.py
--- a/pypy/interpreter/mixedmodule.py
+++ b/pypy/interpreter/mixedmodule.py
@@ -13,6 +13,7 @@
     # imported yet, and when it has been, it is mod.__dict__.items() just
     # after startup().
     w_initialdict = None
+    lazy = False
 
     def __init__(self, space, w_name):
         """ NOT_RPYTHON """
diff --git a/pypy/interpreter/special.py b/pypy/interpreter/special.py
--- a/pypy/interpreter/special.py
+++ b/pypy/interpreter/special.py
@@ -5,13 +5,13 @@
     def __init__(self, space):
         self.space = space
 
-    def descr__repr__(self):
-        return self.space.wrap('Ellipsis')
+    def descr__repr__(self, space):
+        return space.wrap('Ellipsis')
 
 
 class NotImplemented(W_Root):
     def __init__(self, space):
         self.space = space
 
-    def descr__repr__(self):
-        return self.space.wrap('NotImplemented')
+    def descr__repr__(self, space):
+        return space.wrap('NotImplemented')
diff --git a/pypy/interpreter/test/test_app_main.py b/pypy/interpreter/test/test_app_main.py
--- a/pypy/interpreter/test/test_app_main.py
+++ b/pypy/interpreter/test/test_app_main.py
@@ -461,7 +461,7 @@
         p = os.path.abspath(p)
         monkeypatch.chdir(os.path.dirname(app_main))
         child = self.spawn(['-i',
-                            '-m', 'test2.mymodule',
+                            '-m', 'test.mymodule',
                             'extra'])
         child.expect('mymodule running')
         child.expect('Name: __main__')
@@ -472,9 +472,9 @@
         child.expect(re.escape(repr("foobar")))
         child.expect('>>> ')
         child.sendline('import sys')
-        child.sendline('"test2" in sys.modules')
+        child.sendline('"test" in sys.modules')
         child.expect('True')
-        child.sendline('"test2.mymodule" in sys.modules')
+        child.sendline('"test.mymodule" in sys.modules')
         child.expect('False')
         child.sendline('sys.path[0]')
         child.expect("''")
@@ -566,7 +566,7 @@
         child.expect('hello')
 
         monkeypatch.chdir(os.path.dirname(app_main))
-        child = self.spawn(['-mtest2.mymodule'])
+        child = self.spawn(['-mtest.mymodule'])
         child.expect('mymodule running')
 
     def test_ps1_only_if_interactive(self):
@@ -671,7 +671,7 @@
         p = os.path.join(os.path.realpath(os.path.dirname(__file__)), 'mymodule.py')
         p = os.path.abspath(p)
         monkeypatch.chdir(os.path.dirname(app_main))
-        data = self.run('-m test2.mymodule extra')
+        data = self.run('-m test.mymodule extra')
         assert 'mymodule running' in data
         assert 'Name: __main__' in data
         # ignoring case for windows. abspath behaves different from autopath
diff --git a/pypy/interpreter/test/test_gateway.py b/pypy/interpreter/test/test_gateway.py
--- a/pypy/interpreter/test/test_gateway.py
+++ b/pypy/interpreter/test/test_gateway.py
@@ -135,18 +135,39 @@
 
     def test_interpindirect2app(self):
         space = self.space
+
         class BaseA(W_Root):
             def method(self, space, x):
+                "This is a method"
+                pass
+
+            def method_with_default(self, space, x=5):
+                pass
+
+            @gateway.unwrap_spec(x=int)
+            def method_with_unwrap_spec(self, space, x):
                 pass
 
         class A(BaseA):
             def method(self, space, x):
                 return space.wrap(x + 2)
 
+            def method_with_default(self, space, x):
+                return space.wrap(x + 2)
+
+            def method_with_unwrap_spec(self, space, x):
+                return space.wrap(x + 2)
+
         class B(BaseA):
             def method(self, space, x):
                 return space.wrap(x + 1)
 
+            def method_with_default(self, space, x):
+                return space.wrap(x + 1)
+
+            def method_with_unwrap_spec(self, space, x):
+                return space.wrap(x + 1)
+
         class FakeTypeDef(object):
             rawdict = {}
             bases = {}
@@ -163,6 +184,23 @@
         assert space.int_w(space.call_function(w_c, w_a, space.wrap(1))) == 1 + 2
         assert space.int_w(space.call_function(w_c, w_b, space.wrap(-10))) == -10 + 1
 
+        doc = space.str_w(space.getattr(w_c, space.wrap('__doc__')))
+        assert doc == "This is a method"
+
+        meth_with_default = gateway.interpindirect2app(
+            BaseA.method_with_default, {'x': int})
+        w_d = space.wrap(meth_with_default)
+
+        assert space.int_w(space.call_function(w_d, w_a, space.wrap(4))) == 4 + 2
+        assert space.int_w(space.call_function(w_d, w_b, space.wrap(-10))) == -10 + 1
+        assert space.int_w(space.call_function(w_d, w_a)) == 5 + 2
+        assert space.int_w(space.call_function(w_d, w_b)) == 5 + 1
+
+        meth_with_unwrap_spec = gateway.interpindirect2app(
+            BaseA.method_with_unwrap_spec)
+        w_e = space.wrap(meth_with_unwrap_spec)
+        assert space.int_w(space.call_function(w_e, w_a, space.wrap(4))) == 4 + 2
+
     def test_interp2app_unwrap_spec(self):
         space = self.space
         w = space.wrap
diff --git a/pypy/interpreter/test/test_targetpypy.py b/pypy/interpreter/test/test_targetpypy.py
--- a/pypy/interpreter/test/test_targetpypy.py
+++ b/pypy/interpreter/test/test_targetpypy.py
@@ -1,5 +1,6 @@
 from pypy.goal.targetpypystandalone import get_entry_point, create_entry_point
 from pypy.config.pypyoption import get_pypy_config
+from rpython.rtyper.lltypesystem import rffi, lltype
 
 class TestTargetPyPy(object):
     def test_run(self):
@@ -8,11 +9,20 @@
         entry_point(['pypy-c' , '-S', '-c', 'print 3'])
 
 def test_exeucte_source(space):
-    _, execute_source = create_entry_point(space, None)
-    execute_source("import sys; sys.modules['xyz'] = 3")
+    _, d = create_entry_point(space, None)
+    execute_source = d['pypy_execute_source']
+    lls = rffi.str2charp("import sys; sys.modules['xyz'] = 3")
+    execute_source(lls)
+    lltype.free(lls, flavor='raw')
     x = space.int_w(space.getitem(space.getattr(space.builtin_modules['sys'],
                                                 space.wrap('modules')),
                                                 space.wrap('xyz')))
     assert x == 3
-    execute_source("sys")
+    lls = rffi.str2charp("sys")
+    execute_source(lls)
+    lltype.free(lls, flavor='raw')
     # did not crash - the same globals
+    pypy_setup_home = d['pypy_setup_home']
+    lls = rffi.str2charp(__file__)
+    pypy_setup_home(lls, 1)
+    lltype.free(lls, flavor='raw')
diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py
--- a/pypy/module/__pypy__/interp_magic.py
+++ b/pypy/module/__pypy__/interp_magic.py
@@ -1,4 +1,3 @@
-from pypy.interpreter.baseobjspace import ObjSpace, W_Root
 from pypy.interpreter.error import OperationError, wrap_oserror
 from pypy.interpreter.gateway import unwrap_spec
 from rpython.rlib.objectmodel import we_are_translated
@@ -56,7 +55,7 @@
     bltn = BuiltinFunction(func)
     return space.wrap(bltn)
 
- at unwrap_spec(ObjSpace, W_Root, str)
+ at unwrap_spec(meth=str)
 def lookup_special(space, w_obj, meth):
     """Lookup up a special method on an object."""
     if space.is_oldstyle_instance(w_obj):
diff --git a/pypy/module/array/__init__.py b/pypy/module/array/__init__.py
--- a/pypy/module/array/__init__.py
+++ b/pypy/module/array/__init__.py
@@ -1,12 +1,5 @@
 from pypy.interpreter.mixedmodule import MixedModule
 
-from pypy.module.array.interp_array import types
-from pypy.objspace.std.model import registerimplementation
-
-for mytype in types.values():
-    registerimplementation(mytype.w_class)
-
-
 class Module(MixedModule):
     interpleveldefs = {
         'array': 'interp_array.W_ArrayBase',
diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py
--- a/pypy/module/array/interp_array.py
+++ b/pypy/module/array/interp_array.py
@@ -2,17 +2,14 @@
 
 from pypy.interpreter.buffer import RWBuffer
 from pypy.interpreter.error import OperationError
-from pypy.interpreter.gateway import interp2app, unwrap_spec
-from pypy.interpreter.typedef import GetSetProperty, make_weakref_descr
+from pypy.interpreter.gateway import interp2app, unwrap_spec, interpindirect2app
+from pypy.interpreter.typedef import GetSetProperty, make_weakref_descr, TypeDef
+from pypy.interpreter.baseobjspace import W_Root
 from pypy.module._file.interp_file import W_File
-from pypy.objspace.std.model import W_Object
-from pypy.objspace.std.multimethod import FailedToImplement
-from pypy.objspace.std.stdtypedef import SMM, StdTypeDef
-from pypy.objspace.std.register_all import register_all
 from rpython.rlib import jit
 from rpython.rlib.rarithmetic import ovfcheck, widen
 from rpython.rlib.unroll import unrolling_iterable
-from rpython.rlib.objectmodel import specialize, keepalive_until_here
+from rpython.rlib.objectmodel import keepalive_until_here
 from rpython.rtyper.lltypesystem import lltype, rffi
 
 
@@ -39,9 +36,9 @@
             if len(__args__.arguments_w) > 0:
                 w_initializer = __args__.arguments_w[0]
                 if space.type(w_initializer) is space.w_str:
-                    a.fromstring(space.str_w(w_initializer))
+                    a.descr_fromstring(space, space.str_w(w_initializer))
                 elif space.type(w_initializer) is space.w_list:
-                    a.fromlist(w_initializer)
+                    a.descr_fromlist(space, w_initializer)
                 else:
                     a.extend(w_initializer, True)
             break
@@ -52,31 +49,6 @@
     return a
 
 
-array_append = SMM('append', 2)
-array_extend = SMM('extend', 2)
-
-array_count = SMM('count', 2)
-array_index = SMM('index', 2)
-array_reverse = SMM('reverse', 1)
-array_remove = SMM('remove', 2)
-array_pop = SMM('pop', 2, defaults=(-1,))
-array_insert = SMM('insert', 3)
-
-array_tolist = SMM('tolist', 1)
-array_fromlist = SMM('fromlist', 2)
-array_tostring = SMM('tostring', 1)
-array_fromstring = SMM('fromstring', 2)
-array_tounicode = SMM('tounicode', 1)
-array_fromunicode = SMM('fromunicode', 2)
-array_tofile = SMM('tofile', 2)
-array_fromfile = SMM('fromfile', 3)
-
-array_buffer_info = SMM('buffer_info', 1)
-array_reduce = SMM('__reduce__', 1)
-array_copy = SMM('__copy__', 1)
-array_byteswap = SMM('byteswap', 1)
-
-
 def descr_itemsize(space, self):
     return space.wrap(self.itemsize)
 
@@ -84,28 +56,476 @@
 def descr_typecode(space, self):
     return space.wrap(self.typecode)
 
+arr_eq_driver = jit.JitDriver(greens = ['comp_func'], reds = 'auto')
+EQ, NE, LT, LE, GT, GE = range(6)
 
-class W_ArrayBase(W_Object):
-    @staticmethod
-    def register(typeorder):
-        typeorder[W_ArrayBase] = []
+def compare_arrays(space, arr1, arr2, comp_op, comp_func):
+    if (not isinstance(arr1, W_ArrayBase) or
+        not isinstance(arr2, W_ArrayBase)):
+        return space.w_NotImplemented
+    if comp_op == EQ and arr1.len != arr2.len:
+        return space.w_False
+    if comp_op == NE and arr1.len != arr2.len:
+        return space.w_True
+    lgt = min(arr1.len, arr2.len)
+    for i in range(lgt):
+        arr_eq_driver.jit_merge_point(comp_func=comp_func)
+        w_elem1 = arr1.w_getitem(space, i)
+        w_elem2 = arr2.w_getitem(space, i)
+        res = space.is_true(comp_func(w_elem1, w_elem2))
+        if comp_op == EQ:
+            if not res:
+                return space.w_False
+        elif comp_op == NE:
+            if res:
+                return space.w_True
+        elif comp_op == LT or comp_op == GT:
+            if res:
+                return space.w_True
+            elif not space.is_true(space.eq(w_elem1, w_elem2)):
+                return space.w_False
+        else:
+            if not res:
+                return space.w_False
+            elif not space.is_true(space.eq(w_elem1, w_elem2)):
+                return space.w_True
+    # we have some leftovers
+    if comp_op == EQ:
+        return space.w_True
+    elif comp_op == NE:
+        return space.w_False
+    if arr1.len == arr2.len:
+        if comp_op == LT or comp_op == GT:
+            return space.w_False
+        return space.w_True
+    if comp_op == LT or comp_op == LE:
+        if arr1.len < arr2.len:
+            return space.w_False
+        return space.w_True
+    if arr1.len > arr2.len:
+        return space.w_False
+    return space.w_True
 
-W_ArrayBase.typedef = StdTypeDef(
+UNICODE_ARRAY = lltype.Ptr(lltype.Array(lltype.UniChar,
+                                        hints={'nolength': True}))
+
+class W_ArrayBase(W_Root):
+    _attrs_ = ('space', 'len', 'allocated', '_lifeline_') # no buffer
+
+    def __init__(self, space):
+        self.space = space
+        self.len = 0
+        self.allocated = 0
+
+    def descr_append(self, space, w_x):
+        """ append(x)
+
+        Append new value x to the end of the array.
+        """
+        raise NotImplementedError
+
+    def descr_extend(self, space, w_x):
+        """ extend(array or iterable)
+
+        Append items to the end of the array.
+        """
+        self.extend(w_x)
+
+    def descr_count(self, space, w_val):
+        """ count(x)
+
+        Return number of occurrences of x in the array.
+        """
+        raise NotImplementedError
+
+    def descr_index(self, space, w_x):
+        """ index(x)
+
+        Return index of first occurrence of x in the array.
+        """
+        raise NotImplementedError
+
+    def descr_reverse(self, space):
+        """ reverse()
+
+        Reverse the order of the items in the array.
+        """
+        raise NotImplementedError
+
+    def descr_remove(self, space, w_val):
+        """ remove(x)
+
+        Remove the first occurrence of x in the array.
+        """
+        raise NotImplementedError
+
+    @unwrap_spec(i=int)
+    def descr_pop(self, space, i=-1):
+        """ pop([i])
+
+        Return the i-th element and delete it from the array. i defaults to -1.
+        """
+        raise NotImplementedError
+
+    @unwrap_spec(idx=int)
+    def descr_insert(self, space, idx, w_val):
+        """ insert(i,x)
+
+        Insert a new item x into the array before position i.
+        """
+        raise NotImplementedError
+
+    def descr_tolist(self, space):
+        """ tolist() -> list
+
+        Convert array to an ordinary list with the same items.
+        """
+        w_l = space.newlist([])
+        for i in range(self.len):
+            w_l.append(self.w_getitem(space, i))
+        return w_l
+
+    def descr_fromlist(self, space, w_lst):
+        """ fromlist(list)
+
+        Append items to array from list.
+        """
+        if not space.isinstance_w(w_lst, space.w_list):
+            raise OperationError(space.w_TypeError,
+                                 space.wrap("arg must be list"))
+        s = self.len
+        try:
+            self.fromsequence(w_lst)
+        except OperationError:
+            self.setlen(s)
+            raise
+
+    def descr_tostring(self, space):
+        """ tostring() -> string
+
+        Convert the array to an array of machine values and return the string
+        representation.
+        """
+        cbuf = self._charbuf_start()
+        s = rffi.charpsize2str(cbuf, self.len * self.itemsize)
+        self._charbuf_stop()
+        return self.space.wrap(s)
+
+    @unwrap_spec(s=str)
+    def descr_fromstring(self, space, s):
+        """ fromstring(string)
+
+        Appends items from the string, interpreting it as an array of machine
+        values,as if it had been read from a file using the fromfile() method).
+        """
+        if len(s) % self.itemsize != 0:
+            msg = 'string length not a multiple of item size'
+            raise OperationError(self.space.w_ValueError, self.space.wrap(msg))
+        oldlen = self.len
+        new = len(s) / self.itemsize
+        self.setlen(oldlen + new)
+        cbuf = self._charbuf_start()
+        for i in range(len(s)):
+            cbuf[oldlen * self.itemsize + i] = s[i]
+        self._charbuf_stop()
+
+    @unwrap_spec(w_f=W_File, n=int)
+    def descr_fromfile(self, space, w_f, n):
+        """ fromfile(f, n)
+
+        Read n objects from the file object f and append them to the end of the
+        array.  Also called as read.
+        """
+        try:
+            size = ovfcheck(self.itemsize * n)
+        except OverflowError:
+            raise MemoryError
+        w_item = space.call_method(w_f, 'read', space.wrap(size))
+        item = space.str_w(w_item)
+        if len(item) < size:
+            n = len(item) % self.itemsize
+            elems = max(0, len(item) - (len(item) % self.itemsize))
+            if n != 0:
+                item = item[0:elems]
+            self.descr_fromstring(space, item)
+            msg = "not enough items in file"
+            raise OperationError(space.w_EOFError, space.wrap(msg))
+        self.descr_fromstring(space, item)
+
+    @unwrap_spec(w_f=W_File)
+    def descr_tofile(self, space, w_f):
+        """ tofile(f)
+
+        Write all items (as machine values) to the file object f.  Also called as
+        write.
+        """
+        w_s = self.descr_tostring(space)
+        space.call_method(w_f, 'write', w_s)
+
+    def descr_fromunicode(self, space, w_ustr):
+        """ fromunicode(ustr)
+
+        Extends this array with data from the unicode string ustr.
+        The array must be a type 'u' array; otherwise a ValueError
+        is raised.  Use array.fromstring(ustr.decode(...)) to
+        append Unicode data to an array of some other type.
+        """
+        # XXX the following probable bug is not emulated:
+        # CPython accepts a non-unicode string or a buffer, and then
+        # behaves just like fromstring(), except that it strangely truncate
+        # string arguments at multiples of the unicode byte size.
+        # Let's only accept unicode arguments for now.
+        if self.typecode == 'u':
+            self.fromsequence(w_ustr)
+        else:
+            msg = "fromunicode() may only be called on type 'u' arrays"
+            raise OperationError(space.w_ValueError, space.wrap(msg))
+
+    def descr_tounicode(self, space):
+        """ tounicode() -> unicode
+
+        Convert the array to a unicode string.  The array must be
+        a type 'u' array; otherwise a ValueError is raised.  Use
+        array.tostring().decode() to obtain a unicode string from
+        an array of some other type.
+        """
+        if self.typecode == 'u':
+            buf = rffi.cast(UNICODE_ARRAY, self._buffer_as_unsigned())
+            return space.wrap(rffi.wcharpsize2unicode(buf, self.len))
+        else:
+            msg = "tounicode() may only be called on type 'u' arrays"
+            raise OperationError(space.w_ValueError, space.wrap(msg))
+
+    def descr_buffer_info(self, space):
+        """ buffer_info() -> (address, length)
+
+        Return a tuple (address, length) giving the current memory address and
+        the length in items of the buffer used to hold array's contents
+        The length should be multiplied by the itemsize attribute to calculate
+        the buffer length in bytes.
+        """
+        w_ptr = space.wrap(self._buffer_as_unsigned())
+        w_len = space.wrap(self.len)
+        return space.newtuple([w_ptr, w_len])
+
+    def descr_reduce(self, space):
+        """ Return state information for pickling.
+        """
+        if self.len > 0:
+            w_s = self.descr_tostring(space)
+            args = [space.wrap(self.typecode), w_s]
+        else:
+            args = [space.wrap(self.typecode)]
+        try:
+            dct = space.getattr(self, space.wrap('__dict__'))
+        except OperationError:
+            dct = space.w_None
+        return space.newtuple([space.type(self), space.newtuple(args), dct])
+
+    def descr_copy(self, space):
+        """ copy(array)
+
+        Return a copy of the array.
+        """
+        w_a = self.constructor(self.space)
+        w_a.setlen(self.len, overallocate=False)
+        rffi.c_memcpy(
+            rffi.cast(rffi.VOIDP, w_a._buffer_as_unsigned()),
+            rffi.cast(rffi.VOIDP, self._buffer_as_unsigned()),
+            self.len * self.itemsize
+        )
+        return w_a
+
+    def descr_byteswap(self, space):
+        """ byteswap()
+
+        Byteswap all items of the array.  If the items in the array are not 1, 2,
+        4, or 8 bytes in size, RuntimeError is raised.
+        """
+        if self.itemsize not in [1, 2, 4, 8]:
+            msg = "byteswap not supported for this array"
+            raise OperationError(space.w_RuntimeError, space.wrap(msg))
+        if self.len == 0:
+            return
+        bytes = self._charbuf_start()
+        tmp = [bytes[0]] * self.itemsize
+        for start in range(0, self.len * self.itemsize, self.itemsize):
+            stop = start + self.itemsize - 1
+            for i in range(self.itemsize):
+                tmp[i] = bytes[start + i]
+            for i in range(self.itemsize):
+                bytes[stop - i] = tmp[i]
+        self._charbuf_stop()
+
+    def descr_len(self, space):
+        return space.wrap(self.len)
+
+    def descr_eq(self, space, w_arr2):
+        "x.__eq__(y) <==> x==y"
+        return compare_arrays(space, self, w_arr2, EQ, space.eq)
+
+    def descr_ne(self, space, w_arr2):
+        "x.__ne__(y) <==> x!=y"
+        return compare_arrays(space, self, w_arr2, NE, space.ne)
+
+    def descr_lt(self, space, w_arr2):
+        "x.__lt__(y) <==> x<y"
+        return compare_arrays(space, self, w_arr2, LT, space.lt)
+
+    def descr_le(self, space, w_arr2):
+        "x.__le__(y) <==> x<=y"
+        return compare_arrays(space, self, w_arr2, LE, space.le)
+
+    def descr_gt(self, space, w_arr2):
+        "x.__gt__(y) <==> x>y"
+        return compare_arrays(space, self, w_arr2, GT, space.gt)
+
+    def descr_ge(self, space, w_arr2):
+        "x.__ge__(y) <==> x>=y"
+        return compare_arrays(space, self, w_arr2, GE, space.ge)
+
+    # Basic get/set/append/extend methods
+
+    def descr_getitem(self, space, w_idx):
+        "x.__getitem__(y) <==> x[y]"
+        if not space.isinstance_w(w_idx, space.w_slice):
+            idx, stop, step = space.decode_index(w_idx, self.len)
+            assert step == 0
+            return self.w_getitem(space, idx)
+        else:
+            return self.getitem_slice(space, w_idx)
+
+    def descr_getslice(self, space, w_i, w_j):
+        return space.getitem(self, space.newslice(w_i, w_j, space.w_None))
+
+
+    def descr_setitem(self, space, w_idx, w_item):
+        "x.__setitem__(i, y) <==> x[i]=y"
+        if space.isinstance_w(w_idx, space.w_slice):
+            self.setitem_slice(space, w_idx, w_item)
+        else:
+            self.setitem(space, w_idx, w_item)
+
+    def descr_setslice(self, space, w_start, w_stop, w_item):
+        self.setitem_slice(space,
+                           space.newslice(w_start, w_stop, space.w_None),
+                           w_item)
+
+    def descr_delitem(self, space, w_idx):
+        start, stop, step, size = self.space.decode_index4(w_idx, self.len)
+        if step != 1:
+            # I don't care about efficiency of that so far
+            w_lst = self.descr_tolist(space)
+            space.delitem(w_lst, w_idx)
+            self.setlen(0)
+            self.fromsequence(w_lst)
+            return
+        return self.delitem(space, start, stop)
+
+    def descr_delslice(self, space, w_start, w_stop):
+        self.descr_delitem(space, space.newslice(w_start, w_stop, space.w_None))
+
+    def descr_add(self, space, w_other):
+        raise NotImplementedError
+
+    def descr_inplace_add(self, space, w_other):
+        raise NotImplementedError
+
+    def descr_mul(self, space, w_repeat):
+        raise NotImplementedError
+
+    def descr_inplace_mul(self, space, w_repeat):
+        raise NotImplementedError
+
+    def descr_radd(self, space, w_other):
+        return self.descr_add(space, w_other)
+
+    def descr_rmul(self, space, w_repeat):
+        return self.descr_mul(space, w_repeat)
+
+    # Misc methods
+
+    def descr_buffer(self, space):
+        return space.wrap(ArrayBuffer(self))
+
+    def descr_repr(self, space):
+        if self.len == 0:
+            return space.wrap("array('%s')" % self.typecode)
+        elif self.typecode == "c":
+            r = space.repr(self.descr_tostring(space))
+            s = "array('%s', %s)" % (self.typecode, space.str_w(r))
+            return space.wrap(s)
+        elif self.typecode == "u":
+            r = space.repr(self.descr_tounicode(space))
+            s = "array('%s', %s)" % (self.typecode, space.str_w(r))
+            return space.wrap(s)
+        else:
+            r = space.repr(self.descr_tolist(space))
+            s = "array('%s', %s)" % (self.typecode, space.str_w(r))
+            return space.wrap(s)
+
+W_ArrayBase.typedef = TypeDef(
     'array',
     __new__ = interp2app(w_array),
     __module__   = 'array',
+
+    __len__ = interp2app(W_ArrayBase.descr_len),
+    __eq__ = interp2app(W_ArrayBase.descr_eq),
+    __ne__ = interp2app(W_ArrayBase.descr_ne),
+    __lt__ = interp2app(W_ArrayBase.descr_lt),
+    __le__ = interp2app(W_ArrayBase.descr_le),
+    __gt__ = interp2app(W_ArrayBase.descr_gt),
+    __ge__ = interp2app(W_ArrayBase.descr_ge),
+
+    __getitem__ = interp2app(W_ArrayBase.descr_getitem),
+    __getslice__ = interp2app(W_ArrayBase.descr_getslice),
+    __setitem__ = interp2app(W_ArrayBase.descr_setitem),
+    __setslice__ = interp2app(W_ArrayBase.descr_setslice),
+    __delitem__ = interp2app(W_ArrayBase.descr_delitem),
+    __delslice__ = interp2app(W_ArrayBase.descr_delslice),
+
+    __add__ = interpindirect2app(W_ArrayBase.descr_add),
+    __iadd__ = interpindirect2app(W_ArrayBase.descr_inplace_add),
+    __mul__ = interpindirect2app(W_ArrayBase.descr_mul),
+    __imul__ = interpindirect2app(W_ArrayBase.descr_inplace_mul),
+    __radd__ = interp2app(W_ArrayBase.descr_radd),
+    __rmul__ = interp2app(W_ArrayBase.descr_rmul),
+
+    __buffer__ = interp2app(W_ArrayBase.descr_buffer),
+    __repr__ = interp2app(W_ArrayBase.descr_repr),
+
     itemsize = GetSetProperty(descr_itemsize),
     typecode = GetSetProperty(descr_typecode),
     __weakref__ = make_weakref_descr(W_ArrayBase),
+    append = interpindirect2app(W_ArrayBase.descr_append),
+    extend = interp2app(W_ArrayBase.descr_extend),
+    count = interpindirect2app(W_ArrayBase.descr_count),
+    index = interpindirect2app(W_ArrayBase.descr_index),
+    reverse = interpindirect2app(W_ArrayBase.descr_reverse),
+    remove = interpindirect2app(W_ArrayBase.descr_remove),
+    pop = interpindirect2app(W_ArrayBase.descr_pop),
+    insert = interpindirect2app(W_ArrayBase.descr_insert),
+
+    tolist = interp2app(W_ArrayBase.descr_tolist),
+    fromlist = interp2app(W_ArrayBase.descr_fromlist),
+    tostring = interp2app(W_ArrayBase.descr_tostring),
+    fromstring = interp2app(W_ArrayBase.descr_fromstring),
+    tofile = interp2app(W_ArrayBase.descr_tofile),
+    fromfile = interp2app(W_ArrayBase.descr_fromfile),
+    fromunicode = interp2app(W_ArrayBase.descr_fromunicode),
+    tounicode = interp2app(W_ArrayBase.descr_tounicode),
+
+    buffer_info = interp2app(W_ArrayBase.descr_buffer_info),
+    __copy__ = interp2app(W_ArrayBase.descr_copy),
+    __reduce__ = interp2app(W_ArrayBase.descr_reduce),
+    byteswap = interp2app(W_ArrayBase.descr_byteswap),
 )
-W_ArrayBase.typedef.registermethods(globals())
 
 
 class TypeCode(object):
     def __init__(self, itemtype, unwrap, canoverflow=False, signed=False):
         self.itemtype = itemtype
         self.bytes = rffi.sizeof(itemtype)
-        #self.arraytype = lltype.GcArray(itemtype)
         self.arraytype = lltype.Array(itemtype, hints={'nolength': True})
         self.unwrap = unwrap
         self.signed = signed
@@ -175,14 +595,10 @@
         itemsize = mytype.bytes
         typecode = mytype.typecode
 
-        @staticmethod
-        def register(typeorder):
-            typeorder[W_Array] = [(W_ArrayBase, None)]
+        _attrs_ = ('space', 'len', 'allocated', '_lifeline_', 'buffer')
 
         def __init__(self, space):
-            self.space = space
-            self.len = 0
-            self.allocated = 0
+            W_ArrayBase.__init__(self, space)
             self.buffer = lltype.nullptr(mytype.arraytype)
 
         def item_w(self, w_item):
@@ -289,26 +705,6 @@
                 raise
             self.setlen(oldlen + i)
 
-        def fromstring(self, s):
-            if len(s) % self.itemsize != 0:
-                msg = 'string length not a multiple of item size'
-                raise OperationError(self.space.w_ValueError, self.space.wrap(msg))
-            oldlen = self.len
-            new = len(s) / mytype.bytes
-            self.setlen(oldlen + new)
-            cbuf = self._charbuf_start()
-            for i in range(len(s)):
-                cbuf[oldlen * mytype.bytes + i] = s[i]
-            self._charbuf_stop()
-
-        def fromlist(self, w_lst):
-            s = self.len
-            try:
-                self.fromsequence(w_lst)
-            except OperationError:
-                self.setlen(s)
-                raise
-
         def extend(self, w_iterable, accept_different_array=False):
             space = self.space
             if isinstance(w_iterable, W_Array):
@@ -332,6 +728,9 @@
         def _charbuf_start(self):
             return rffi.cast(rffi.CCHARP, self.buffer)
 
+        def _buffer_as_unsigned(self):
+            return rffi.cast(lltype.Unsigned, self.buffer)
+
         def _charbuf_stop(self):
             keepalive_until_here(self)
 
@@ -343,202 +742,180 @@
                 item = float(item)
             return space.wrap(item)
 
-    # Basic get/set/append/extend methods
+        # interface
 
-    def len__Array(space, self):
-        return space.wrap(self.len)
+        def descr_append(self, space, w_x):
+            x = self.item_w(w_x)
+            self.setlen(self.len + 1)
+            self.buffer[self.len - 1] = x
 
-    def getitem__Array_ANY(space, self, w_idx):
-        idx, stop, step = space.decode_index(w_idx, self.len)
-        assert step == 0
-        return self.w_getitem(space, idx)
+        # List interface
+        def descr_count(self, space, w_val):
+            cnt = 0
+            for i in range(self.len):
+                # XXX jitdriver
+                w_item = self.w_getitem(space, i)
+                if space.is_true(space.eq(w_item, w_val)):
+                    cnt += 1
+            return space.wrap(cnt)
 
-    def getitem__Array_Slice(space, self, w_slice):
-        start, stop, step, size = space.decode_index4(w_slice, self.len)
-        w_a = mytype.w_class(self.space)
-        w_a.setlen(size, overallocate=False)
-        assert step != 0
-        j = 0
-        for i in range(start, stop, step):
-            w_a.buffer[j] = self.buffer[i]
-            j += 1
-        return w_a
+        def descr_index(self, space, w_val):
+            for i in range(self.len):
+                w_item = self.w_getitem(space, i)
+                if space.is_true(space.eq(w_item, w_val)):
+                    return space.wrap(i)
+            msg = 'array.index(x): x not in list'
+            raise OperationError(space.w_ValueError, space.wrap(msg))
 
-    def getslice__Array_ANY_ANY(space, self, w_i, w_j):
-        return space.getitem(self, space.newslice(w_i, w_j, space.w_None))
+        def descr_reverse(self, space):
+            b = self.buffer
+            for i in range(self.len / 2):
+                b[i], b[self.len - i - 1] = b[self.len - i - 1], b[i]
 
-    def setitem__Array_ANY_ANY(space, self, w_idx, w_item):
-        idx, stop, step = space.decode_index(w_idx, self.len)
-        if step != 0:
-            msg = 'can only assign array to array slice'
-            raise OperationError(self.space.w_TypeError, self.space.wrap(msg))
-        item = self.item_w(w_item)
-        self.buffer[idx] = item
+        def descr_pop(self, space, i):
+            if i < 0:
+                i += self.len
+            if i < 0 or i >= self.len:
+                msg = 'pop index out of range'
+                raise OperationError(space.w_IndexError, space.wrap(msg))
+            w_val = self.w_getitem(space, i)
+            while i < self.len - 1:
+                self.buffer[i] = self.buffer[i + 1]
+                i += 1
+            self.setlen(self.len - 1)
+            return w_val
 
-    def setitem__Array_Slice_Array(space, self, w_idx, w_item):
-        start, stop, step, size = self.space.decode_index4(w_idx, self.len)
-        assert step != 0
-        if w_item.len != size or self is w_item:
-            # XXX this is a giant slow hack
-            w_lst = array_tolist__Array(space, self)
-            w_item = space.call_method(w_item, 'tolist')
-            space.setitem(w_lst, w_idx, w_item)
-            self.setlen(0)
-            self.fromsequence(w_lst)
-        else:
+        def descr_remove(self, space, w_val):
+            w_idx = self.descr_index(space, w_val)
+            self.descr_pop(space, space.int_w(w_idx))
+
+        def descr_insert(self, space, idx, w_val):
+            if idx < 0:
+                idx += self.len
+            if idx < 0:
+                idx = 0
+            if idx > self.len:
+                idx = self.len
+
+            val = self.item_w(w_val)
+            self.setlen(self.len + 1)
+            i = self.len - 1
+            while i > idx:
+                self.buffer[i] = self.buffer[i - 1]
+                i -= 1
+            self.buffer[i] = val
+
+        def getitem_slice(self, space, w_idx):
+            start, stop, step, size = space.decode_index4(w_idx, self.len)
+            w_a = mytype.w_class(self.space)
+            w_a.setlen(size, overallocate=False)
+            assert step != 0
             j = 0
             for i in range(start, stop, step):
-                self.buffer[i] = w_item.buffer[j]
+                w_a.buffer[j] = self.buffer[i]
                 j += 1
+            return w_a
 
-    def setslice__Array_ANY_ANY_ANY(space, self, w_i, w_j, w_x):
-        space.setitem(self, space.newslice(w_i, w_j, space.w_None), w_x)
+        def setitem(self, space, w_idx, w_item):
+            idx, stop, step = space.decode_index(w_idx, self.len)
+            if step != 0:
+                msg = 'can only assign array to array slice'
+                raise OperationError(self.space.w_TypeError,
+                                     self.space.wrap(msg))
+            item = self.item_w(w_item)
+            self.buffer[idx] = item
 
-    def array_append__Array_ANY(space, self, w_x):
-        x = self.item_w(w_x)
-        self.setlen(self.len + 1)
-        self.buffer[self.len - 1] = x
+        def setitem_slice(self, space, w_idx, w_item):
+            if not isinstance(w_item, W_Array):
+                raise OperationError(space.w_TypeError, space.wrap(
+                    "can only assign to a slice array"))
+            start, stop, step, size = self.space.decode_index4(w_idx, self.len)
+            assert step != 0
+            if w_item.len != size or self is w_item:
+                # XXX this is a giant slow hack
+                w_lst = self.descr_tolist(space)
+                w_item = space.call_method(w_item, 'tolist')
+                space.setitem(w_lst, w_idx, w_item)
+                self.setlen(0)
+                self.fromsequence(w_lst)
+            else:
+                j = 0
+                for i in range(start, stop, step):
+                    self.buffer[i] = w_item.buffer[j]
+                    j += 1
 
-    def array_extend__Array_ANY(space, self, w_iterable):
-        self.extend(w_iterable)
+        # We can't look into this function until ptradd works with things (in the
+        # JIT) other than rffi.CCHARP
+        @jit.dont_look_inside
+        def delitem(self, space, i, j):
+            if i < 0:
+                i += self.len
+            if i < 0:
+                i = 0
+            if j < 0:
+                j += self.len
+            if j < 0:
+                j = 0
+            if j > self.len:
+                j = self.len
+            if i >= j:
+                return None
+            oldbuffer = self.buffer
+            self.buffer = lltype.malloc(mytype.arraytype,
+                          max(self.len - (j - i), 0), flavor='raw',
+                          add_memory_pressure=True)
+            if i:
+                rffi.c_memcpy(
+                    rffi.cast(rffi.VOIDP, self.buffer),
+                    rffi.cast(rffi.VOIDP, oldbuffer),
+                    i * mytype.bytes
+                )
+            if j < self.len:
+                rffi.c_memcpy(
+                    rffi.cast(rffi.VOIDP, rffi.ptradd(self.buffer, i)),
+                    rffi.cast(rffi.VOIDP, rffi.ptradd(oldbuffer, j)),
+                    (self.len - j) * mytype.bytes
+                )
+            self.len -= j - i
+            self.allocated = self.len
+            if oldbuffer:
+                lltype.free(oldbuffer, flavor='raw')
 
-    # List interface
-    def array_count__Array_ANY(space, self, w_val):
-        cnt = 0
-        for i in range(self.len):
-            w_item = self.w_getitem(space, i)
-            if space.is_true(space.eq(w_item, w_val)):
-                cnt += 1
-        return space.wrap(cnt)
+        # Add and mul methods
 
-    def array_index__Array_ANY(space, self, w_val):
-        for i in range(self.len):
-            w_item = self.w_getitem(space, i)
-            if space.is_true(space.eq(w_item, w_val)):
-                return space.wrap(i)
-        msg = 'array.index(x): x not in list'
-        raise OperationError(space.w_ValueError, space.wrap(msg))
+        def descr_add(self, space, w_other):
+            if not isinstance(w_other, W_Array):
+                return space.w_NotImplemented
+            a = mytype.w_class(space)
+            a.setlen(self.len + w_other.len, overallocate=False)
+            for i in range(self.len):
+                a.buffer[i] = self.buffer[i]
+            for i in range(w_other.len):
+                a.buffer[i + self.len] = w_other.buffer[i]
+            return a
 
-    def array_reverse__Array(space, self):
-        b = self.buffer
-        for i in range(self.len / 2):
-            b[i], b[self.len - i - 1] = b[self.len - i - 1], b[i]
+        def descr_inplace_add(self, space, w_other):
+            if not isinstance(w_other, W_Array):
+                return space.w_NotImplemented
+            oldlen = self.len
+            otherlen = w_other.len
+            self.setlen(oldlen + otherlen)
+            for i in range(otherlen):
+                self.buffer[oldlen + i] = w_other.buffer[i]
+            return self
 
-    def array_pop__Array_ANY(space, self, w_idx):
-        i = space.int_w(w_idx)
-        if i < 0:
-            i += self.len
-        if i < 0 or i >= self.len:
-            msg = 'pop index out of range'
-            raise OperationError(space.w_IndexError, space.wrap(msg))
-        w_val = self.w_getitem(space, i)
-        while i < self.len - 1:
-            self.buffer[i] = self.buffer[i + 1]
-            i += 1
-        self.setlen(self.len - 1)
-        return w_val
+        def descr_mul(self, space, w_repeat):
+            return _mul_helper(space, self, w_repeat, False)
 
-    def array_remove__Array_ANY(space, self, w_val):
-        w_idx = array_index__Array_ANY(space, self, w_val)
-        array_pop__Array_ANY(space, self, w_idx)
-
-    def array_insert__Array_ANY_ANY(space, self, w_idx, w_val):
-        idx = space.int_w(w_idx)
-        if idx < 0:
-            idx += self.len
-        if idx < 0:
-            idx = 0
-        if idx > self.len:
-            idx = self.len
-
-        val = self.item_w(w_val)
-        self.setlen(self.len + 1)
-        i = self.len - 1
-        while i > idx:
-            self.buffer[i] = self.buffer[i - 1]
-            i -= 1
-        self.buffer[i] = val
-
-    def delitem__Array_ANY(space, self, w_idx):
-        # XXX this is a giant slow hack
-        w_lst = array_tolist__Array(space, self)
-        space.delitem(w_lst, w_idx)
-        self.setlen(0)
-        self.fromsequence(w_lst)
-
-    # We can't look into this function until ptradd works with things (in the
-    # JIT) other than rffi.CCHARP
-    @jit.dont_look_inside
-    def delslice__Array_ANY_ANY(space, self, w_i, w_j):
-        i = space.int_w(w_i)
-        if i < 0:
-            i += self.len
-        if i < 0:
-            i = 0
-        j = space.int_w(w_j)
-        if j < 0:
-            j += self.len
-        if j < 0:
-            j = 0
-        if j > self.len:
-            j = self.len
-        if i >= j:
-            return None
-        oldbuffer = self.buffer
-        self.buffer = lltype.malloc(mytype.arraytype,
-                      max(self.len - (j - i), 0), flavor='raw',
-                      add_memory_pressure=True)
-        if i:
-            rffi.c_memcpy(
-                rffi.cast(rffi.VOIDP, self.buffer),
-                rffi.cast(rffi.VOIDP, oldbuffer),
-                i * mytype.bytes
-            )
-        if j < self.len:
-            rffi.c_memcpy(
-                rffi.cast(rffi.VOIDP, rffi.ptradd(self.buffer, i)),
-                rffi.cast(rffi.VOIDP, rffi.ptradd(oldbuffer, j)),
-                (self.len - j) * mytype.bytes
-            )
-        self.len -= j - i
-        self.allocated = self.len
-        if oldbuffer:
-            lltype.free(oldbuffer, flavor='raw')
-
-    # Add and mul methods
-
-    def add__Array_Array(space, self, other):
-        a = mytype.w_class(space)
-        a.setlen(self.len + other.len, overallocate=False)
-        for i in range(self.len):
-            a.buffer[i] = self.buffer[i]
-        for i in range(other.len):
-            a.buffer[i + self.len] = other.buffer[i]
-        return a
-
-    def inplace_add__Array_Array(space, self, other):
-        oldlen = self.len
-        otherlen = other.len
-        self.setlen(oldlen + otherlen)
-        for i in range(otherlen):
-            self.buffer[oldlen + i] = other.buffer[i]
-        return self
-
-    def mul__Array_ANY(space, self, w_repeat):
-        return _mul_helper(space, self, w_repeat, False)
-
-    def mul__ANY_Array(space, w_repeat, self):
-        return _mul_helper(space, self, w_repeat, False)
-
-    def inplace_mul__Array_ANY(space, self, w_repeat):
-        return _mul_helper(space, self, w_repeat, True)
+        def descr_inplace_mul(self, space, w_repeat):
+            return _mul_helper(space, self, w_repeat, True)
 
     def _mul_helper(space, self, w_repeat, is_inplace):
         try:
             repeat = space.getindex_w(w_repeat, space.w_OverflowError)
         except OperationError, e:
             if e.match(space, space.w_TypeError):
-                raise FailedToImplement
+                return space.w_NotImplemented
             raise
         repeat = max(repeat, 0)
         try:
@@ -577,186 +954,11 @@
                 a.buffer[r * oldlen + i] = self.buffer[i]
         return a
 
-    # Convertions
-
-    def array_tolist__Array(space, self):
-        w_l = space.newlist([])
-        for i in range(self.len):
-            w_l.append(self.w_getitem(space, i))
-        return w_l
-
-    def array_fromlist__Array_List(space, self, w_lst):
-        self.fromlist(w_lst)
-
-    def array_fromstring__Array_ANY(space, self, w_s):
-        self.fromstring(space.str_w(w_s))
-
-    def array_tostring__Array(space, self):
-        cbuf = self._charbuf_start()
-        s = rffi.charpsize2str(cbuf, self.len * mytype.bytes)
-        self._charbuf_stop()
-        return self.space.wrap(s)
-
-    def array_fromfile__Array_ANY_ANY(space, self, w_f, w_n):
-        if not isinstance(w_f, W_File):
-            msg = "arg1 must be open file"
-            raise OperationError(space.w_TypeError, space.wrap(msg))
-        n = space.int_w(w_n)
-
-        try:
-            size = ovfcheck(self.itemsize * n)
-        except OverflowError:
-            raise MemoryError
-        w_item = space.call_method(w_f, 'read', space.wrap(size))
-        item = space.str_w(w_item)
-        if len(item) < size:
-            n = len(item) % self.itemsize
-            elems = max(0, len(item) - (len(item) % self.itemsize))
-            if n != 0:
-                item = item[0:elems]
-            w_item = space.wrap(item)
-            array_fromstring__Array_ANY(space, self, w_item)
-            msg = "not enough items in file"
-            raise OperationError(space.w_EOFError, space.wrap(msg))
-        array_fromstring__Array_ANY(space, self, w_item)
-
-    def array_tofile__Array_ANY(space, self, w_f):
-        if not isinstance(w_f, W_File):
-            msg = "arg1 must be open file"
-            raise OperationError(space.w_TypeError, space.wrap(msg))
-        w_s = array_tostring__Array(space, self)
-        space.call_method(w_f, 'write', w_s)
-
-    if mytype.typecode == 'u':
-
-        def array_fromunicode__Array_Unicode(space, self, w_ustr):
-            # XXX the following probable bug is not emulated:
-            # CPython accepts a non-unicode string or a buffer, and then
-            # behaves just like fromstring(), except that it strangely truncate
-            # string arguments at multiples of the unicode byte size.
-            # Let's only accept unicode arguments for now.
-            self.fromsequence(w_ustr)
-
-        def array_tounicode__Array(space, self):
-            return space.wrap(rffi.wcharpsize2unicode(self.buffer, self.len))
-    else:
-
-        def array_fromunicode__Array_Unicode(space, self, w_ustr):
-            msg = "fromunicode() may only be called on type 'u' arrays"
-            raise OperationError(space.w_ValueError, space.wrap(msg))
-
-        def array_tounicode__Array(space, self):
-            msg = "tounicode() may only be called on type 'u' arrays"
-            raise OperationError(space.w_ValueError, space.wrap(msg))
-
-    # Compare methods
-    @specialize.arg(3)
-    def _cmp_impl(space, self, other, space_fn):
-        # XXX this is a giant slow hack
-        w_lst1 = array_tolist__Array(space, self)
-        w_lst2 = space.call_method(other, 'tolist')
-        return space_fn(w_lst1, w_lst2)
-
-    def eq__Array_ArrayBase(space, self, other):
-        return _cmp_impl(space, self, other, space.eq)
-
-    def ne__Array_ArrayBase(space, self, other):
-        return _cmp_impl(space, self, other, space.ne)
-
-    def lt__Array_ArrayBase(space, self, other):
-        return _cmp_impl(space, self, other, space.lt)
-
-    def le__Array_ArrayBase(space, self, other):
-        return _cmp_impl(space, self, other, space.le)
-
-    def gt__Array_ArrayBase(space, self, other):
-        return _cmp_impl(space, self, other, space.gt)
-
-    def ge__Array_ArrayBase(space, self, other):
-        return _cmp_impl(space, self, other, space.ge)
-
-    # Misc methods
-
-    def buffer__Array(space, self):
-        return space.wrap(ArrayBuffer(self))
-
-    def array_buffer_info__Array(space, self):
-        w_ptr = space.wrap(rffi.cast(lltype.Unsigned, self.buffer))
-        w_len = space.wrap(self.len)
-        return space.newtuple([w_ptr, w_len])
-
-    def array_reduce__Array(space, self):
-        if self.len > 0:
-            w_s = array_tostring__Array(space, self)
-            args = [space.wrap(mytype.typecode), w_s]
-        else:
-            args = [space.wrap(mytype.typecode)]
-        try:
-            dct = space.getattr(self, space.wrap('__dict__'))
-        except OperationError:
-            dct = space.w_None
-        return space.newtuple([space.type(self), space.newtuple(args), dct])
-
-    def array_copy__Array(space, self):
-        w_a = mytype.w_class(self.space)
-        w_a.setlen(self.len, overallocate=False)
-        rffi.c_memcpy(
-            rffi.cast(rffi.VOIDP, w_a.buffer),
-            rffi.cast(rffi.VOIDP, self.buffer),
-            self.len * mytype.bytes
-        )
-        return w_a
-
-    def array_byteswap__Array(space, self):
-        if mytype.bytes not in [1, 2, 4, 8]:
-            msg = "byteswap not supported for this array"
-            raise OperationError(space.w_RuntimeError, space.wrap(msg))
-        if self.len == 0:
-            return
-        bytes = self._charbuf_start()
-        tmp = [bytes[0]] * mytype.bytes
-        for start in range(0, self.len * mytype.bytes, mytype.bytes):
-            stop = start + mytype.bytes - 1
-            for i in range(mytype.bytes):
-                tmp[i] = bytes[start + i]
-            for i in range(mytype.bytes):
-                bytes[stop - i] = tmp[i]
-        self._charbuf_stop()
-
-    def repr__Array(space, self):
-        if self.len == 0:
-            return space.wrap("array('%s')" % self.typecode)
-        elif self.typecode == "c":
-            r = space.repr(array_tostring__Array(space, self))
-            s = "array('%s', %s)" % (self.typecode, space.str_w(r))
-            return space.wrap(s)
-        elif self.typecode == "u":
-            r = space.repr(array_tounicode__Array(space, self))
-            s = "array('%s', %s)" % (self.typecode, space.str_w(r))
-            return space.wrap(s)
-        else:
-            r = space.repr(array_tolist__Array(space, self))
-            s = "array('%s', %s)" % (self.typecode, space.str_w(r))
-            return space.wrap(s)
-
     mytype.w_class = W_Array
-
-    # Annotator seems to mess up if the names are not unique
+    W_Array.constructor = W_Array
     name = 'ArrayType' + mytype.typecode
     W_Array.__name__ = 'W_' + name
-    import re
-    for n, f in locals().items():
-        new, n = re.subn('_Array_', '_%s_' % name, n)
-        if n > 0:
-            f.__name__ = new
-
-    from pypy.objspace.std.sliceobject import W_SliceObject
-    from pypy.objspace.std.listobject import W_ListObject
-    from pypy.objspace.std.unicodeobject import W_UnicodeObject
-    register_all(locals(), globals())
-
 
 for mytype in types.values():
     make_array(mytype)
-
-register_all(locals(), globals())
+del mytype
diff --git a/pypy/module/array/test/test_array.py b/pypy/module/array/test/test_array.py
--- a/pypy/module/array/test/test_array.py
+++ b/pypy/module/array/test/test_array.py
@@ -19,7 +19,7 @@
 
 class BaseArrayTests:
 
-    
+
     def test_ctor(self):
         assert len(self.array('c')) == 0
         assert len(self.array('i')) == 0
@@ -390,7 +390,6 @@
         assert self.array('c', ('h', 'i')).tostring() == 'hi'
         a = self.array('i', [0, 0, 0])
         assert a.tostring() == '\x00' * 3 * a.itemsize
-
         s = self.array('i', [1, 2, 3]).tostring()
         assert '\x00' in s
         assert '\x01' in s
@@ -502,7 +501,7 @@
                 return 0
         class incomparable(object):
             pass
-        
+
         for v1, v2, tt in (([1, 2, 3], [1, 3, 2], 'bhilBHIL'),
                          ('abc', 'acb', 'c'),
                          (unicode('abc'), unicode('acb'), 'u')):
@@ -653,14 +652,14 @@
         raises(TypeError, "a * 'hi'")
         raises(TypeError, "'hi' * a")
         raises(TypeError, "a *= 'hi'")
-        
+
         class mulable(object):
             def __mul__(self, other):
                 return "mul"
 
             def __rmul__(self, other):
                 return "rmul"
-        
+
         assert mulable() * self.array('i') == 'mul'
         assert self.array('i') * mulable() == 'rmul'
 
@@ -769,7 +768,7 @@
 
             def __getitem__(self, i):
                 return array.__getitem__(self, self._index(i))
-            
+
             def __setitem__(self, i, val):
                 return array.__setitem__(self, self._index(i), val)
 
@@ -783,7 +782,7 @@
 
         assert img[3, 25] == 3 * 9
 
-                
+
     def test_override_from(self):
         class mya(self.array):
             def fromlist(self, lst):
@@ -854,7 +853,7 @@
     def test_subclass_del(self):
         import array, gc, weakref
         l = []
-        
+
         class A(array.array):
             pass
 
diff --git a/pypy/module/array/test/test_ztranslation.py b/pypy/module/array/test/test_ztranslation.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/array/test/test_ztranslation.py
@@ -0,0 +1,6 @@
+
+from pypy.objspace.fake.checkmodule import checkmodule
+
+def test_checkmodule():
+    checkmodule('array')
+
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -544,37 +544,38 @@
 def make_wrapper(space, callable):
     "NOT_RPYTHON"
     names = callable.api_func.argnames
-    argtypes_enum_ui = unrolling_iterable(enumerate(zip(callable.api_func.argtypes,
-        [name.startswith("w_") for name in names])))
+    argtypes = callable.api_func.argtypes
+    is_wrapped_list = [name.startswith("w_") for name in names]
     fatal_value = callable.api_func.restype._defl()
 
-    @specialize.ll()
-    def wrapper(*args):
+    lines = []
+    for i, (argtype, is_wrapped) in enumerate(zip(argtypes, is_wrapped_list)):
+        if is_PyObject(argtype) and is_wrapped:
+            new_lines = [
+                'if %(arg)s:',
+                '    %(arg)s = from_ref(space, rffi.cast(PyObject, %(arg)s))',
+                'else:',
+                '    %(arg)s = None',
+            ]
+            for j in range(len(new_lines)):
+                new_lines[j] = new_lines[j] % {'arg': 'arg%d' % i}
+            lines += new_lines
+    middle = '\n            '.join(lines)
+    arg_spec = ", ".join(["arg%d" % i for i in range(len(argtypes))])
+
+    source = py.code.Source("""
+    def wrapper(%(args)s):
         from pypy.module.cpyext.pyobject import make_ref, from_ref
         from pypy.module.cpyext.pyobject import Reference
-        # we hope that malloc removal removes the newtuple() that is
-        # inserted exactly here by the varargs specializer
-        rffi.stackcounter.stacks_counter += 1
-        llop.gc_stack_bottom(lltype.Void)   # marker for trackgcroot.py
         retval = fatal_value
         boxed_args = ()
         try:
             if not we_are_translated() and DEBUG_WRAPPER:
                 print >>sys.stderr, callable,
-            assert len(args) == len(callable.api_func.argtypes)
-            for i, (typ, is_wrapped) in argtypes_enum_ui:
-                arg = args[i]
-                if is_PyObject(typ) and is_wrapped:
-                    if arg:
-                        arg_conv = from_ref(space, rffi.cast(PyObject, arg))
-                    else:
-                        arg_conv = None
-                else:
-                    arg_conv = arg
-                boxed_args += (arg_conv, )
             state = space.fromcache(State)
+            %(middle)s
             try:
-                result = callable(space, *boxed_args)
+                result = callable(space, %(args)s)
                 if not we_are_translated() and DEBUG_WRAPPER:
                     print >>sys.stderr, " DONE"
             except OperationError, e:
@@ -596,8 +597,8 @@
             if failed:
                 error_value = callable.api_func.error_value
                 if error_value is CANNOT_FAIL:
-                    raise SystemError("The function '%s' was not supposed to fail"
-                                      % (callable.__name__,))
+                    raise SystemError("The function '%%s' was not supposed to fail"
+                                      %% (callable.__name__,))
                 retval = error_value
 
             elif is_PyObject(callable.api_func.restype):
@@ -624,8 +625,13 @@
             else:
                 print str(e)
                 pypy_debug_catch_fatal_exception()
-        rffi.stackcounter.stacks_counter -= 1
         return retval
+    """ % {"middle": middle, "args": arg_spec})
+    d = {}
+    d.update(locals())
+    d.update(globals())
+    exec source.compile() in d
+    wrapper = d['wrapper']
     callable._always_inline_ = 'try'
     wrapper.__name__ = "wrapper for %r" % (callable, )
     return wrapper
@@ -1023,7 +1029,7 @@
         export_struct(name, struct)
 
     for name, func in FUNCTIONS.iteritems():
-        deco = entrypoint("cpyext", func.argtypes, name, relax=True)
+        deco = entrypoint("cpyext", func.argtypes, name)
         deco(func.get_wrapper(space))
 
     setup_init_functions(eci, translating=True)
diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py
--- a/pypy/module/micronumpy/__init__.py
+++ b/pypy/module/micronumpy/__init__.py
@@ -12,6 +12,7 @@
         'zeros': 'interp_numarray.zeros',
         'empty': 'interp_numarray.zeros',
         'ones': 'interp_numarray.ones',
+        '_reconstruct' : 'interp_numarray._reconstruct',
         'dot': 'interp_arrayops.dot',
         'fromstring': 'interp_support.fromstring',
         'flatiter': 'interp_flatiter.W_FlatIterator',
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
@@ -13,6 +13,7 @@
      raw_storage_setitem, RAW_STORAGE
 from pypy.module.micronumpy.arrayimpl.sort import argsort_array
 from rpython.rlib.debug import make_sure_not_resized
+from pypy.interpreter.special import Ellipsis
 
 
 class BaseConcreteArray(base.BaseArrayImplementation):
@@ -55,6 +56,9 @@
     def get_size(self):
         return self.size // self.dtype.itemtype.get_element_size()
 
+    def get_storage_size(self):
+        return self.size
+
     def reshape(self, space, orig_array, new_shape):
         # Since we got to here, prod(new_shape) == self.size
         new_strides = None
@@ -154,6 +158,7 @@
         """
         if (space.isinstance_w(w_idx, space.w_str) or
             space.isinstance_w(w_idx, space.w_slice) or
+            isinstance(w_idx, Ellipsis) or
             space.is_w(w_idx, space.w_None)):
             raise IndexError
         if isinstance(w_idx, W_NDimArray) and not isinstance(w_idx.implementation, scalar.Scalar):
@@ -200,7 +205,7 @@
         if (space.isinstance_w(w_idx, space.w_int) or
             space.isinstance_w(w_idx, space.w_slice)):
             return Chunks([Chunk(*space.decode_index4(w_idx, self.get_shape()[0]))])
-        elif space.is_w(w_idx, space.w_None):
+        elif space.is_w(w_idx, space.w_None) or isinstance(w_idx, Ellipsis):
             return Chunks([NewAxisChunk()])
         result = []
         i = 0
@@ -328,13 +333,14 @@
 
 
 class ConcreteArray(ConcreteArrayNotOwning):
-    def __init__(self, shape, dtype, order, strides, backstrides):
-        # we allocate the actual storage later because we need to compute
-        # self.size first
+    def __init__(self, shape, dtype, order, strides, backstrides, storage=lltype.nullptr(RAW_STORAGE)):
         null_storage = lltype.nullptr(RAW_STORAGE)
         ConcreteArrayNotOwning.__init__(self, shape, dtype, order, strides, backstrides,
                                         null_storage)
-        self.storage = dtype.itemtype.malloc(self.size)
+        if storage == lltype.nullptr(RAW_STORAGE):
+            self.storage = dtype.itemtype.malloc(self.size)
+        else:
+            self.storage = storage
 
     def __del__(self):
         free_raw_storage(self.storage, track_allocation=False)
diff --git a/pypy/module/micronumpy/arrayimpl/scalar.py b/pypy/module/micronumpy/arrayimpl/scalar.py
--- a/pypy/module/micronumpy/arrayimpl/scalar.py
+++ b/pypy/module/micronumpy/arrayimpl/scalar.py
@@ -3,6 +3,7 @@
 from pypy.module.micronumpy.base import W_NDimArray, convert_to_array
 from pypy.module.micronumpy import support
 from pypy.interpreter.error import OperationError
+from pypy.interpreter.special import Ellipsis
 
 class ScalarIterator(base.BaseArrayIterator):
     def __init__(self, v):
@@ -73,7 +74,7 @@
         dtype = self.dtype.float_type or self.dtype
         if len(w_arr.get_shape()) > 0:
             raise OperationError(space.w_ValueError, space.wrap(
-                "could not broadcast input array from shape " + 
+                "could not broadcast input array from shape " +
                 "(%s) into shape ()" % (
                     ','.join([str(x) for x in w_arr.get_shape()],))))
         if self.dtype.is_complex_type():
@@ -102,7 +103,7 @@
         dtype = self.dtype.float_type
         if len(w_arr.get_shape()) > 0:
             raise OperationError(space.w_ValueError, space.wrap(
-                "could not broadcast input array from shape " + 
+                "could not broadcast input array from shape " +
                 "(%s) into shape ()" % (
                     ','.join([str(x) for x in w_arr.get_shape()],))))
         self.value = self.dtype.itemtype.composite(
@@ -119,7 +120,10 @@
                              space.wrap("scalars cannot be indexed"))
 
     def descr_setitem(self, space, _, w_idx, w_val):
-        raise OperationError(space.w_IndexError,
+        if isinstance(w_idx, Ellipsis):
+            self.value = self.dtype.coerce(space, w_val)
+        else:
+            raise OperationError(space.w_IndexError,
                              space.wrap("scalars cannot be indexed"))
 
     def setitem_index(self, space, idx, w_val):
diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py
--- a/pypy/module/micronumpy/base.py
+++ b/pypy/module/micronumpy/base.py
@@ -35,12 +35,17 @@
         return W_NDimArray(impl)
 
     @staticmethod
-    def from_shape_and_storage(shape, storage, dtype, order='C'):
+    def from_shape_and_storage(shape, storage, dtype, order='C', owning=False):
         from pypy.module.micronumpy.arrayimpl import concrete
         assert shape
         strides, backstrides = calc_strides(shape, dtype, order)
-        impl = concrete.ConcreteArrayNotOwning(shape, dtype, order, strides,
-                                               backstrides, storage)
+        if owning:
+            # Will free storage when GCd
+            impl = concrete.ConcreteArray(shape, dtype, order, strides,
+                                                backstrides, storage=storage)
+        else:
+            impl = concrete.ConcreteArrayNotOwning(shape, dtype, order, strides,
+                                                backstrides, storage)
         return W_NDimArray(impl)
 
     @staticmethod
diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py
--- a/pypy/module/micronumpy/compile.py
+++ b/pypy/module/micronumpy/compile.py
@@ -58,7 +58,8 @@
     w_str = "str"
     w_unicode = "unicode"
     w_complex = "complex"
-    
+    w_dict = "dict"
+
     def __init__(self):
         """NOT_RPYTHON"""
         self.fromcache = InternalSpaceCache(self).getorbuild
@@ -115,9 +116,13 @@
     def newcomplex(self, r, i):
         return ComplexObject(r, i)
 
-    def listview(self, obj):
+    def listview(self, obj, number=-1):
         assert isinstance(obj, ListObject)
+        if number != -1:
+            assert number == 2
+            return [obj.items[0], obj.items[1]]
         return obj.items
+
     fixedview = listview
 
     def float(self, w_obj):
@@ -480,7 +485,7 @@
                 w_res = neg.call(interp.space, [arr])
             elif self.name == "cos":
                 cos = interp_ufuncs.get(interp.space).cos
-                w_res = cos.call(interp.space, [arr])                
+                w_res = cos.call(interp.space, [arr])
             elif self.name == "flat":
                 w_res = arr.descr_get_flatiter(interp.space)
             elif self.name == "argsort":
diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py
--- a/pypy/module/micronumpy/interp_dtype.py
+++ b/pypy/module/micronumpy/interp_dtype.py
@@ -133,11 +133,46 @@
                                                                  space.wrap(offset)]))
         return w_d
 
+    def set_fields(self, space, w_fields):
+        if w_fields == space.w_None:
+            self.fields = None
+        else:
+            ofs_and_items = []
+            size = 0
+            for key in space.listview(w_fields):
+                value = space.getitem(w_fields, key)
+
+                dtype = space.getitem(value, space.wrap(0))
+                assert isinstance(dtype, W_Dtype)
+
+                offset = space.int_w(space.getitem(value, space.wrap(1)))
+                self.fields[space.str_w(key)] = offset, dtype
+
+                ofs_and_items.append((offset, dtype.itemtype))
+                size += dtype.itemtype.get_element_size()
+
+            self.itemtype = types.RecordType(ofs_and_items, size)
+            self.name = "void" + str(8 * self.itemtype.get_element_size())
+
     def descr_get_names(self, space):
         if self.fieldnames is None:
             return space.w_None
         return space.newtuple([space.wrap(name) for name in self.fieldnames])
 
+    def set_names(self, space, w_names):
+        if w_names == space.w_None:
+            self.fieldnames = None
+        else:
+            self.fieldnames = []
+            iter = space.iter(w_names)
+            while True:
+                try:
+                    self.fieldnames.append(space.str_w(space.next(iter)))
+                except OperationError, e:
+                    if not e.match(space, space.w_StopIteration):
+                        raise
+                    break
+
     @unwrap_spec(item=str)
     def descr_getitem(self, space, item):
         if self.fields is None:
@@ -180,6 +215,51 @@
     def get_size(self):
         return self.itemtype.get_element_size()
 
+    def descr_reduce(self, space):
+        w_class = space.type(self)
+
+        kind = self.kind
+        elemsize = self.itemtype.get_element_size()
+        builder_args = space.newtuple([space.wrap("%s%d" % (kind, elemsize)), space.wrap(0), space.wrap(1)])
+
+        version = space.wrap(3)
+        order = space.wrap(byteorder_prefix if self.native else nonnative_byteorder_prefix)
+        names = self.descr_get_names(space)
+        values = self.descr_get_fields(space)
+        if self.fields:
+            #TODO: Implement this when subarrays are implemented
+            subdescr = space.w_None
+            #TODO: Change this when alignment is implemented :
+            size = 0
+            for key in self.fields:
+                dtype = self.fields[key][1]
+                assert isinstance(dtype, W_Dtype)
+                size += dtype.get_size()
+            w_size = space.wrap(size)
+            alignment = space.wrap(1)
+        else:
+            subdescr = space.w_None
+            w_size = space.wrap(-1)
+            alignment = space.wrap(-1)
+        flags = space.wrap(0)
+
+        data = space.newtuple([version, order, subdescr, names, values, w_size, alignment, flags])
+
+        return space.newtuple([w_class, builder_args, data])
+
+    def descr_setstate(self, space, w_data):
+        if space.int_w(space.getitem(w_data, space.wrap(0))) != 3:
+            raise OperationError(space.w_NotImplementedError, space.wrap("Pickling protocol version not supported"))
+
+        self.native = space.str_w(space.getitem(w_data, space.wrap(1))) == byteorder_prefix
+
+        fieldnames = space.getitem(w_data, space.wrap(3))
+        self.set_names(space, fieldnames)
+
+        fields = space.getitem(w_data, space.wrap(4))
+        self.set_fields(space, fields)
+        print self.itemtype
+
 class W_ComplexDtype(W_Dtype):
     def __init__(self, itemtype, num, kind, name, char, w_box_type,
                  alternate_constructors=[], aliases=[],
@@ -238,8 +318,7 @@
         num = 20
         basename = 'void'
         w_box_type = space.gettypefor(interp_boxes.W_VoidBox)
-        raise OperationError(space.w_NotImplementedError, space.wrap(
-            "pure void dtype"))
+        return dtype_from_list(space, space.newlist([]))
     else:
         assert char == 'U'
         basename = 'unicode'
@@ -252,9 +331,10 @@
 
 def dtype_from_spec(space, name):
         raise OperationError(space.w_NotImplementedError, space.wrap(
-            "dtype from spec"))    
+            "dtype from spec"))
 
-def descr__new__(space, w_subtype, w_dtype):
+def descr__new__(space, w_subtype, w_dtype, w_align=None, w_copy=None):
+    # w_align and w_copy are necessary for pickling
     cache = get_dtype_cache(space)
 
     if space.is_none(w_dtype):
@@ -297,6 +377,9 @@
     __ne__ = interp2app(W_Dtype.descr_ne),
     __getitem__ = interp2app(W_Dtype.descr_getitem),
 
+    __reduce__ = interp2app(W_Dtype.descr_reduce),
+    __setstate__ = interp2app(W_Dtype.descr_setstate),
+
     num = interp_attrproperty("num", cls=W_Dtype),
     kind = interp_attrproperty("kind", cls=W_Dtype),
     char = interp_attrproperty("char", cls=W_Dtype),
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
@@ -20,6 +20,7 @@
 from rpython.rlib import jit
 from rpython.rlib.rstring import StringBuilder
 from pypy.module.micronumpy.arrayimpl.base import BaseArrayImplementation
+from pypy.interpreter.special import Ellipsis
 
 def _find_shape(space, w_size):
     if space.is_none(w_size):
@@ -167,6 +168,8 @@
                                prefix)
 
     def descr_getitem(self, space, w_idx):
+        if isinstance(w_idx, Ellipsis):
+            return self
         if (isinstance(w_idx, W_NDimArray) and
             w_idx.get_dtype().is_bool_type()):
             return self.getitem_filter(space, w_idx)
@@ -781,6 +784,42 @@


More information about the pypy-commit mailing list