[Jython-checkins] jython: bytearray: increment including comparison operations, __add__, append, find

frank.wierzbicki jython-checkins at python.org
Wed May 23 19:21:27 CEST 2012


http://hg.python.org/jython/rev/f09dfd68d9e4
changeset:   6664:f09dfd68d9e4
user:        Jeff Allen <ja...py at farowl.co.uk>
date:        Fri May 18 09:30:33 2012 +0100
summary:
  bytearray: increment including comparison operations, __add__, append, find

This increment includes _eq__, __ne__ and so on (which makes Python unit test work), and some of the basic Python API. In the absence of a memory buffer equivalent, BaseBytes provides a wrapper that permits bytearray operations to accept str arguments. test_bytes.py currently produces 4 fail and 70 error results. There are also improved JUnit tests to cover slice deletion.

files:
  src/org/python/core/BaseBytes.java              |  1200 ++++-
  src/org/python/core/PyByteArray.java            |  1069 ++-
  src/org/python/core/PyByteArrayDerived.java     |  2232 +++++-----
  tests/java/org/python/core/BaseBytesTest.java   |    61 +-
  tests/java/org/python/core/PyByteArrayTest.java |   921 +++-
  5 files changed, 3616 insertions(+), 1867 deletions(-)


diff --git a/src/org/python/core/BaseBytes.java b/src/org/python/core/BaseBytes.java
--- a/src/org/python/core/BaseBytes.java
+++ b/src/org/python/core/BaseBytes.java
@@ -9,28 +9,31 @@
 
 /**
  * Base class for Jython bytearray (and bytes in due course) that provides most of the Java API,
- * including Java List behaviour. Attempts to modify the contents through this API will throw
- * a TypeError if the actual type of the object is not mutable.
+ * including Java List behaviour. Attempts to modify the contents through this API will throw a
+ * TypeError if the actual type of the object is not mutable.
  * <p>
- * It is possible for a Java client to treat this class as a <tt>List&lt;PyInteger></tt>,
- * obtaining equivalent functionality to the Python interface in a Java paradigm.
- * The reason 
- * {@link }
- * <p>Subclasses must define (from {@link PySequence}): <ul>
+ * It is possible for a Java client to treat this class as a <tt>List&lt;PyInteger></tt>, obtaining
+ * equivalent functionality to the Python interface in a Java paradigm. The reason {@link }
+ * <p>
+ * Subclasses must define (from {@link PySequence}):
+ * <ul>
  * <li>{@link #getslice(int, int, int)}</li>
  * <li>{@link #repeat(int)}</li>
- * </ul>each returning an appropriate concrete type. Mutable subclasses should override:<ul>
+ * </ul>
+ * each returning an appropriate concrete type. Mutable subclasses should override:
+ * <ul>
  * <li>{@link #pyset(int, PyObject)}</li>
  * <li>{@link #setslice(int, int, int, PyObject)}</li>
  * <li>{@link #del(int)}</li>
  * <li>{@link #delRange(int, int)}</li>
- * </ul> 
+ * </ul>
  * since the default implementations will otherwise throw an exception.
  */
 public abstract class BaseBytes extends PySequence implements MemoryViewProtocol, List<PyInteger> {
-    
+
     /**
      * Simple constructor of empty zero-length array of defined type.
+     *
      * @param type explicit Jython type
      */
     public BaseBytes(PyType type) {
@@ -40,17 +43,18 @@
 
     /**
      * Simple constructor of zero-filled array of defined size and type.
+     *
      * @param size required
      * @param type explicit Jython type
      */
     public BaseBytes(PyType type, int size) {
         super(type);
-        newStorage( size );
+        newStorage(size);
     }
 
     /**
      * Construct byte array of defined type by copying values from int[].
-     * 
+     *
      * @param type explicit Jython type
      * @param value source of values (and size)
      */
@@ -58,14 +62,15 @@
         super(type);
         int n = value.length;
         newStorage(n);
-        for (int i = offset, j = 0; j < n; i++, j++)      // Note offset may be non-zero
+        for (int i = offset, j = 0; j < n; i++, j++) {
             storage[i] = byteCheck(value[j]);
+        }
     }
 
     /**
      * Construct byte array of defined type by copying character values from a String. These values
      * have to be in the Python byte range 0 to 255.
-     * 
+     *
      * @param type explicit Jython type
      * @param value source of characters
      * @throws PyException if any value[i] > 255
@@ -74,17 +79,17 @@
         super(type);
         int n = value.length();
         newStorage(n);
-        int i = offset + size;
-        while (n > 0)
-            storage[--i] = byteCheck(value.charAt(--n));
-    }   
-    
+        for (int i = offset, j = 0; j < n; j++) {
+            storage[i++] = byteCheck(value.charAt(j));
+        }
+    }
+
     /**
      * Helper for constructors and methods that manipulate the storage in mutable subclasses. It
      * also permits shared storage between objects, which in general is unsafe if the storage is
      * subject to modification independent of the object now being created. Immutable types may
      * share storage (safely).
-     * 
+     *
      * @param storage byte array allocated by client
      * @param size number of bytes actually used
      * @param offset index of first byte used
@@ -102,9 +107,9 @@
     }
 
     /**
-     * Helper for constructors and methods that manipulate the storage in mutable subclassesin the
+     * Helper for constructors and methods that manipulate the storage in mutable subclasses in the
      * case where the storage should consist of the first part of the given array.
-     * 
+     *
      * @param storage byte array allocated by client
      * @param size number of bytes actually used
      * @throws IllegalArgumentException if the range [0:size] is not within the array bounds of
@@ -123,7 +128,7 @@
     /**
      * Helper for constructors and methods that manipulate the storage in mutable subclasses in the
      * case where the storage should consist of exactly the whole of the given array.
-     * 
+     *
      * @param storage byte array allocated by client
      */
     protected void setStorage(byte[] storage) {
@@ -132,23 +137,25 @@
         this.offset = 0;
     }
 
-
     /*
      * ========================================================================================
      * Support for memoryview
      * ========================================================================================
-     * 
+     *
      * This is present in order to facilitate development of PyMemoryView which a full
      * implementation of bytearray would depend on, while at the same time a full implementation of
      * memoryview depends on bytearray.
      */
     /**
      * Get hold of a <code>memoryview</code> on the current byte array.
+     *
      * @see MemoryViewProtocol#getMemoryView()
      */
     @Override
     public MemoryView getMemoryView() {
-        if (mv == null) mv = new MemoryViewImpl();
+        if (mv == null) {
+            mv = new MemoryViewImpl();
+        }
         return mv;
     }
 
@@ -198,23 +205,22 @@
         }
 
     }
-    
-    
+
     /*
      * ========================================================================================
      * Support for construction and initialisation
      * ========================================================================================
-     * 
+     *
      * Methods here help subclasses set the initial state. They are designed with bytearray in mind,
      * but note that from Python 3, bytes() has the same set of calls and behaviours, although in
-     * Peterson's "sort of backport" to Python 2.x, bytes is effectively an alias for str and
-     * it shows.
+     * Peterson's "sort of backport" to Python 2.x, bytes is effectively an alias for str and it
+     * shows.
      */
 
     /**
      * Helper for <code>__new__</code> and <code>__init__</code> and the Java API constructor from
      * PyObject in subclasses.
-     * 
+     *
      * @see org.python.core.ByteArray#bytearray___init__(PyObject[], String[])
      * @see org.python.core.ByteArray#ByteArray(PyObject)
      * @param arg primary argument from which value is taken
@@ -268,7 +274,7 @@
     /**
      * Helper for <code>__new__</code> and <code>__init__</code> and the Java API constructor from a
      * text string with the specified encoding in subclasses.
-     * 
+     *
      * @see #bytearray___init__(PyObject[], String[])
      * @see PyByteArray#PyByteArray(PyString, String, String)
      * @param arg primary argument from which value is taken
@@ -284,7 +290,7 @@
     /**
      * Helper for <code>__new__</code> and <code>__init__</code> and the Java API constructor from a
      * text string with the specified encoding in subclasses.
-     * 
+     *
      * @see #bytearray___init__(PyObject[], String[])
      * @see PyByteArray#PyByteArray(PyString, String, String)
      * @param arg primary argument from which value is taken
@@ -298,14 +304,12 @@
         setBytes(0, encoded);
     }
 
-
     /**
-     * Helper for {@linkplain #setslice(int, int, int, PyObject)},
-     * for <code>__new__</code> and <code>__init__</code> and the Java API constructor from a
-     * text string with the specified encoding in subclasses. This method thinly wraps a call to
-     * the codecs module and deals with checking
-     * for PyUnicode (where the encoding argument is mandatory).
-     * 
+     * Helper for {@linkplain #setslice(int, int, int, PyObject)}, for <code>__new__</code> and
+     * <code>__init__</code> and the Java API constructor from a text string with the specified
+     * encoding in subclasses. This method thinly wraps a call to the codecs module and deals with
+     * checking for PyUnicode (where the encoding argument is mandatory).
+     *
      * @see #ByteArray(PyString, String, String)
      * @param arg primary argument from which value is taken
      * @param encoding name of optional encoding
@@ -319,25 +323,24 @@
 
         if (arg instanceof PyUnicode) {
             if (encoding != null) {
-                encoded = codecs.encode((PyUnicode)arg, encoding, errors);
+                encoded = codecs.encode(arg, encoding, errors);
             } else {
                 throw Py.TypeError("unicode argument without an encoding");
             }
         } else {
             if (encoding != null) {
-                encoded = codecs.encode((PyString)arg, encoding, errors);
+                encoded = codecs.encode(arg, encoding, errors);
             } else {
-                encoded = ((PyString)arg).getString();
+                encoded = arg.getString();
             }
         }
         return encoded;
     }
 
-
     /**
      * Fill a defined section of a byte array by copying character values from a String. These
      * values have to be in the Python byte range 0 to 255.
-     * 
+     *
      * @param start index in this byte array at which the first character code lands
      * @param value source of characters
      * @throws PyException(ValueError) if any value[i] > 255
@@ -345,14 +348,15 @@
     protected void setBytes(int start, String value) throws PyException {
         int n = value.length();
         int io = offset + start;
-        for (int j = 0; j < n; j++)
+        for (int j = 0; j < n; j++) {
             storage[io++] = byteCheck(value.charAt(j));
+        }
     }
 
     /**
      * Fill a strided slice of a byte array by copying character values from a String. These values
      * have to be in the Python byte range 0 to 255.
-     * 
+     *
      * @param start index in this byte array at which the first character code lands
      * @param value source of characters
      * @throws PyException(ValueError) if any value[i] > 255
@@ -365,12 +369,11 @@
             io += step;
         }
     }
-    
 
     /**
      * Helper for <code>__new__</code> and <code>__init__</code> and the Java API constructor from
      * int in subclasses. Construct zero-filled bytearray of specified size.
-     * 
+     *
      * @param n size of zero-filled array
      */
     protected void init(int n) {
@@ -383,7 +386,7 @@
     /**
      * Helper for <code>__new__</code> and <code>__init__</code> and the Java API constructor from
      * objects supporting the Jython implementation of PEP 3118 (memoryview) in subclasses.
-     * 
+     *
      * @param value a memoryview object consistent with the slice assignment
      * @throws PyException(NotImplementedError) until memoryview is properly supported
      * @throws PyException(TypeError) if the memoryview is not byte-oriented
@@ -405,7 +408,7 @@
     /**
      * Helper for <code>__new__</code> and <code>__init__</code> and the Java API constructor from
      * bytearray or bytes in subclasses.
-     * 
+     *
      * @param source bytearray (or bytes) to copy
      */
     protected void init(BaseBytes source) {
@@ -416,7 +419,7 @@
     /**
      * Helper for <code>__new__</code> and <code>__init__</code> and the Java API constructor from
      * an arbitrary iterable Python type in subclasses. This will include generators and lists.
-     * 
+     *
      * @param iter iterable source of values to enter in the array
      */
     protected void init(Iterable<? extends PyObject> iter) {
@@ -426,33 +429,31 @@
          */
         FragmentList fragList = new FragmentList();
         fragList.loadFrom(iter);
-        
+
         // Now, aggregate all those fragments.
         //
-        if (fragList.totalCount>0) {
-            
-            if (fragList.size()==1) {
+        if (fragList.totalCount > 0) {
+
+            if (fragList.size() == 1) {
                 // Note that the first fragment is small: negligible waste if stolen directly.
                 Fragment frag = fragList.getFirst();
                 setStorage(frag.storage, frag.count);
-                
+
             } else {
                 // Stitch the fragments together in new storage of sufficient size
                 newStorage(fragList.totalCount);
                 fragList.emptyInto(storage, offset);
             }
-            
-        } else
+
+        } else {
             // Nothing in the iterator
             setStorage(emptyStorage);
+        }
     }
 
-    
-
-    
     /**
-     * Intended as a fragment of temporary storage for use we do not know how many bytes of allocate, and we are
-     * reading in some kind of iterable stream.
+     * Intended as a fragment of temporary storage for use we do not know how many bytes of
+     * allocate, and we are reading in some kind of iterable stream.
      */
     protected static class Fragment {
 
@@ -472,7 +473,7 @@
             return count == storage.length;
         }
     }
-    
+
     /**
      * A container of temporary storage when we do not know how many bytes to allocate, and we are
      * reading in some kind of iterable stream.
@@ -486,7 +487,7 @@
 
         /**
          * Load bytes into the container from the given iterable
-         * 
+         *
          * @param iter iterable source of values to enter into the container
          * @throws PyException(TypeError) if any value not acceptable type
          * @throws PyException(ValueError) if any value<0 or value>255 or string length!=1
@@ -522,8 +523,9 @@
         }
 
         /**
-         * Move the contents of this container to the given byte array at the specified index.
-         * This method leaves this container empty.
+         * Move the contents of this container to the given byte array at the specified index. This
+         * method leaves this container empty.
+         *
          * @param target destination array
          * @param p position to write first byte
          */
@@ -543,7 +545,7 @@
          * we run out. (You must have checked beforehand that the destination is big enough.) This
          * method leaves this container empty. If the step size is one, it would be much quicker to
          * call {@link BaseBytes#emptyInto(byte[], int)}
-         * 
+         *
          * @param target destination array
          * @param start position to write first byte
          * @param step amount to advance index with each byte
@@ -561,39 +563,39 @@
         }
 
     }
-    
-    
-    
-    /* ========================================================================================
+
+    /*
+     * ========================================================================================
      * Sharable storage
      * ========================================================================================
-     * 
-     * The storage is provided by a byte array that may be somewhat larger than the number of
-     * bytes actually stored, and these bytes may begin at an offset within the storage.
-     * Immutable subclasses of BaseBytes may exploit this to share storage when 
-     * constructed from a slice of another immutable subclass. Mutable subclasses may exploit it
-     * to provide efficient insertions near the start of the array.
+     *
+     * The storage is provided by a byte array that may be somewhat larger than the number of bytes
+     * actually stored, and these bytes may begin at an offset within the storage. Immutable
+     * subclasses of BaseBytes may exploit this to share storage when constructed from a slice of
+     * another immutable subclass. Mutable subclasses may exploit it to provide efficient insertions
+     * near the start of the array.
      */
-    
+
     /** Empty storage constant */
     protected static final byte[] emptyStorage = new byte[0];
-    
+
     /** Storage array. */
-    protected byte[] storage;
-    
+    protected byte[] storage = emptyStorage;
+
     /** Number of bytes actually used in storage array. */
-    protected int size;
+    protected int size = 0;
 
     /** Index of first byte used in storage array. */
-    protected int offset;
+    protected int offset = 0;
 
     /**
      * Check that an index is within the range of the array, that is <tt>0&lt;=index&lt;size</tt>.
+     *
      * @param index to check
      * @throws PyException(IndexError) if the index is outside the array bounds
      */
     protected final void indexCheck(int index) throws PyException {
-        if (index<0 || index>=size) {
+        if (index < 0 || index >= size) {
             throw Py.IndexError(getType().fastGetName() + " index out of range");
         }
     }
@@ -602,11 +604,11 @@
      * Allocate fresh, zero-filled storage for the requested number of bytes and make that the size.
      * If the size needed is zero, the "storage" allocated is the shared emptyStorage array. The
      * allocated size may be bigger than needed, and the method chooses a value for offset.
-     * 
+     *
      * @param needed becomes the new value of this.size
      */
     protected void newStorage(int needed) {
-        // The implementation for immutable arrays allocates exactly, and with offset zero.
+        // The implementation for immutable arrays allocates only as many bytes as needed.
         if (needed > 0) {
             setStorage(new byte[needed]); // guaranteed zero (by JLS 2ed para 4.5.5)
         } else {
@@ -614,96 +616,955 @@
         }
     }
 
-    
     /**
-     * Check that an integer is suitable for storage in a (Python) byte array,
-     * and convert it to the Java byte value that can be stored there.
-     * (Java bytes run -128..127 whereas Python bytes run 0..255.)
+     * Check that an integer is suitable for storage in a (Python) byte array, and convert it to the
+     * Java byte value that can be stored there. (Java bytes run -128..127 whereas Python bytes run
+     * 0..255.)
+     *
      * @param value to convert.
      * @throws PyException(ValueError) if value<0 or value>255
      */
     protected static final byte byteCheck(int value) throws PyException {
-        if (value<0 || value>=255) {
+        if (value < 0 || value > 255) {
             throw Py.ValueError("byte must be in range(0, 256)");
         }
-        return (byte) value;
+        return (byte)value;
     }
-    
+
     /**
-     * Check that the value of an PyInteger is suitable for storage in a (Python) byte array,
-     * and convert it to the Java byte value that can be stored there.
-     * (Java bytes run -128..127 whereas Python bytes run 0..255.)
+     * Check that the value of an PyInteger is suitable for storage in a (Python) byte array, and
+     * convert it to the Java byte value that can be stored there. (Java bytes run -128..127 whereas
+     * Python bytes run 0..255.)
+     *
      * @param value to convert.
      * @throws PyException(ValueError) if value<0 or value>255
      */
     protected static final byte byteCheck(PyInteger value) throws PyException {
         return byteCheck(value.asInt());
     }
-    
+
     /**
-     * Check that the type and value of a PyObject is suitable for storage in a (Python) byte
-     * array, and convert it to the Java byte value that can be stored there.
-     * (Java bytes run -128..127 whereas Python bytes run 0..255.)
-     * Acceptable types are: <ul>
+     * Check that the type and value of a PyObject is suitable for storage in a (Python) byte array,
+     * and convert it to the Java byte value that can be stored there. (Java bytes run -128..127
+     * whereas Python bytes run 0..255.) Acceptable types are:
+     * <ul>
      * <li>PyInteger in range 0 to 255 inclusive</li>
      * <li>PyLong in range 0 to 255 inclusive</li>
+     * <li>Any type having an __index__() method, in range 0 to 255 inclusive</li>
      * <li>PyString of length 1</li>
      * </ul>
+     *
      * @param value to convert.
      * @throws PyException(TypeError) if not acceptable type
      * @throws PyException(ValueError) if value<0 or value>255 or string length!=1
      */
     protected static final byte byteCheck(PyObject value) throws PyException {
-        if (value instanceof PyInteger || value instanceof PyLong) {
+        if (value.isIndex()) {
             // This will possibly produce Py.OverflowError("long int too large to convert")
-            return byteCheck(value.asInt());
-        } else if (value instanceof PyString) {
+            return byteCheck(value.asIndex());
+        } else if (value.getType() == PyString.TYPE) {
+            // Exactly PyString (not PyUnicode)
             String strValue = ((PyString)value).getString();
             if (strValue.length() != 1) {
                 throw Py.ValueError("string must be of size 1");
             }
             return byteCheck(strValue.charAt(0));
-        } else
+        } else {
             throw Py.TypeError("an integer or string of size 1 is required");
+        }
     }
-    
-    /* ========================================================================================
-     * API for org.python.core.PySequence
+
+    /*
+     * ========================================================================================
+     * Wrapper class to make other objects into byte arrays
+     * ========================================================================================
+     *
+     * In much of the bytearray and bytes API, the "other sequence" argument will accept any type
+     * that supports the buffer protocol, that is, the object can supply a memoryview through which
+     * the value is treated as a byte array. We have not implemented memoryview objects yet, and it
+     * is not clear what the Java API should be. As a temporary expedient, we define here a
+     * byte-oriented view on the key built-in types.
+     */
+
+    interface View {
+
+        /**
+         * Return the indexed byte as a byte
+         *
+         * @param index
+         * @return byte at index
+         */
+        public byte byteAt(int index);
+
+        /**
+         * Return the indexed byte as an unsigned integer
+         *
+         * @param index
+         * @return value of the byte at index
+         */
+        public int intAt(int index);
+
+        /**
+         * Number of bytes in the view: valid indexes are from <code>0</code> to
+         * <code>size()-1</code>.
+         *
+         * @return the size
+         */
+        public int size();
+
+        /**
+         * Return a new view that is a simple slice of this one defined by <code>[start:end]</code>.
+         * <code>Py.None</code> or <code>null</code> are acceptable for start and end, and have
+         * Python slice semantics. Negative values for start or end are treated as "from the end",
+         * in the usual manner of Python slices.
+         *
+         * @param start first element to include
+         * @param end first element after slice, not to include
+         * @return byte-oriented view
+         */
+        public View slice(PyObject start, PyObject end);
+    }
+
+    /**
+     * Some common apparatus for views including the implementation of slice semantics.
+     */
+    static abstract class ViewBase implements View {
+
+        // Implement Python slice semantics
+        public View slice(PyObject ostart, PyObject oend) {
+            PySlice s = new PySlice(ostart, oend, null);
+            int[] index = s.indicesEx(size());  // [ start, end, 1, end-start ]
+            return sliceImpl(index[0], index[(index[3] > 0) ? 1 : 0]);
+        }
+
+        /**
+         * Implementation-specific part of returning a slice of the current view. This is called by
+         * the default implementations of {@link #slice(int, int)} and
+         * {@link #slice(PyObject, PyObject)} once the <code>start</code> and <code>end</code>
+         * arguments have been reduced to simple integer indexes. It is guaranteed that
+         * <code>start>=0</code> and <code>size()>=end>=start</code> when the method is called.
+         * Implementors are encouraged to do something more efficient than piling on anothe wrapper.
+         *
+         * @param start first element to include
+         * @param end first element after slice, not to include
+         * @return byte-oriented view
+         */
+        protected abstract View sliceImpl(int start, int end);
+
+    }
+
+    /**
+     * Return a wrapper providing a byte-oriented view for whatever object is passed, or return
+     * <code>null</code> if we don't know how.
+     *
+     * @param b object to wrap
+     * @return byte-oriented view or null
+     */
+    protected static View getView(PyObject b) {
+        if (b == null) {
+            return null;
+        } else if (b instanceof BaseBytes) {
+            return new ViewOfBytes((BaseBytes)b);
+        } else if (b.getType() == PyString.TYPE) {
+            return new ViewOfString(b.asString());
+        }
+        return null;
+    }
+
+    /**
+     * Return a wrapper providing a byte-oriented view for a slice of whatever object is passed, or
+     * return <code>null</code> if we don't know how.
+     *
+     * @param b object to wrap
+     * @param start index of first byte to include
+     * @param end index of first byte after slice
+     * @return byte-oriented view or null
+     */
+    protected static View getView(PyObject b, PyObject start, PyObject end) {
+        View whole = getView(b);
+        if (whole != null) {
+            return whole.slice(start, end);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Return a wrapper providing a byte-oriented view of a slice of this object.
+     *
+     * @param ostart index of first byte to include
+     * @param oend index of first byte after slice
+     * @return byte-oriented view or null
+     */
+    protected ViewOfBytes slice(PyObject ostart, PyObject oend) {
+        PySlice s = new PySlice(ostart, oend, null);
+        int[] index = s.indicesEx(size); // [ start, end, 1, end-start ]
+        return new ViewOfBytes(storage, offset + index[0], index[3]);
+    }
+
+    /**
+     * Return a wrapper providing a byte-oriented view for whatever object is passed, or raise an
+     * exception if we don't know how.
+     *
+     * @param b object to wrap
+     * @return byte-oriented view
+     */
+    protected static View getViewOrError(PyObject b) {
+        View res = getView(b);
+        if (res == null) {
+            // String fmt = "type %s doesn't support the buffer API"; // CPython
+            String fmt = "cannot access type %s as bytes";
+            throw Py.NotImplementedError(String.format(fmt, b.getType().fastGetName()));
+        }
+        return res;
+    }
+
+    /**
+     * Return a wrapper providing a byte-oriented view for a slice of whatever object is passed, or
+     * raise an exception if we don't know how.
+     *
+     * @param b object to wrap
+     * @param start index of first byte to include
+     * @param end index of first byte after slice
+     * @return byte-oriented view or null
+     */
+    protected static View getViewOrError(PyObject b, PyObject start, PyObject end) {
+        View whole = getViewOrError(b);
+        return whole.slice(start, end);
+    }
+
+    /**
+     * Wrapper providing a byte-oriented view for String (or PyString).
+     */
+    protected static class ViewOfString extends ViewBase {
+
+        private String str;
+
+        /**
+         * Create a byte-oriented view of a String.
+         *
+         * @param str
+         */
+        public ViewOfString(String str) {
+            this.str = str;
+        }
+
+        public byte byteAt(int index) {
+            return byteCheck(str.charAt(index));
+        }
+
+        public int intAt(int index) {
+            return str.charAt(index);
+        }
+
+        public int size() {
+            return str.length();
+        }
+
+        public View sliceImpl(int start, int end) {
+            return new ViewOfString(str.substring(start, end));
+        }
+
+    }
+
+    /**
+     * Wrapper providing a byte-oriented view for byte arrays descended from BaseBytes. Not that
+     * this view is not safe against concurrent modification by this or another thread: if the byte
+     * array type is mutable, and the contents change, the contents of the view are likely to be
+     * invalid.
+     */
+    protected static class ViewOfBytes extends ViewBase {
+
+        private byte[] storage;
+        private int offset;
+        private int size;
+
+        /**
+         * Create a byte-oriented view of a byte array descended from BaseBytes.
+         *
+         * @param obj
+         */
+        public ViewOfBytes(BaseBytes obj) {
+            this.storage = obj.storage;
+            this.offset = obj.offset;
+            this.size = obj.size;
+        }
+
+        /**
+         * Create a byte-oriented view of a byte array explicitly. If the size<0, a zero-length
+         * slice results.
+         *
+         * @param storage storage array
+         * @param offset
+         * @param size
+         */
+        ViewOfBytes(byte[] storage, int offset, int size) {
+            if (size > 0) {
+                this.storage = storage;
+                this.offset = offset;
+                this.size = size;
+            } else {
+                this.storage = emptyStorage;
+                this.offset = 0;
+                this.size = 0;
+            }
+        }
+
+        public byte byteAt(int index) {
+            return storage[offset + index];
+        }
+
+        public int intAt(int index) {
+            return 0xff & storage[offset + index];
+        }
+
+        public int size() {
+            return size;
+        }
+
+        public View sliceImpl(int start, int end) {
+            return new ViewOfBytes(storage, offset + start, end - start);
+        }
+    }
+
+    /*
+     * ======================================================================================== API
+     * for org.python.core.PySequence
      * ========================================================================================
      */
     protected PyInteger pyget(int index) {
         return new PyInteger(intAt(index));
     }
-    
-    /* We're not implementing these here, but we can give a stronger guarantee about the return
-     * type and save some casting and type anxiety.
+
+    /*
+     * We're not implementing these here, but we can give a stronger guarantee about the return type
+     * and save some casting and type anxiety.
      */
     protected abstract BaseBytes getslice(int start, int stop, int step);
+
     protected abstract BaseBytes repeat(int count);
-    
+
     /*
      * And this extension point should be overridden in mutable subclasses
      */
-    
+
     /**
      * Insert the element (interpreted as a Python byte value) at the given index. The default
      * implementation produces a Python TypeError, for the benefit of immutable types. Mutable types
      * must override it.
-     * 
+     *
      * @param index to insert at
      * @param element to insert (by value)
      * @throws PyException(IndexError) if the index is outside the array bounds
      * @throws PyException(ValueError) if element<0 or element>255
      * @throws PyException(TypeError) if the subclass is immutable
      */
-    public void pyadd(int index, PyInteger element) {
+    public void pyinsert(int index, PyObject element) {
         // This won't succeed: it just produces the right error.
         // storageReplace(index, 0, 1);
         pyset(index, element);
     }
-    
-    /* ========================================================================================
-     * API for Java access as byte[]
+
+    /*
+     * ========================================================================================
+     * Support for Python API common to mutable and immutable subclasses
+     * ========================================================================================
+     */
+
+    @Override
+    public int __len__() {
+        return size;
+    }
+
+    /**
+     * Comparison function between two byte arrays returning 1, 0, or -1 as a>b, a==b, or a&lt;b
+     * respectively. The comparison is by value, using Python unsigned byte conventions, and
+     * left-to-right (low to high index). Zero bytes are significant, even at the end of the array:
+     * <code>[1,2,3]&lt;[1,2,3,0]</code>, for example and <code>[]</code> is less than every other
+     * value, even <code>[0]</code>.
+     *
+     * @param a left-hand array in the comparison
+     * @param b right-hand array in the comparison
+     * @return 1, 0 or -1 as a>b, a==b, or a&lt;b respectively
+     */
+    private static int compare(BaseBytes a, BaseBytes b) {
+
+        // Compare elements one by one in these ranges:
+        int ap = a.offset;
+        int aEnd = ap + a.size;
+        int bp = b.offset;
+        int bEnd = bp + b.size;
+
+        while (ap < aEnd) {
+            if (bp >= bEnd) {
+                // a is longer than b
+                return 1;
+            } else {
+                // Compare the corresponding bytes (as unsigned ints)
+                int aVal = 0xff & a.storage[ap++];
+                int bVal = 0xff & b.storage[bp++];
+                int diff = aVal - bVal;
+                if (diff != 0) {
+                    return (diff < 0) ? -1 : 1;
+                }
+            }
+        }
+
+        // All the bytes matched and we reached the end of a
+        if (bp < bEnd) {
+            // But we didn't reach the end of b
+            return -1;
+        } else {
+            // And the end of b at the same time, so they're equal
+            return 0;
+        }
+
+    }
+
+// /**
+// * Comparison function between a byte array and a String returning 1, 0 or -1 as a>b, a==b, or
+// * a&lt;b respectively. The comparison is by value, using Python unsigned byte conventions for
+// * the byte array and character code for elements of the string, and left-to-right (low to high
+// * index). Zero bytes are significant, even at the end of the array:
+// * <code>[65,66,67]&lt;"ABC\u0000"</code>, for example and <code>[]</code> is less than every
+// * non-empty String, while <code>[]==""</code>.
+// *
+// * @param a left-hand array in the comparison
+// * @param b right-hand String in the comparison
+// * @return 1, 0 or -1 as a>b, a==b, or a&lt;b respectively
+// */
+// private static int compare(BaseBytes a, String b) {
+//
+// // Compare elements one by one in these ranges:
+// int ap = a.offset;
+// int aEnd = ap + a.size;
+// int bp = 0;
+// int bEnd = b.length();
+//
+// while (ap < aEnd) {
+// if (bp >= bEnd) {
+// // a is longer than b
+// return 1;
+// } else {
+// // Compare the corresponding bytes and character codes
+// int aVal = 0xff & a.storage[ap++];
+// int bVal = b.charAt(bp++);
+// int diff = aVal - bVal;
+// if (diff != 0) {
+// return (diff < 0) ? -1 : 1;
+// }
+// }
+// }
+//
+// // All the bytes matched and we reached the end of a
+// if (bp < bEnd) {
+// // But we didn't reach the end of b
+// return -1;
+// } else {
+// // And the end of b at the same time, so they're equal
+// return 0;
+// }
+//
+// }
+
+    /**
+     * Comparison function between a byte array and a byte-oriented View of some other object, such
+     * as a String, returning 1, 0 or -1 as a>b, a==b, or a&lt;b respectively. The comparison is by
+     * value, using Python unsigned byte conventions, left-to-right (low to high index). Zero bytes
+     * are significant, even at the end of the array: <code>[65,66,67]&lt;"ABC\u0000"</code>, for
+     * example and <code>[]</code> is less than every non-empty b, while <code>[]==""</code>.
+     *
+     * @param a left-hand array in the comparison
+     * @param b right-hand wrapped object in the comparison
+     * @return 1, 0 or -1 as a>b, a==b, or a&lt;b respectively
+     */
+    private static int compare(BaseBytes a, View b) {
+
+        // Compare elements one by one in these ranges:
+        int ap = a.offset;
+        int aEnd = ap + a.size;
+        int bp = 0;
+        int bEnd = b.size();
+
+        while (ap < aEnd) {
+            if (bp >= bEnd) {
+                // a is longer than b
+                return 1;
+            } else {
+                // Compare the corresponding bytes
+                int aVal = 0xff & a.storage[ap++];
+                int bVal = b.intAt(bp++);
+                int diff = aVal - bVal;
+                if (diff != 0) {
+                    return (diff < 0) ? -1 : 1;
+                }
+            }
+        }
+
+        // All the bytes matched and we reached the end of a
+        if (bp < bEnd) {
+            // But we didn't reach the end of b
+            return -1;
+        } else {
+            // And the end of b at the same time, so they're equal
+            return 0;
+        }
+
+    }
+
+    /**
+     * Comparison function between byte array types and any other object. The set of 6
+     * "rich comparison" operators are based on this.
+     *
+     * @param b
+     * @return 1, 0 or -1 as this>b, this==b, or this&lt;b respectively, or -2 if the comparison is
+     *         not implemented
+     */
+    private synchronized int basebytes_cmp(PyObject b) {
+
+        // This is not exposed as bytearray and bytes have no __cmp__.
+
+        if (this == b) {
+            // Same object: quick result
+            return 0;
+
+        } else {
+
+            // Try to get a byte-oriented view
+            View bv = getView(b);
+
+            if (bv == null) {
+                // Signifies a type mis-match. See PyObject _cmp_unsafe() and related code.
+                return -2;
+
+            } else {
+                // Object supported by our interim memory view
+                return compare(this, bv);
+
+            }
+        }
+    }
+
+// /**
+// * Comparison function between byte array types and any other object. The set of 6
+// * "rich comparison" operators are based on this.
+// *
+// * @param b
+// * @return 1, 0 or -1 as this>b, this==b, or this&lt;b respectively, or -2 if the comparison is
+// * not implemented
+// */
+// private synchronized int basebytes_cmp(PyObject b) {
+//
+// // This is based on PyFloat.float___cmp__() as it seems to have the same need to support
+// // multiple types for other, but it is not exposed as bytearray and bytes have no __cmp__.
+//
+// if (this == b) {
+// // Same object: quick result
+// return 0;
+//
+// } else if (b instanceof BaseBytes) {
+// return compare(this, (BaseBytes)b);
+//
+// } else if (b.getType() == PyString.TYPE) {
+// /*
+// * Necessary to permit comparison of bytearray and bytes, which in in Python 2.7 is an
+// * alias of str. Remove in 3.0
+// */
+// return compare(this, ((PyString)b).asString());
+//
+// } else if (b instanceof MemoryViewProtocol) {
+// // XXX: Revisit when we have an implementation of memoryview
+// // MemoryView mv = ((MemoryViewProtocol) other).getMemoryView();
+// return -2;
+//
+// } else {
+// // Signifies a type mis-match. See PyObject _cmp_unsafe() and related code.
+// return -2;
+// }
+// }
+
+    /**
+     * Fail-fast comparison function between byte array types and any other object, for when the
+     * test is only for equality. The "rich comparison" operators <code>__eq__</code> and
+     * <code>__ne__</code> are based on this.
+     *
+     * @param b
+     * @return 0 if this==b, or +1 or -1 if this!=b, or -2 if the comparison is not implemented
+     */
+    private synchronized int basebytes_cmpeq(PyObject b) {
+
+        if (this == b) {
+            // Same object: quick result
+            return 0;
+
+        } else {
+
+            // Try to get a byte-oriented view
+            View bv = getView(b);
+
+            if (bv == null) {
+                // Signifies a type mis-match. See PyObject _cmp_unsafe() and related code.
+                return -2;
+
+            } else if (bv.size() != size) {
+                // Different size: can't be equal, and we don't care which is bigger
+                return 1;
+
+            } else {
+                // Object supported by our interim memory view
+                return compare(this, bv);
+
+            }
+        }
+    }
+
+// /**
+// * Fail-fast comparison function between byte array types and any other object, for when the
+// * test is only for equality. The "rich comparison" operators <code>__eq__</code> and
+// * <code>__ne__</code> are based on this.
+// *
+// * @param b
+// * @return 0 if this==b, or +1 or -1 if this!=b, or -2 if the comparison is not implemented
+// */
+// private synchronized int basebytes_cmpeq(PyObject b) {
+//
+// if (b instanceof BaseBytes) {
+// if (((BaseBytes)b).size != size) {
+// // Different size: can't be equal, and we don't care which is bigger
+// return 1;
+// }
+// } else if (b.getType() == PyString.TYPE) {
+// /*
+// * Necessary to permit comparison of bytearray and bytes, which in in Python 2.7 is an
+// * alias of str. Remove in 3.0
+// */
+// if (((PyString)b).__len__() != size) {
+// // Different size: can't be equal, and we don't care which is bigger
+// return 1;
+// }
+// }
+// return basebytes_cmp(b);
+// }
+
+    /**
+     * Implementation of __eq__ (equality) operator, capable of comparison with another byte array
+     * or bytes. Comparison with an invalid type returns null.
+     *
+     * @param other
+     * @return
+     */
+    final PyObject basebytes___eq__(PyObject other) {
+        int cmp = basebytes_cmpeq(other);
+        if (cmp == 0) {
+            return Py.True;
+        } else if (cmp > -2) {
+            return Py.False;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Implementation of __ne__ (not equals) operator, capable of comparison with another byte array
+     * or bytes. Comparison with an invalid type returns null.
+     *
+     * @param other
+     * @return
+     */
+    final PyObject basebytes___ne__(PyObject other) {
+        int cmp = basebytes_cmpeq(other);
+        if (cmp == 0) {
+            return Py.False;
+        } else if (cmp > -2) {
+            return Py.True;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Implementation of __lt__ (less than) operator, capable of comparison with another byte array
+     * or bytes. Comparison with an invalid type returns null.
+     *
+     * @param other
+     * @return
+     */
+    final PyObject basebytes___lt__(PyObject other) {
+        int cmp = basebytes_cmp(other);
+        if (cmp >= 0) {
+            return Py.False;
+        } else if (cmp > -2) {
+            return Py.True;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Implementation of __le__ (less than or equal to) operator, capable of comparison with another
+     * byte array or bytes. Comparison with an invalid type returns null.
+     *
+     * @param other
+     * @return
+     */
+    final PyObject basebytes___le__(PyObject other) {
+        int cmp = basebytes_cmp(other);
+        if (cmp > 0) {
+            return Py.False;
+        } else if (cmp > -2) {
+            return Py.True;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Implementation of __ge__ (greater than or equal to) operator, capable of comparison with
+     * another byte array or bytes. Comparison with an invalid type returns null.
+     *
+     * @param other
+     * @return
+     */
+    final PyObject basebytes___ge__(PyObject other) {
+        int cmp = basebytes_cmp(other);
+        if (cmp >= 0) {
+            return Py.True;
+        } else if (cmp > -2) {
+            return Py.False;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Implementation of __gt__ (greater than) operator, capable of comparison with another byte
+     * array or bytes. Comparison with an invalid type returns null.
+     *
+     * @param other
+     * @return
+     */
+    final PyObject basebytes___gt__(PyObject other) {
+        int cmp = basebytes_cmp(other);
+        if (cmp > 0) {
+            return Py.True;
+        } else if (cmp > -2) {
+            return Py.False;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Equivalent of the 'string_escape' decode to a String that is all-printable, showing non
+     * printable charater as lowercase hex escapes, except '\t', '\n', and '\r'. This supports
+     * <code>__repr__()</code>.
+     *
+     * @return the byte array as a String, still encoded
+     */
+    protected synchronized String asEscapedString() {
+        StringBuilder buf = new StringBuilder(size + (size >> 8) + 10);
+        int jmax = offset + size;
+        for (int j = offset; j < jmax; j++) {
+            int c = 0xff & storage[j];
+            if (c >= 0x7f) {    // Unprintable high 128 and DEL
+                appendHexEscape(buf, c);
+            } else if (c >= ' ') { // Printable
+                if (c == '\\') {    // Special case
+                    buf.append("\\\\");
+                } else {
+                    buf.append((char)c);
+                }
+            } else if (c == '\t') { // Spacial cases in the low 32
+                buf.append("\\t");
+            } else if (c == '\n') {
+                buf.append("\\n");
+            } else if (c == '\r') {
+                buf.append("\\r");
+            } else {
+                appendHexEscape(buf, c);
+            }
+        }
+        return buf.toString();
+    }
+
+    private static final void appendHexEscape(StringBuilder buf, int c) {
+        buf.append("\\x")
+                .append(Character.forDigit((c & 0xf0) >> 4, 16))
+                .append(Character.forDigit(c & 0xf, 16));
+    }
+
+    /**
+     * Search for the target in this byte array, returning true if found and false if not. The
+     * target must be compatible with the Python byte range.
+     *
+     * @param target byte value to search for
+     * @return true iff found
+     */
+    protected final synchronized boolean basebytes___contains__(PyObject target) {
+        byte t = byteCheck(target);
+        int jmax = offset + size;
+        for (int j = offset; j < jmax; j++) {
+            if (storage[j] == t) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Copy the bytes of a byte array to the characters of a String with no change in ordinal value.
+     * This could also be described as 'latin-1' decoding of the byte array to a String.
+     *
+     * @return the byte array as a String, still encoded
+     */
+    private synchronized String asEncodedString() {
+        StringBuilder buf = new StringBuilder(size);
+        int jmax = offset + size;
+        for (int j = offset; j < jmax; j++) {
+            buf.append((char)(0xff & storage[j]));
+        }
+        return buf.toString();
+    }
+
+    /**
+     * Decode the byte array to a Unicode string according to the default encoding. The returned
+     * PyObject should be a <code>PyUnicode</code>, since the default codec is well-behaved.
+     *
+     * @return object containing the decoded characters
+     */
+    public PyObject decode() {
+        return decode(null, null);
+    }
+
+    /**
+     * Decode the byte array to a Unicode string according to the specified encoding and default
+     * error policy. The returned PyObject will usually be a <code>PyUnicode</code>, but in practice
+     * it is whatever the <code>decode</code> method of the codec decides.
+     *
+     * @param encoding the name of the codec (uses default codec if null)
+     * @return object containing the decoded characters
+     */
+    public PyObject decode(String encoding) {
+        return decode(encoding, null);
+    }
+
+    /**
+     * Decode the byte array to a Unicode string according to the specified encoding and error
+     * policy. The returned PyObject will usually be a <code>PyUnicode</code>, but in practice it is
+     * whatever the <code>decode</code> method of the codec decides.
+     *
+     * @param encoding the name of the codec (uses default codec if null)
+     * @param errors the name of the error policy (uses 'strict' if null)
+     * @return object containing the decoded characters
+     */
+    public PyObject decode(String encoding, String errors) {
+        /*
+         * Provide a Python <code>str</code> input to the decode method of a codec, which in v2.7
+         * expects a PyString. (In Python 3k the codecs decode from the <code>bytes</code> type, so
+         * we can pass this directly.)
+         */
+        PyString this_ = new PyString(this.asEncodedString());
+        return codecs.decode(this_, encoding, errors);
+    }
+
+    /**
+     * Ready-to-expose implementation of decode( [ encoding [, errors ]] )
+     *
+     * @param args Python argument list
+     * @param keywords Assocaited keywords
+     * @return
+     */
+    protected final PyObject basebytes_decode(PyObject[] args, String[] keywords) {
+        ArgParser ap = new ArgParser("decode", args, keywords, "encoding", "errors");
+        String encoding = ap.getString(0, null);
+        String errors = ap.getString(1, null);
+        return decode(encoding, errors);
+    }
+
+    /**
+     * Ready-to-expose implementation of Python <code>find( sub [, start [, end ]] )</code>. Return
+     * the lowest index in the byte array where byte sequence <code>sub</code> is found, such that
+     * <code>sub</code> is contained in the slice <code>[start:end]</code>. Arguments
+     * <code>start</code> and <code>end</code> (which may be <code>null</code> or
+     * <code>Py.None</code> ) are interpreted as in slice notation. Return -1 if <code>sub</code> is
+     * not found.
+     *
+     * @param sub bytes to find
+     * @param start of slice to search
+     * @param end of slice to search
+     * @return index of start of ocurrence of sub within this byte array
+     */
+    final int basebytes_find(PyObject sub, PyObject start, PyObject end) {
+        ViewOfBytes v = this.slice(start, end);
+        byte[] buf = v.storage;
+        View vsub = getViewOrError(sub);
+        int n = vsub.size();
+        // No point testing beyond this location, as insufficient space:
+        int pmax = v.offset + v.size - n;
+        // Use start positions from v.offset to pmax in the buffer buf
+        for (int p = v.offset; p < pmax; p++) {
+            int j;
+            for (j = 0; j < n; j++) {
+                if (buf[p + j] != vsub.byteAt(j)) {
+                    break;
+                }
+            }
+            // If we tested all n bytes, that's a match. Note that the returned index is
+            // relative to the (operative) start of this, not relative to the start of the slice.
+            if (j == n) {
+                return p - this.offset;
+            }
+        }
+        // We tested all the start positions without success
+        return -1;
+    }
+
+    /**
+     * Convenience method to create a <code>TypeError</code> PyException with the message
+     * "can't concat {type} to {toType}"
+     *
+     * @param type
+     * @param toType
+     * @return PyException (TypeError) as detailed
+     */
+    public static PyException ConcatenationTypeError(PyType type, PyType toType) {
+        String fmt = "can't concat %s to %s";
+        return Py.TypeError(String.format(fmt, type.fastGetName(), toType.fastGetName()));
+    }
+
+    /**
+     * Support for pickling byte arrays: reduce a byte array to the actual type, arguments for
+     * (re-)construction of the object, and the dictionary of any user-defined sub-class.
+     *
+     * @return PyTuple that is first stage in pickling byte array
+     */
+    public PyObject __reduce__() {
+        return basebytes___reduce__();
+    }
+
+    final PyTuple basebytes___reduce__() {
+        PyUnicode encoded = new PyUnicode(this.asEncodedString());
+        PyObject args = new PyTuple(encoded, getPickleEncoding());
+        PyObject dict = __findattr__("__dict__");
+        return new PyTuple(getType(), args, (dict != null) ? dict : Py.None);
+    }
+
+    private static PyString PICKLE_ENCODING;
+
+    /**
+     * Name the encoding effectively used in __reduce__() suport for pickling: this choice is
+     * hard-coded in CPython as "latin-1".
+     */
+    private static final PyString getPickleEncoding() {
+        if (PICKLE_ENCODING == null) {
+            PICKLE_ENCODING = new PyString("latin-1");
+        }
+        return PICKLE_ENCODING;
+    }
+
+    /*
+     * ======================================================================================== API
+     * for Java access as byte[]
      * ========================================================================================
      *
      * Just the immutable case for now
@@ -711,29 +1572,33 @@
 
     /**
      * No range check access to byte[index].
+     *
      * @param index
      * @return the byte at the given index
      */
     private final synchronized byte byteAt(int index) {
-        return storage[index+offset]; 
+        return storage[index + offset];
     }
 
     /**
      * Return the Python byte (in range 0 to 255 inclusive) at the given index.
+     *
      * @param index of value in byte array
      * @return the integer value at the index
      * @throws PyException(IndexError) if the index is outside the array bounds
      */
     public synchronized int intAt(int index) throws PyException {
         indexCheck(index);
-        return 0xff & ((int)byteAt(index)); 
+        return 0xff & byteAt(index);
     }
 
     /**
      * Helper to implement {@link #repeat(int)}. Use something like:
-     * 
+     *
      * <pre>
-     * 
+     *
+     *
+     *
      * &#064;Override
      * protected PyByteArray repeat(int count) {
      *     PyByteArray ret = new PyByteArray();
@@ -741,7 +1606,7 @@
      *     return ret;
      * }
      * </pre>
-     * 
+     *
      * @param count the number of times to repeat this.
      * @return this byte array repeated count times.
      */
@@ -753,9 +1618,9 @@
         return dst;
     }
 
-
-    /* ========================================================================================
-     * API for java.util.List<PyInteger>
+    /*
+     * ======================================================================================== API
+     * for java.util.List<PyInteger>
      * ========================================================================================
      */
 
@@ -773,12 +1638,15 @@
         }
 
         @Override
-        public int size() { return size; }
+        public int size() {
+            return size;
+        }
 
         // For mutable subclass use
-        
+
         /**
          * Replaces the element at the specified position in this list with the specified element.
+         *
          * @see java.util.AbstractList#set(int, java.lang.Object)
          * @throws PyException(TypeError) if actual class is immutable
          * @throws PyException(IndexError) if the index is outside the array bounds
@@ -794,8 +1662,9 @@
         }
 
         /**
-         * Inserts the specified element at the specified position in this list.
-         * Shifts the element currently at that position and any subsequent elements to the right.
+         * Inserts the specified element at the specified position in this list. Shifts the element
+         * currently at that position and any subsequent elements to the right.
+         *
          * @see java.util.AbstractList#add(int, java.lang.Object)
          * @throws PyException(IndexError) if the index is outside the array bounds
          * @throws PyException(ValueError) if element<0 or element>255
@@ -805,13 +1674,14 @@
         public void add(int index, PyInteger element) throws PyException {
             // Not using __setitem__ as it applies Python index semantics to e.g. b[-1].
             indexCheck(index);
-            pyadd(index, element);          // TypeError if immutable
+            pyinsert(index, element);          // TypeError if immutable
         }
 
         /**
          * Removes the element at the specified position in this list. Shifts any subsequent
-         * elements to the left (subtracts one from their indices).
-         * Returns the element that was removed from the list.
+         * elements to the left (subtracts one from their indices). Returns the element that was
+         * removed from the list.
+         *
          * @see java.util.AbstractList#remove(int)
          * @throws PyException(IndexError) if the index is outside the array bounds
          */
@@ -825,17 +1695,22 @@
         }
     };
 
-    /** 
-     * Number of bytes in bytearray (or bytes) object. 
+    /**
+     * Number of bytes in bytearray (or bytes) object.
+     *
      * @see java.util.List#size()
      * @return Number of bytes in byte array.
      * */
-    public int size() { return size;}
+    public int size() {
+        return size;
+    }
 
     /*
      * @see java.util.List#isEmpty()
      */
-    public boolean isEmpty() { return size==0; }
+    public boolean isEmpty() {
+        return size == 0;
+    }
 
     /**
      * Returns true if this list contains the specified value. More formally, returns true if and
@@ -847,6 +1722,7 @@
 
     /*
      * @return
+     *
      * @see java.util.List#iterator()
      */
     public Iterator<PyInteger> iterator() {
@@ -855,6 +1731,7 @@
 
     /*
      * @return
+     *
      * @see java.util.List#toArray()
      */
     public Object[] toArray() {
@@ -863,7 +1740,9 @@
 
     /*
      * @param a
+     *
      * @return
+     *
      * @see java.util.List#toArray(T[])
      */
     public <T> T[] toArray(T[] a) {
@@ -872,7 +1751,9 @@
 
     /*
      * @param o
+     *
      * @return
+     *
      * @see java.util.List#add(java.lang.Object)
      */
     public boolean add(PyInteger o) {
@@ -881,7 +1762,9 @@
 
     /*
      * @param o
+     *
      * @return
+     *
      * @see java.util.List#remove(java.lang.Object)
      */
     public boolean remove(Object o) {
@@ -890,7 +1773,9 @@
 
     /*
      * @param c
+     *
      * @return
+     *
      * @see java.util.List#containsAll(java.util.Collection)
      */
     public boolean containsAll(Collection<?> c) {
@@ -899,7 +1784,9 @@
 
     /*
      * @param c
+     *
      * @return
+     *
      * @see java.util.List#addAll(java.util.Collection)
      */
     public boolean addAll(Collection<? extends PyInteger> c) {
@@ -908,8 +1795,11 @@
 
     /*
      * @param index
+     *
      * @param c
+     *
      * @return
+     *
      * @see java.util.List#addAll(int, java.util.Collection)
      */
     public boolean addAll(int index, Collection<? extends PyInteger> c) {
@@ -918,7 +1808,9 @@
 
     /*
      * @param c
+     *
      * @return
+     *
      * @see java.util.List#removeAll(java.util.Collection)
      */
     public boolean removeAll(Collection<?> c) {
@@ -927,7 +1819,9 @@
 
     /*
      * @param c
+     *
      * @return
+     *
      * @see java.util.List#retainAll(java.util.Collection)
      */
     public boolean retainAll(Collection<?> c) {
@@ -935,7 +1829,7 @@
     }
 
     /*
-     * 
+     *
      * @see java.util.List#clear()
      */
     public void clear() {
@@ -944,7 +1838,9 @@
 
     /*
      * @param o
+     *
      * @return
+     *
      * @see java.util.List#equals(java.lang.Object)
      */
     public boolean equals(Object o) {
@@ -953,6 +1849,7 @@
 
     /*
      * @return
+     *
      * @see java.util.List#hashCode()
      */
     public int hashCode() {
@@ -961,7 +1858,9 @@
 
     /*
      * @param index
+     *
      * @return
+     *
      * @see java.util.List#get(int)
      */
     public PyInteger get(int index) {
@@ -970,8 +1869,11 @@
 
     /*
      * @param index
+     *
      * @param element
+     *
      * @return
+     *
      * @see java.util.List#set(int, java.lang.Object)
      */
     public PyInteger set(int index, PyInteger element) {
@@ -980,7 +1882,9 @@
 
     /*
      * @param index
+     *
      * @param element
+     *
      * @see java.util.List#add(int, java.lang.Object)
      */
     public void add(int index, PyInteger element) {
@@ -989,7 +1893,9 @@
 
     /*
      * @param index
+     *
      * @return
+     *
      * @see java.util.List#remove(int)
      */
     public PyInteger remove(int index) {
@@ -998,7 +1904,9 @@
 
     /*
      * @param o
+     *
      * @return
+     *
      * @see java.util.List#indexOf(java.lang.Object)
      */
     public int indexOf(Object o) {
@@ -1007,7 +1915,9 @@
 
     /*
      * @param o
+     *
      * @return
+     *
      * @see java.util.List#lastIndexOf(java.lang.Object)
      */
     public int lastIndexOf(Object o) {
@@ -1016,6 +1926,7 @@
 
     /*
      * @return
+     *
      * @see java.util.List#listIterator()
      */
     public ListIterator<PyInteger> listIterator() {
@@ -1024,7 +1935,9 @@
 
     /*
      * @param index
+     *
      * @return
+     *
      * @see java.util.List#listIterator(int)
      */
     public ListIterator<PyInteger> listIterator(int index) {
@@ -1033,12 +1946,15 @@
 
     /*
      * @param fromIndex
+     *
      * @param toIndex
+     *
      * @return
+     *
      * @see java.util.List#subList(int, int)
      */
     public List<PyInteger> subList(int fromIndex, int toIndex) {
         return listDelegate.subList(fromIndex, toIndex);
     }
-     
+
 }
diff --git a/src/org/python/core/PyByteArray.java b/src/org/python/core/PyByteArray.java
--- a/src/org/python/core/PyByteArray.java
+++ b/src/org/python/core/PyByteArray.java
@@ -5,6 +5,7 @@
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedType;
+import org.python.expose.MethodType;
 
 /**
  * Partial implementation of Python bytearray. At the present stage of development, the class
@@ -18,21 +19,22 @@
  * implementation does not support the <code>memoryview</code> interface either for access or a a
  * source for its constructors although the signatures are present. The rich set of string-like
  * operations due a <code>bytearray</code> is not implemented.
- * 
+ *
  */
 @ExposedType(name = "bytearray", base = PyObject.class, doc = BuiltinDocs.bytearray_doc)
 public class PyByteArray extends BaseBytes {
 
     public static final PyType TYPE = PyType.fromClass(PyByteArray.class);
-    
+
     /**
      * Create a zero-length Python bytearray of explicitly-specified sub-type
+     *
      * @param type explicit Jython type
      */
     public PyByteArray(PyType type) {
         super(type);
     }
-    
+
     /**
      * Create a zero-length Python bytearray.
      */
@@ -42,6 +44,7 @@
 
     /**
      * Create zero-filled Python bytearray of specified size.
+     *
      * @param size of bytearray
      */
     public PyByteArray(int size) {
@@ -51,7 +54,7 @@
 
     /**
      * Construct bytearray by copying values from int[].
-     * 
+     *
      * @param value source of the bytes (and size)
      */
     public PyByteArray(int[] value) {
@@ -59,39 +62,40 @@
     }
 
     /**
-     * Create a new array filled exactly by a copy of the contents of the
-     * source.
+     * Create a new array filled exactly by a copy of the contents of the source.
+     *
      * @param value source of the bytes (and size)
      */
     public PyByteArray(BaseBytes value) {
         super(TYPE);
         init(value);
     }
-    
+
     /**
-     * Create a new array filled exactly by a copy of the contents of the
-     * source.
+     * Create a new array filled exactly by a copy of the contents of the source.
+     *
      * @param value source of the bytes (and size)
      */
     public PyByteArray(MemoryViewProtocol value) {
         super(TYPE);
         init(value.getMemoryView());
     }
-    
+
     /**
      * Create a new array filled from an iterable of PyObject. The iterable must yield objects
      * convertible to Python bytes (non-negative integers less than 256 or strings of length 1).
+     *
      * @param value source of the bytes (and size)
      */
     public PyByteArray(Iterable<? extends PyObject> value) {
         super(TYPE);
         init(value);
     }
-    
+
     /**
      * Create a new array by encoding a PyString argument to bytes. If the PyString is actually a
      * PyUnicode, the encoding must be explicitly specified.
-     * 
+     *
      * @param arg primary argument from which value is taken
      * @param encoding name of optional encoding (must be a string type)
      * @param errors name of optional errors policy (must be a string type)
@@ -104,7 +108,7 @@
     /**
      * Create a new array by encoding a PyString argument to bytes. If the PyString is actually a
      * PyUnicode, the encoding must be explicitly specified.
-     * 
+     *
      * @param arg primary argument from which value is taken
      * @param encoding name of optional encoding (may be null to select the default for this
      *            installation)
@@ -116,6 +120,17 @@
     }
 
     /**
+     * Create a new array by encoding a PyString argument to bytes. If the PyString is actually a
+     * PyUnicode, an exception is thrown saying that the encoding must be explicitly specified.
+     *
+     * @param arg primary argument from which value is taken
+     */
+    public PyByteArray(PyString arg) {
+        super(TYPE);
+        init(arg, (String)null, (String)null);
+    }
+
+    /**
      * Create a new bytearray object from an arbitrary Python object according to the same rules as
      * apply in Python to the bytearray() constructor:
      * <ul>
@@ -133,16 +148,17 @@
      * <code>bytearray(string, encoding[, errors])</code>, use the constructor
      * {@link #PyByteArray(PyString, String, String)}. If the PyString is actually a PyUnicode, an
      * encoding must be specified, and using this constructor will throw an exception about that.
-     * 
+     *
      * @param arg primary argument from which value is taken (may be null)
      * @throws PyException in the same circumstances as bytearray(arg), TypeError for non-iterable,
-     * non-integer argument type, and ValueError if iterables do not yield byte [0..255] values.
+     *             non-integer argument type, and ValueError if iterables do not yield byte [0..255]
+     *             values.
      */
     public PyByteArray(PyObject arg) throws PyException {
         super(TYPE);
         init(arg);
     }
-    
+
     /* ========================================================================================
      * API for org.python.core.PySequence
      * ========================================================================================
@@ -160,12 +176,12 @@
     protected synchronized PyByteArray getslice(int start, int stop, int step) {
         if (step == 1) {
             // Efficiently copy contiguous slice
-            int n = stop-start;
-            if (n<=0) {
+            int n = stop - start;
+            if (n <= 0) {
                 return new PyByteArray();
             } else {
                 PyByteArray ret = new PyByteArray(n);
-                System.arraycopy(storage, offset+start, ret.storage, ret.offset, n);
+                System.arraycopy(storage, offset + start, ret.storage, ret.offset, n);
                 return ret;
             }
         } else {
@@ -173,16 +189,17 @@
             PyByteArray ret = new PyByteArray(n);
             n += ret.offset;
             byte[] dst = ret.storage;
-            for (int io = start + offset, jo = ret.offset; jo < n; io += step, jo++)
+            for (int io = start + offset, jo = ret.offset; jo < n; io += step, jo++) {
                 dst[jo] = storage[io];
+            }
             return ret;
         }
     }
 
-    
     /**
-     * Returns a PyByteArray that repeats this  sequence the given number of times, as
-     * in the implementation of <tt>__mul__</tt> for strings.
+     * Returns a PyByteArray that repeats this sequence the given number of times, as in the
+     * implementation of <tt>__mul__</tt> for strings.
+     *
      * @param count the number of times to repeat this.
      * @return this byte array repeated count times.
      */
@@ -191,14 +208,13 @@
         PyByteArray ret = new PyByteArray();
         ret.setStorage(repeatImpl(count));
         return ret;
-    }    
+    }
 
     /**
-     * Sets the indexed element of the bytearray to the given value.
-     * This is an extension point called by PySequence in its implementation of
-     * {@link #__setitem__}
-     * It is guaranteed by PySequence that the index is within the bounds of the array.
-     * Any other clients calling <tt>pyset(int)</tt> must make the same guarantee.
+     * Sets the indexed element of the bytearray to the given value. This is an extension point
+     * called by PySequence in its implementation of {@link #__setitem__} It is guaranteed by
+     * PySequence that the index is within the bounds of the array. Any other clients calling
+     * <tt>pyset(int)</tt> must make the same guarantee.
      *
      * @param index index of the element to set.
      * @param value the value to set this element to.
@@ -206,23 +222,26 @@
      * @throws PyException(ValueError) if value<0 or value>255
      */
     public synchronized void pyset(int index, PyObject value) throws PyException {
-        storage[index+offset] = byteCheck(value); 
+        storage[index + offset] = byteCheck(value);
     }
 
     /**
      * Insert the element (interpreted as a Python byte value) at the given index.
-     * 
+     * Python int, long and string types of length 1 are allowed.
+     *
      * @param index to insert at
      * @param element to insert (by value)
      * @throws PyException(IndexError) if the index is outside the array bounds
      * @throws PyException(ValueError) if element<0 or element>255
+     * @throws PyException(TypeError) if the subclass is immutable
      */
-    public synchronized void pyadd(int index, PyInteger element) {
+    @Override
+    public synchronized void pyinsert(int index, PyObject element) {
         // Open a space at the right location.
         storageReplace(index, 0, 1);
-        storage[index] = byteCheck(element); 
+        storage[offset+index] = byteCheck(element);
     }
-    
+
     /**
      * Sets the given range of elements according to Python slice assignment semantics. If the step
      * size is one, it is a simple slice and the operation is equivalent to deleting that slice,
@@ -236,15 +255,15 @@
      * <code>PyObject</code>s, but acceptable ones are PyInteger, PyLong or PyString of length 1. If
      * any one of them proves unsuitable for assignment to a Python bytarray element, an exception
      * is thrown and this bytearray is unchanged.
-     * 
+     *
      * <pre>
      * a = bytearray(b'abcdefghijklmnopqrst')
      * a[2:12:2] = iter( [65, 66, 67, long(68), "E"] )
      * </pre>
-     * 
+     *
      * Results in <code>a=bytearray(b'abAdBfChDjElmnopqrst')</code>.
      * <p>
-     * 
+     *
      * @param start the position of the first element.
      * @param stop one more than the position of the last element.
      * @param step the step size.
@@ -308,12 +327,10 @@
         }
     }
 
-
-
     /**
      * Sets the given range of elements according to Python slice assignment semantics from a
      * zero-filled bytearray of the given length.
-     * 
+     *
      * @see #setslice(int, int, int, PyObject)
      * @param start the position of the first element.
      * @param stop one more than the position of the last element.
@@ -330,17 +347,19 @@
         } else {
             // This is an extended slice which means we are replacing elements
             int n = sliceLength(start, stop, step);
-            if (n != len) throw SliceSizeError("bytes", len, n);
-            for (int io = start + offset; n > 0; io += step, --n)
+            if (n != len) {
+                throw SliceSizeError("bytes", len, n);
+            }
+            for (int io = start + offset; n > 0; io += step, --n) {
                 storage[io] = 0;
+            }
         }
     }
 
-
     /**
      * Sets the given range of elements according to Python slice assignment semantics from a
      * PyString.
-     * 
+     *
      * @see #setslice(int, int, int, PyObject)
      * @param start the position of the first element.
      * @param stop one more than the position of the last element.
@@ -368,7 +387,7 @@
     /**
      * Sets the given range of elements according to Python slice assignment semantics from an
      * object supporting the Jython implementation of PEP 3118.
-     * 
+     *
      * @see #setslice(int, int, int, PyObject)
      * @param start the position of the first element.
      * @param stop one more than the position of the last element.
@@ -378,34 +397,37 @@
      */
     private void setslice(int start, int stop, int step, MemoryView value) throws PyException {
         // XXX Support memoryview once means of access to bytes is defined
-        Py.NotImplementedError("memoryview not yet supported in bytearray");
-        String format = value.get_format();
-        boolean isBytes = format == null || "B".equals(format);
-        if (value.get_ndim() != 1 || !isBytes) {
-            Py.TypeError("memoryview value must be byte-oriented");
-        } else {
-            // Dimensions are given as a PyTple (although only one)
-            int len = value.get_shape().pyget(0).asInt();
-            if (step == 1) {
-                // Delete this[start:stop] and open a space of the right size
-                storageReplace(start, stop - start, len);
-                // System.arraycopy(value.storage, value.offset, storage, start
-                // + offset, len);
-            } else {
-                // This is an extended slice which means we are replacing elements
-                int n = sliceLength(start, stop, step);
-                if (n != len) throw SliceSizeError("bytes", len, n);
-                // int no = n + value.offset;
-                // for (int io = start + offset, jo = value.offset; jo < no; io += step, jo++) {
-                // storage[io] = value.storage[jo]; // Assign this[i] = value[j]
-                // }
-            }
-        }
+        throw Py.NotImplementedError("memoryview not yet supported in bytearray");
+//        String format = value.get_format();
+//        boolean isBytes = format == null || "B".equals(format);
+//        if (value.get_ndim() != 1 || !isBytes) {
+//            throw Py.TypeError("memoryview value must be byte-oriented");
+//        } else {
+//            // Dimensions are given as a PyTuple (although only one)
+//            int len = value.get_shape().pyget(0).asInt();
+//            if (step == 1) {
+//                // Delete this[start:stop] and open a space of the right size
+//                storageReplace(start, stop - start, len);
+//                // System.arraycopy(value.storage, value.offset, storage, start
+//                // + offset, len);
+//            } else {
+//                // This is an extended slice which means we are replacing elements
+//                int n = sliceLength(start, stop, step);
+//                if (n != len) {
+//                    throw SliceSizeError("bytes", len, n);
+//                }
+//                // int no = n + value.offset;
+//                // for (int io = start + offset, jo = value.offset; jo < no; io += step, jo++) {
+//                // storage[io] = value.storage[jo]; // Assign this[i] = value[j]
+//                // }
+//            }
+//        }
     }
 
     /**
-     * Sets the given range of elements according to Python slice assignment semantics
-     * from a bytearray (or bytes).
+     * Sets the given range of elements according to Python slice assignment semantics from a
+     * bytearray (or bytes).
+     *
      * @see #setslice(int, int, int, PyObject)
      * @param start the position of the first element.
      * @param stop one more than the position of the last element.
@@ -414,33 +436,37 @@
      * @throws PyException(SliceSizeError) if the value size is inconsistent with an extended slice
      */
     private void setslice(int start, int stop, int step, BaseBytes value) throws PyException {
-        if (value == this) {
-            value = new PyByteArray(value);  // Must work with a copy
+
+        if (value == this) {  // Must work with a copy
+            value = new PyByteArray(value);
         }
+
         int len = value.size;
+
         if (step == 1) {
-            //Delete this[start:stop] and open a space of the right size
+            // Delete this[start:stop] and open a space of the right size
             storageReplace(start, stop - start, len);
-            System.arraycopy(value.storage, value.offset, storage, start
-                    + offset, len);
+            System.arraycopy(value.storage, value.offset, storage, start + offset, len);
+
         } else {
             // This is an extended slice which means we are replacing elements
             int n = sliceLength(start, stop, step);
             if (n != len) {
                 throw SliceSizeError("bytes", len, n);
             }
+
             int no = n + value.offset;
             for (int io = start + offset, jo = value.offset; jo < no; io += step, jo++) {
                 storage[io] = value.storage[jo];    // Assign this[i] = value[j]
             }
+
         }
     }
 
-
     /**
      * Sets the given range of elements according to Python slice assignment semantics from a
      * bytearray (or bytes).
-     * 
+     *
      * @see #setslice(int, int, int, PyObject)
      * @param start the position of the first element.
      * @param stop one more than the position of the last element.
@@ -452,7 +478,8 @@
     private void setslice(int start, int stop, int step, Iterable<? extends PyObject> iter) {
         /*
          * As we don't know how many elements the iterable represents, we can't adjust the array
-         * until after we run the iterator. We use this elastic byte structure to hold the bytes until then.
+         * until after we run the iterator. We use this elastic byte structure to hold the bytes
+         * until then.
          */
         FragmentList fragList = new BaseBytes.FragmentList();
         fragList.loadFrom(iter);
@@ -464,29 +491,30 @@
                 // Stitch the fragments together in the space we made
                 fragList.emptyInto(storage, start + offset);
             }
+
         } else {
             // This is an extended slice which means we are replacing elements
             int n = sliceLength(start, stop, step);
-            if (n != fragList.totalCount) throw SliceSizeError("bytes", fragList.totalCount, n);
+            if (n != fragList.totalCount) {
+                throw SliceSizeError("bytes", fragList.totalCount, n);
+            }
             fragList.emptyInto(storage, start + offset, step);
         }
     }
 
+// Idiom:
+// if (step == 1) {
+// // Do something efficient with block start...stop-1
+// } else {
+// int n = sliceLength(start, stop, step);
+// for (int i = start, j = 0; j < n; i += step, j++) {
+// // Perform jth operation with element i
+// }
+// }
 
-// Idiom:    
-//    if (step == 1) {
-//        // Do something efficient with block start...stop-1
-//    } else {
-//        int n = sliceLength(start, stop, step);
-//        for (int i = start, j = 0; j < n; i += step, j++) {
-//            // Perform jth operation with element i
-//        }
-//    }
-    
-    
-    
     /*
      * Deletes an element from the sequence (and closes up the gap).
+     *
      * @param index index of the element to delete.
      */
     protected synchronized void del(int index) {
@@ -496,17 +524,18 @@
 
     /*
      * Deletes contiguous sub-sequence (and closes up the gap).
+     *
      * @param start the position of the first element.
+     *
      * @param stop one more than the position of the last element.
      */
     protected synchronized void delRange(int start, int stop) {
-        // XXX Use the specialised storageDelete()
-        storageReplace(start, stop-start, 0);
+        storageDelete(start, stop - start);
     }
 
     /**
      * Deletes a simple or extended slice and closes up the gap(s).
-     * 
+     *
      * @param start the position of the first element.
      * @param stop one more than the position of the last element.
      * @param step from one element to the next
@@ -532,22 +561,20 @@
     }
 
     /**
-     * Convenience method to create a <code>ValueError</code> PyException with the message
+     * Convenience method to build (but not throw) a <code>ValueError</code> PyException with the message
      * "attempt to assign {type} of size {valueSize} to extended slice of size {sliceSize}"
-     * 
+     *
      * @param valueType
      * @param valueSize size of sequence being assigned to slice
      * @param sliceSize size of slice expected to receive
-     * @throws PyException (ValueError) as detailed
+     * @return PyException (ValueError) as detailed
      */
-    public static PyException SliceSizeError(String valueType, int valueSize, int sliceSize)
-            throws PyException {
+    public static PyException SliceSizeError(String valueType, int valueSize, int sliceSize) {
         String fmt = "attempt to assign %s of size %d to extended slice of size %d";
         return Py.ValueError(String.format(fmt, valueType, valueSize, sliceSize));
-        // XXX consider moving to SequenceIndexDelegate.java or somewhere else generic
+        // XXX consider moving to SequenceIndexDelegate.java or somewhere else generic, even Py
     }
 
-
     /**
      * Initialise a mutable bytearray object from various arguments. This single initialisation must
      * support:
@@ -566,17 +593,18 @@
      * Construct as copy of any object implementing the buffer API.</li> </ul> Although effectively
      * a constructor, it is possible to call __init__ on a 'used' object so the method does not
      * assume any particular prior state.
-     * 
+     *
      * @param args argument array according to Jython conventions
-     * @param kwds Keywords according to Jython conventions 
+     * @param kwds Keywords according to Jython conventions
      * @throws PyException in the same circumstances as bytearray(arg), TypeError for non-iterable,
-     * non-integer argument type, and ValueError if iterables do not yield byte [0..255] values.
+     *             non-integer argument type, and ValueError if iterables do not yield byte [0..255]
+     *             values.
      */
     @ExposedNew
     @ExposedMethod(doc = BuiltinDocs.bytearray___init___doc)
     final synchronized void bytearray___init__(PyObject[] args, String[] kwds) {
-        
-        ArgParser ap = new ArgParser("bytearray", args, kwds, "source", "encoding", "errors");        
+
+        ArgParser ap = new ArgParser("bytearray", args, kwds, "source", "encoding", "errors");
         PyObject arg = ap.getPyObject(0, null);
         // If not null, encoding and errors must be PyString (or PyUnicode)
         PyObject encoding = ap.getPyObjectByType(1, PyBaseString.TYPE, null);
@@ -598,58 +626,278 @@
                 throw Py.TypeError("encoding or errors without sequence argument");
             }
             init((PyString)arg, encoding, errors);
-            
+
         } else {
             // Now construct from arbitrary object (or null)
             init(arg);
         }
 
     }
-    
-    
+
+
+    /* ========================================================================================
+     * Python API rich comparison operations
+     * ========================================================================================
+     */
+
     @Override
-    public int __len__() {
-        return list___len__();
+    public PyObject __eq__(PyObject other) {
+        return basebytes___eq__(other);
     }
 
-    @ExposedMethod(doc = BuiltinDocs.list___len___doc)
-    final int list___len__() {
-        return size;
+    @Override
+    public PyObject __ne__(PyObject other) {
+        return basebytes___ne__(other);
     }
 
-    
+    @Override
+    public PyObject __lt__(PyObject other) {
+        return basebytes___lt__(other);
+    }
+
+    @Override
+    public PyObject __le__(PyObject other) {
+        return basebytes___le__(other);
+    }
+
+    @Override
+    public PyObject __ge__(PyObject other) {
+        return basebytes___ge__(other);
+    }
+
+    @Override
+    public PyObject __gt__(PyObject other) {
+        return basebytes___gt__(other);
+    }
+
+
+
+    @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___eq___doc)
+    final synchronized PyObject bytearray___eq__(PyObject other) {
+        return basebytes___eq__(other);
+    }
+
+    @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___ne___doc)
+    final synchronized PyObject bytearray___ne__(PyObject other) {
+        return basebytes___ne__(other);
+    }
+
+    @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___lt___doc)
+    final synchronized PyObject bytearray___lt__(PyObject other) {
+        return basebytes___lt__(other);
+    }
+
+    @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___le___doc)
+    final synchronized PyObject bytearray___le__(PyObject other) {
+        return basebytes___le__(other);
+    }
+
+    @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___ge___doc)
+    final synchronized PyObject bytearray___ge__(PyObject other) {
+        return basebytes___ge__(other);
+    }
+
+    @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___gt___doc)
+    final synchronized PyObject bytearray___gt__(PyObject other) {
+        return basebytes___gt__(other);
+    }
+
+/* ========================================================================================
+ * Python API for bytearray
+ * ========================================================================================
+ */
+
+    @Override
+    public PyObject __add__(PyObject o) {
+        return bytearray___add__(o);
+    }
+
+    @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___add___doc)
+    final synchronized PyObject bytearray___add__(PyObject o) {
+        PyByteArray sum = null;
+
+        if (o instanceof BaseBytes) {
+            BaseBytes ob = (BaseBytes)o;
+            // Quick route: allocate the right size bytearray and copy the two parts in.
+            sum = new PyByteArray(size + ob.size);
+            System.arraycopy(storage, offset, sum.storage, sum.offset, size);
+            System.arraycopy(ob.storage, ob.offset, sum.storage, sum.offset + size, ob.size);
+
+        } else if (o.getType() == PyString.TYPE) {
+            // Support bytes type, which in in Python 2.7 is an alias of str. Remove in 3.0
+            PyString os = (PyString)o;
+            // Allocate the right size bytearray and copy the two parts in.
+            sum = new PyByteArray(size + os.__len__());
+            System.arraycopy(storage, offset, sum.storage, sum.offset, size);
+            sum.setslice(size, sum.size, 1, os);
+
+        } else {
+            // Unsuitable type
+            // XXX note reversed order relative to __iadd__ may be wrong, matches Python 2.7
+            throw ConcatenationTypeError(TYPE, o.getType());
+        }
+
+        return sum;
+    }
+
+
+    /**
+     * Returns the number of bytes actually allocated.
+     */
+    public int __alloc__() {
+        return bytearray___alloc__();
+    }
+
+    @ExposedMethod(doc = BuiltinDocs.bytearray___alloc___doc)
+    final int bytearray___alloc__() {
+        return storage.length;
+    }
+
+    /**
+     * Append a single element to the end of the array, equivalent to:
+     * <code>s[len(s):len(s)] = o</code>. The argument must be a PyInteger, PyLong or string of length 1.
+     *
+     * @param o the item to append to the list.
+     */
+    public void append(PyObject o) {
+        bytearray_append(o);
+    }
+
+    @ExposedMethod(doc = BuiltinDocs.bytearray_append_doc)
+    final synchronized void bytearray_append(PyObject o) {
+        // Insert at the end, checked for type and range
+        pyinsert(size, o);
+    }
+
+    @ExposedMethod(doc = BuiltinDocs.bytearray___contains___doc)
+    final boolean bytearray___contains__(PyObject o) {
+        return basebytes___contains__(o);
+    }
+
+    @ExposedMethod(doc = BuiltinDocs.bytearray_decode_doc)
+    final PyObject bytearray_decode(PyObject[] args, String[] keywords) {
+        return basebytes_decode(args, keywords);
+    }
+
+    /**
+     * Implementation of Python <code>find(sub)</code>. Return the lowest index in the byte array
+     * where byte sequence <code>sub</code> is found. Return -1 if <code>sub</code> is not found.
+     *
+     * @param sub bytes to find
+     * @return index of start of ocurrence of sub within this byte array
+     */
+    public int find(PyObject sub) {
+        return basebytes_find(sub, null, null);
+    }
+
+    /**
+     * Implementation of Python <code>find( sub [, start ] )</code>. Return the lowest index in the
+     * byte array where byte sequence <code>sub</code> is found, such that <code>sub</code> is
+     * contained in the slice <code>[start:]</code>. Return -1 if <code>sub</code> is not found.
+     *
+     * @param sub bytes to find
+     * @param start of slice to search
+     * @return index of start of ocurrence of sub within this byte array
+     */
+    public int find(PyObject sub, PyObject start) {
+        return basebytes_find(sub, start, null);
+    }
+
+    /**
+     * Implementation of Python <code>find( sub [, start [, end ]] )</code>. Return the lowest index
+     * in the byte array where byte sequence <code>sub</code> is found, such that <code>sub</code>
+     * is contained in the slice <code>[start:end]</code>. Arguments <code>start</code> and
+     * <code>end</code> (which may be <code>null</code> or <code>Py.None</code> ) are interpreted as
+     * in slice notation. Return -1 if <code>sub</code> is not found.
+     *
+     * @param sub bytes to find
+     * @param start of slice to search
+     * @param end of slice to search
+     * @return index of start of ocurrence of sub within this byte array
+     */
+    public int find(PyObject sub, PyObject start, PyObject end) {
+        return basebytes_find(sub, start, end);
+    }
+
+    @ExposedMethod(defaults = {"null", "null"}, doc = BuiltinDocs.bytearray_find_doc)
+    final int bytearray_find(PyObject sub, PyObject start, PyObject end) {
+        return basebytes_find(sub, start, end);
+    }
+
+
+
+    /**
+     * Append the elements in the argument sequence to the end of the array, equivalent to:
+     * <code>s[len(s):len(s)] = o</code>. The argument must be a subclass of BaseBytes or an
+     * iterable type returning elements compatible with byte assignment.
+     *
+     * @param o the sequence of items to append to the list.
+     */
+    public void extend(PyObject o) {
+        bytearray_extend(o);
+    }
+
+    @ExposedMethod(doc = BuiltinDocs.bytearray_extend_doc)
+    final synchronized void bytearray_extend(PyObject o) {
+        // Use the general method, assigning to the crack at the end of the array.
+        // Note this deals with all legitimate PyObject types and the case o==this.
+        setslice(size, size, 1, o);
+    }
+
+    @Override
+    public PyObject __iadd__(PyObject o) {
+        return bytearray___iadd__(o);
+    }
+
+    @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___iadd___doc)
+    final synchronized PyObject bytearray___iadd__(PyObject o) {
+        PyType oType = o.getType();
+        if (oType == TYPE) {
+            // Use the general method, specifying the crack at the end of the array.
+            // Note this deals with the case o==this.
+            setslice(size, size, 1, (BaseBytes)o);
+        } else if (oType == PyString.TYPE) {
+            // Will fail if somehow not 8-bit clean
+            setslice(size, size, 1, (PyString)o);
+        } else {
+            // Unsuitable type
+            throw ConcatenationTypeError(oType, TYPE);
+        }
+        return this;
+    }
+
+    /**
+     * Insert the argument element into the byte array at the specified index.
+     * Same as <code>s[index:index] = [o] if index &gt;= 0</code>.
+     *
+     * @param index the position where the element will be inserted.
+     * @param value the element to insert.
+     */
+    public void insert(PyObject index, PyObject value) {
+        bytearray_insert(index, value);
+    }
+
+    @ExposedMethod(doc = BuiltinDocs.bytearray_insert_doc)
+    final synchronized void bytearray_insert(PyObject index, PyObject value) {
+        // XXX: do something with delegator instead?
+        pyinsert(boundToSequence(index.asIndex()), value);
+    }
+
+
+    @ExposedMethod(doc = BuiltinDocs.bytearray___len___doc)
+    final int bytearray___len__() {
+        return __len__();
+    }
+
+    @ExposedMethod(doc = BuiltinDocs.bytearray___reduce___doc)
+    final PyObject bytearray___reduce__() {
+        return basebytes___reduce__();
+    }
+
+
+
 // Based on PyList and not yet properly implemented.
 //
-//    @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___ne___doc)
-//    final synchronized PyObject bytearray___ne__(PyObject o) {
-//        return seq___ne__(o);
-//    }
-//
-//    @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___eq___doc)
-//    final synchronized PyObject bytearray___eq__(PyObject o) {
-//        return seq___eq__(o);
-//    }
-//
-//    @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___lt___doc)
-//    final synchronized PyObject bytearray___lt__(PyObject o) {
-//        return seq___lt__(o);
-//    }
-//
-//    @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___le___doc)
-//    final synchronized PyObject bytearray___le__(PyObject o) {
-//        return seq___le__(o);
-//    }
-//
-//    @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___gt___doc)
-//    final synchronized PyObject bytearray___gt__(PyObject o) {
-//        return seq___gt__(o);
-//    }
-//
-//    @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___ge___doc)
-//    final synchronized PyObject bytearray___ge__(PyObject o) {
-//        return seq___ge__(o);
-//    }
-//
 //    @Override
 //    public PyObject __imul__(PyObject o) {
 //        return bytearray___imul__(o);
@@ -714,37 +962,6 @@
 //        return repeat(o.asIndex(Py.OverflowError));
 //    }
 //
-//    @Override
-//    public PyObject __add__(PyObject o) {
-//        return bytearray___add__(o);
-//    }
-//
-//    @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___add___doc)
-//    final synchronized PyObject bytearray___add__(PyObject o) {
-//        PyByteArray sum = null;
-//        if (o instanceof PySequenceList && !(o instanceof PyTuple)) {
-//            if (o instanceof PyByteArray) {
-//                List oList = ((PyByteArray) o).storage;
-//                List newList = new ArrayList(storage.size() + oList.size());
-//                newList.addAll(storage);
-//                newList.addAll(oList);
-//                sum = fromList(newList);
-//            }
-//        } else if (!(o instanceof PySequenceList)) {
-//            // also support adding java lists (but not PyTuple!)
-//            Object oList = o.__tojava__(List.class);
-//            if (oList != Py.NoConversion && oList != null) {
-//                List otherList = (List) oList;
-//                sum = new PyByteArray();
-//                sum.bytearray_extend(this);
-//                for (Iterator i = otherList.iterator(); i.hasNext();) {
-//                    sum.add(i.next());
-//                }
-//            }
-//        }
-//        return sum;
-//    }
-//
 //    @ExposedMethod(doc = BuiltinDocs.bytearray___contains___doc)
 //    final synchronized boolean bytearray___contains__(PyObject o) {
 //        return object___contains__(o);
@@ -787,275 +1004,238 @@
 //        return super.unsupportedopMessage(op, o2);
 //    }
 //
-//    public String toString() {
-//        return bytearray_toString();
-//    }
-//
-    @ExposedMethod(names = "__repr__", doc = BuiltinDocs.bytearray___repr___doc)
-    final synchronized String bytearray_toString() {
-        // XXX revisit: understand the thread state logic and use encode()
-//        ThreadState ts = Py.getThreadState();
-//        if (!ts.enterRepr(this)) {
-//            return "[...]";
-//        }
-        StringBuilder buf = new StringBuilder("bytearray(b'");
-        final int last = size()-1;
-        for (int i=0; i<=last; i++) {
-            int element = intAt(i);
-            if (Character.isISOControl(element))
-                buf.append(String.format("\\x%02x", element));
-            else
-                buf.append((char)element);
-        }
-        buf.append("')");
-//        ts.exitRepr(this);
-        return buf.toString();
+    @Override
+    public String toString() {
+        return bytearray_toString();
     }
 
-    
-    
-    
-    
+    @ExposedMethod(names = {"__repr__", "__str__"}, doc = BuiltinDocs.bytearray___repr___doc)
+    final synchronized String bytearray_toString() {
+        return "bytearray(b'" + asEscapedString()  + "')";
+    }
+
     /*
      * ========================================================================================
      * Manipulation of storage capacity
      * ========================================================================================
-     * 
+     *
      * Here we add to the inherited variables defining byte storage, the methods necessary to resize
      * it.
-     */    
-   
+     */
+
     /**
      * Choose a size appropriate to store the given number of bytes, with some room for growth.
-     * @param size
-     * @return n >= needed
+     * We'll be more generous than CPython for small array sizes to avoid needless reallocation.
+     *
+     * @param size of storage actually needed
+     * @return n >= size a recommended storage array size
      */
     private static final int roundUp(int size) {
-        // XXX Consider equivalent case statement
-        int alloc = size + (size >> 3) + (size < 9 ? 3 : 6);    // As CPython
-        // XXX What's a good allocation unit size here?
-        final int ALLOC = 8;
-        return (alloc+(ALLOC-1)) & ~(ALLOC-1);                  // round up to multiple of ALLOC
-    }
-    
-    /**
-     * Used mainly to prevent repeated attempts to shrink an array that is already minimal.
-     */
-    private static final int minAlloc = roundUp(1);
-        
-    /**
-     * Decide whether a new storage array should be allocated (but don't do it). This method returns
-     * true if the needed storage is bigger than the allocated array length.
-     * 
-     * @param needed number of bytes needed
-     * @return true if needed number of bytes justifies a new array
-     */
-    private final boolean shouldGrow(int needed) {
-        return needed > storage.length;
+        /*
+         * The CPython formula is: size + (size >> 3) + (size < 9 ? 3 : 6). But when the array
+         * grows, CPython can use a realloc(), which will often be able to extend the allocation
+         * into memory already secretly allocated by the initial malloc(). Extension in Java means
+         * that we have to allocate a new array of bytes and copy to it.
+         */
+        final int ALLOC = 16;   // Must be power of two!
+        final int SIZE2 = 10;   // Smallest size leading to a return value of 2*ALLOC
+        if (size >= SIZE2) {       // Result > ALLOC, so work it out
+            // Same recommendation as Python, but rounded up to multiple of ALLOC
+            return (size + (size >> 3) + (6 + ALLOC - 1)) & ~(ALLOC - 1);
+        } else if (size > 0) {  // Easy: save arithmetic
+            return ALLOC;
+        } else {                // Very easy
+            return 0;
+        }
     }
 
     /**
-     * Decide whether a smaller storage array should be allocated (but don't do it). This method
-     * returns true if the needed storage size is much smaller than the allocated array length.
-     * 
+     * Recommend a length for (but don't allocate) a new storage array, taking into account the
+     * current length and the number of bytes now needed. The returned value will always be at least
+     * as big as the argument (the length will always be sufficient). If the return value is equal
+     * to the present length, it is recommending no reallocation; otherwise, the return is either
+     * comfortably bigger than what is currently needed, or significantly smaller than currently
+     * allocated. This method embeds our policy for growing or shrinking the allocated array.
+     *
      * @param needed number of bytes needed
-     * @return true if needed number of bytes justifies a new array
+     * @return recommended amount to allocate
      */
-    private final boolean shouldShrink(int needed) {
-        return needed == 0 || (needed * 2 + minAlloc) < storage.length;
-    }
-
-    /**
-     * Decide whether a new storage array should be allocated (but don't do it). This method returns
-     * true if the needed storage is bigger, or much smaller, than the allocated array length.
-     * 
-     * @param needed number of bytes needed
-     * @return true if needed number of bytes justifies a new array
-     */
-    private final boolean shouldResize(int needed) {
-        return shouldGrow(needed) || shouldShrink(needed);
+    private final int recLength(int needed) {
+        final int L = storage.length;
+        if (needed > L || needed * 2 < L) {
+            // Amount needed is a lot less than current length, or
+            // more space we have, so recommend the new ideal size.
+            return roundUp(needed);
+        } else {
+            // Amount needed is less than current length, but it doesn't justify reallocation
+            return L;
+        }
     }
 
     /**
      * Allocate fresh storage for at least the requested number of bytes. Spare bytes are alloceted
-     * evenly at each end of the new storage by choice of a new value for offset.
-     * If the size needed is zero, the "storage" allocated is the shared emptyStorage array.
+     * evenly at each end of the new storage by choice of a new value for offset. If the size needed
+     * is zero, the "storage" allocated is the shared emptyStorage array.
+     *
      * @param needed becomes the new value of this.size
      */
     protected void newStorage(int needed) {
         if (needed > 0) {
-            byte[] s = new byte[roundUp(needed)]; // guaranteed zero (by JLS 2ed para 4.5.5)
-            setStorage(s, needed, (s.length - needed) / 2);
-        } else
+            final int L = recLength(needed);
+            byte[] s = new byte[L]; // guaranteed zero (by JLS 2ed para 4.5.5)
+            setStorage(s, needed, (L - needed) / 2);
+        } else {
             setStorage(emptyStorage);
+        }
     }
 
     /**
-     * Ensure there is storage for at least the requested number of bytes, optionally clearing
-     * elements to zero. After the call, the needed number of bytes will be available,
-     * and if requested in the second parameter, they are guaranteed to be zero.
-     * @param needed number of bytes
-     * @param clear if true, storage bytes guaranteed zero
-     */
-    private void newStorage(int needed, boolean clear) {
-        if (shouldResize(needed)) {
-            newStorage(needed);                 // guaranteed zero
-        } else {
-            setStorage(storage, needed, (storage.length - needed) / 2);
-            if (clear) {
-                Arrays.fill(storage, (byte)0); // guarantee zero
-            }
-        }
-    }
-
-
-    
-    /**
-     * Delete <code>d</code> elements at index <code>a</code> and prepare to insert
-     * <code>e</code> elements there by moving aside the surrounding elements.
-     * The method manipulates the <code>storage</code> array contents, <code>size</code> and
-     * <code>offset</code>. It will allocate a new array <code>storage</code> if necessary,
-     * or if desirable for efficiency. If the initial storage looks like this:
+     * Delete <code>d</code> elements at index <code>a</code> and prepare to insert <code>e</code>
+     * elements there by moving aside the surrounding elements. The method manipulates the
+     * <code>storage</code> array contents, <code>size</code> and <code>offset</code>. It will
+     * allocate a new array <code>storage</code> if necessary, or if desirable for efficiency. If
+     * the initial storage looks like this:
+     *
      * <pre>
      *       |-                  s                -|
      * |--f--|--------a--------|---d---|-----b-----|----------------|
      * </pre>
+     *
      * then after the call the (possibly new) storage looks like this:
+     *
      * <pre>
      *            |-                   s'                -|
      * |----f'----|--------a--------|----e----|-----b-----|--------------|
      * </pre>
+     *
      * where the contents of regions of length <code>a</code> and <code>b=size-(a+d)</code> have
-     * been preserved, although probably moved, and the gap between them has been adjusted to
-     * the requested size.
+     * been preserved, although probably moved, and the gap between them has been adjusted to the
+     * requested size.
      * <p>
      * The effect on this PyByteArray is that:
+     *
      * <pre>
      * this.offset = f'
      * this.size = s' = a + e + b
      * </pre>
-     * The method does not implement the Python repertoire of slice indices but avoids indexing
-     * outside the bytearray by silently adjusting a to be within it.
-     * Negative d or e is treated as 0 and if d is too large, it is truncated to the array end.
-     * @param a index of hole in byte array 
+     *
+     * The method does not implement the Python repertoire of slice indices, or bound-check the
+     * sizes given, since code leading up to the call has done that.
+     *
+     * @param a index of hole in byte array
      * @param d number to discard (will discard x[a,a+d-1])
      * @param e size of hole to open (will be x[a, a+e-1])
      */
     private void storageReplace(int a, int d, int e) {
 
-        int s = this.size;
+        final int c = e - d; // Change in overall size
+        if (c == 0)
+         {
+            return; // Everything stays where it is.
+        }
 
-        // Some of these should perhaps be errors but let's silently correct insane requests
-        if (a<0) a=0; else if (a>s) a = s;
-        if (d<0) d=0; else if (d>s-a) d = s-a;
-        if (e<0) e=0;
+        // Compute some handy points of reference
+        final int L = storage.length;
+        final int f = offset;
+        final int b = size - (a + d); // Count of B section
+        final int s2 = a + e + b; // Size of result s'
+        final int L2 = recLength(s2); // Length of storage for result
 
-        if (e != d) {
-            // Otherwise, everything stays where it is.
-            // Handy derived values:
-            int b = s - (a + d);    // which is >= 0
-            int s2 = a + e + b;     // which is >= 0
-            int f = this.offset;    // Location of x[0]
-            int g = f + (a + d);    // Location of x[-b]
-            
-            if (shouldShrink(s2)) {
-                if (s2 > 0) {
-                    // We have far more storage than we need: shrink and copy both parts
-                    newStorage(f, a, g, b, e);
-                } else {
-                    // Need no storage as a+e+b = 0
-                    setStorage(emptyStorage);
-                }
+        if (L2 == L) {
+            // The result will definitely fit into the existing array
 
-            } else if (a < b) {
+            if (a <= b) {
+
                 // It would be less copying if we moved A=x[:a] not B=x[-b:].
                 // If B is to stay where it is, it means A will land here:
-                int f2 = f - (e - d);
+                final int f2 = f - c;
                 if (f2 >= 0) {
                     // ... which luckily is still inside the array
                     if (a > 0) {
                         System.arraycopy(storage, f, storage, f2, a);
                     }
-                    this.offset = f2;
+                    offset = f2;
                     size = s2;
+
                 } else {
                     // ... which unfortunately is before the start of the array.
-                    // We have to move both A and B and it might be time for a new array.
-                    if (s2<=storage.length) {
-                        // Repack it all in the existing array
-                        newStorageAvoided(f, a, g, b, e);
-                    } else {
-                        newStorage(f, a, g, b, e);
-                    }
+                    // We have to move both A and B within the existing array
+                    newStorageAvoided(a, d, b, e);
                 }
 
-            } else /* a >= b */{
+            } else /* a > b */{
+
                 // It would be less copying if we moved B=x[-b:] not A=x[:a]
                 // If A is to stay where it is, it means B will land here:
-                int g2 = g + (e - d);
-                if (g2 + b <= storage.length) {
+                final int g2 = f + a + e;
+                if (g2 + b <= L) {
                     // ... which luckily leaves all of B inside the array
                     if (b > 0) {
-                        System.arraycopy(storage, g, storage, g2, b);
+                        System.arraycopy(storage, g2 - c, storage, g2, b);
                     }
                     // this.offset is unchanged
                     size = s2;
+
                 } else {
                     // ... which unfortunately runs beyond the end of the array.
-                    // We have to move both A and B and it might be time for a new array.
-                    if (s2<=storage.length) {
-                        // Repack it all in the existing array
-                        newStorageAvoided(f, a, g, b, e);
-                    } else {
-                        newStorage(f, a, g, b, e);
-                    }
+                    // We have to move both A and B within the existing array
+                    newStorageAvoided(a, d, b, e);
                 }
             }
+
+        } else if (L2 > 0) {
+
+            // New storage (bigger or much smaller) is called for. Copy A and B to it.
+            newStorage(L2, a, d, b, e);
+
+        } else {
+
+            // We need no storage at all
+            setStorage(emptyStorage);
+
         }
+    }
 
-    }
-    
-   
     /**
      * Use the existing storage but move two blocks within it to leave a gap of the required size.
-     * This is the strategy usually used when the array is still big enough to hold the required
-     * new value, but we can't leave either block fixed.
-     * If the initial storage looks like this:
-     * 
+     * This is the strategy usually used when the array is still big enough to hold the required new
+     * value, but we can't leave either block fixed. If the initial storage looks like this:
+     *
      * <pre>
      * |-----f-----|--------a--------|---d---|----------b----------|----------|
      * </pre>
-     * 
+     *
      * then after the call the storage looks like this:
-     * 
+     *
      * <pre>
      *        |-                             s'                          -|
      * |--f'--|--------a--------|---------e---------|----------b----------|---|
      * </pre>
-     * 
+     *
      * where the regions of length <code>a</code> and <code>b=size-(a+d)</code> have been preserved
      * and the gap between them adjusted to specification. The new offset f' is chosen heuristically
      * by the method to optimise the efficiency of repeated adjustment near either end of the array,
      * e.g. repeated prepend or append operations. The effect on this PyByteArray is that:
-     * 
+     *
      * <pre>
      * this.offset = f'
      * this.size = s' = a+e+b
      * </pre>
-     * 
-     * Arguments are not checked for validity <b>at all</b>.
-     * a, e and b are non-negative and not all zero.
-     * 
-     * @param f location (with offset) of A
+     *
+     * Arguments are not checked for validity <b>at all</b>. At call time, a, d, b, and e are
+     * non-negative and not all zero.
+     *
      * @param a length of A
-     * @param g = f+a+d location (with offset) of B
+     * @param d gap between A and B in current storage layout
      * @param b length of B
-     * @param e gap between A and B in new storage.
+     * @param e gap between A and B in new storage layout.
      */
-    private void newStorageAvoided(int f, int a, int g, int b, int e) {
+    private void newStorageAvoided(int a, int d, int b, int e) {
 
-        // Shorthands
-        int s2 = a + e + b;
+        // Compute some handy points of reference
+        final int f = offset;
+        final int g = f + a + d; // Location of B section x[-b]
+        final int s2 = a + e + b; // Size of result s'
 
         // Choose the new offset f' to make prepend or append operations quicker.
         // E.g. if insertion was near the end (b small) put most of the new space at the end.
@@ -1068,164 +1248,201 @@
             long spare = storage.length - s2;
             f2 = (int)((spare * b) / (a + b));
         }
-        // We have a new size and offset (but the same storage)
-        size = s2;
-        offset = f2;
-        
+
         // This puts B at
-        int g2 = f2 + a + e;
+        final int g2 = f2 + a + e;
 
         // We can make do with the existing array. Do an in place copy.
         if (f2 + a > g) {
             // New A overlaps existing B so we must copy B first
-            if (b > 0) System.arraycopy(storage, g, storage, g2, b);
-            if (a > 0) System.arraycopy(storage, f, storage, f2, a);
+            if (b > 0) {
+                System.arraycopy(storage, g, storage, g2, b);
+            }
+            if (a > 0) {
+                System.arraycopy(storage, f, storage, f2, a);
+            }
         } else {
             // Safe to copy A first
-            if (a > 0) System.arraycopy(storage, f, storage, f2, a);
-            if (b > 0) System.arraycopy(storage, g, storage, g2, b);
+            if (a > 0) {
+                System.arraycopy(storage, f, storage, f2, a);
+            }
+            if (b > 0) {
+                System.arraycopy(storage, g, storage, g2, b);
+            }
         }
 
+        // We have a new size and offset (but the same storage)
+        size = s2;
+        offset = f2;
+
     }
-    
 
     /**
      * Allocate new storage and copy two blocks from the current storage to it. If the initial
      * storage looks like this:
-     * 
+     *
      * <pre>
      * |--f--|--------a--------|---d---|-----b-----|----------------|
      * </pre>
-     * 
+     *
      * then after the call the (definitely new) storage looks like this:
-     * 
+     *
      * <pre>
      *            |-                   s'                -|
      * |----f'----|--------a--------|----e----|-----b-----|--------------|
      * </pre>
-     * 
+     *
      * where the regions of length <code>a</code> and <code>b=size-(a+d)</code> have been preserved
      * and the gap between them adjusted to specification. The new offset f' is chosen heuristically
      * by the method to optimise the efficiency of repeated adjustment near either end of the array,
      * e.g. repeated prepend or append operations. The effect on this PyByteArray is that:
-     * 
+     *
      * <pre>
      * this.offset = f'
      * this.size = s' = a+e+b
      * </pre>
-     * 
-     * Arguments are not checked for validity <b>at all</b>.
-     * a, e and b are non-negative and not all zero.
-     * 
-     * @param f location (with offset) of A
+     *
+     * Arguments are not checked for validity <b>at all</b>. At call time, a, e and b are
+     * non-negative and not all zero.
+     *
+     * @param L2 length of storage array to allocate (decided by caller)
      * @param a length of A
-     * @param g = f+a+d location (with offset) of B
+     * @param d gap between A and B in current storage layout
      * @param b length of B
-     * @param e gap between A and B in new storage.
+     * @param e gap between A and B in new storage layout.
      */
-    private void newStorage(int f, int a, int g, int b, int e) {
-        // Enough room for the data and the gap
-        int s2 = a + e + b;
-        // Preserve a reference to the current data in the storage being discarded
-        byte[] source = this.storage;
-        // New storage with a bit of elbow-room
-        byte[] newStorage = new byte[roundUp(s2)];
-        // Choose the new offset f' to make prepend or append operations quicker.
+    private void newStorage(int L2, int a, int d, int b, int e) {
+
+        // Compute some handy points of reference
+        final int f = offset;
+        final int g = f + a + d; // Location of B section x[-b]
+        final int s2 = a + e + b; // Size of result s'
+
+        // New storage as specified by caller
+        byte[] newStorage = new byte[L2];
+
+        // Choose the new offset f' to make repeated prepend or append operations quicker.
         // E.g. if insertion was near the end (b small) put most of the new space at the end.
         int f2;
         if (a == b) {
             // Mainly to trap the case a=b=0
-            f2 = (newStorage.length - s2) / 2;
+            f2 = (L2 - s2) / 2;
         } else {
             // a and b are not both zero (since not equal)
-            long spare = newStorage.length - s2;
+            long spare = L2 - s2;
             f2 = (int)((spare * b) / (a + b));
         }
+
+        // Copy across the data from existing to new storage.
+        if (a > 0) {
+            System.arraycopy(storage, f, newStorage, f2, a);
+        }
+        if (b > 0) {
+            System.arraycopy(storage, g, newStorage, f2 + a + e, b);
+        }
         setStorage(newStorage, s2, f2);
-
-        // Copy across the data
-        if (a > 0) System.arraycopy(source, f, storage, offset, a);
-        if (b > 0) System.arraycopy(source, g, storage, offset + (a + e), b);
     }
-    
 
     /**
      * Delete <code>d</code> elements at index <code>a</code> by moving together the surrounding
      * elements. The method manipulates the <code>storage</code> array, <code>size</code> and
      * <code>offset</code>, and will allocate a new storage array if necessary, or if the deletion
      * is big enough. If the initial storage looks like this:
-     * 
+     *
      * <pre>
      * |-                           L                              -|
      *       |-                  s                -|
      * |--f--|--------a--------|---d---|-----b-----|----------------|
      * </pre>
-     * 
+     *
      * then after the call the (possibly new) storage looks like this:
-     * 
+     *
      * <pre>
      * |-                 L'                     -|
      *      |-                  s'               -|
      * |-f'-|--------a--------|-----b-----|-------|
      * </pre>
-     * 
+     *
      * where the regions of length <code>a</code> and <code>b=size-(a+d)</code> have been preserved
      * and the gap between them eliminated. The effect on this PyByteArray is that:
-     * 
+     *
      * <pre>
      * this.offset = f'
      * this.size = s' = a+b
      * </pre>
+     *
      * The method does not implement the Python repertoire of slice indices but avoids indexing
-     * outside the bytearray by silently adjusting a to be within it.
-     * Negative d is treated as 0 and if d is too large, it is truncated to the array end.
-     * 
+     * outside the bytearray by silently adjusting a to be within it. Negative d is treated as 0 and
+     * if d is too large, it is truncated to the array end.
+     *
      * @param a index of hole in byte array
      * @param d number to discard (will discard x[a,a+d-1])
      * @param e size of hole to open (will be x[a, a+e-1])
      */
     private void storageDelete(int a, int d) {
         // storageReplace specialised for delete (e=0)
-        int s = this.size;
 
-        // Some of these should perhaps be errors but let's silently correct insane requests
-        if (a < 0) a = 0; else if (a > s) a = s;
-        if (d < 0) d = 0; else if (d > s - a) d = s - a;
+        if (d == 0)
+         {
+            return; // Everything stays where it is.
+        }
 
-        // Handy derived values
-        int b = s - (a + d);    // which is >= 0
-        int s2 = s - d;         // which is >= 0
-        int f = this.offset;    // Location of x[0]
-        int g = f + (a + d);    // Location of x[-b]
+        // Compute some handy points of reference
+        final int L = storage.length;
+        final int f = offset;
+        final int b = size - (a + d); // Count of B section
+        final int s2 = a + b; // Size of result s'
+        final int L2 = recLength(s2); // Length of storage for result
 
-        if (shouldShrink(s2)) {
-            // We have far more storage than we need: shrink and copy both parts
-            // Preserve a reference to the current data in the storage being discarded
-            byte[] source = this.storage;
-            // New storage with a bit of elbow-room
-            newStorage(s2);
-            // Copy across the data
-            if (a > 0) System.arraycopy(source, f, storage, offset, a);
-            if (b > 0) System.arraycopy(source, g, storage, offset + a, b);
+        if (L2 == L) {
 
-        } else {
-            if (a < b) {
+            // We are re-using the existing array
+            if (a <= b) {
                 // It would be less copying if we moved A=x[:a] not B=x[-b:].
                 // If B is to stay where it is, it means A will land here:
-                int f2 = f + d;
+                final int f2 = f + d;
                 if (a > 0) {
                     System.arraycopy(storage, f, storage, f2, a);
                 }
-                this.offset = f2;
+                offset = f2;
+                size = s2;
 
-            } else /* a >= b */{
+            } else /* a > b */{
                 // It would be less copying if we moved B=x[-b:] not A=x[:a]
                 // If A is to stay where it is, it means B will land here:
-                int g2 = f + a;
+                final int g2 = f + a;
                 if (b > 0) {
-                    System.arraycopy(storage, g, storage, g2, b);
+                    System.arraycopy(storage, g2 + d, storage, g2, b);
                 }
+                // this.offset is unchanged
+                size = s2;
             }
+
+        } else if (L2 > 0) {
+
+            // New storage (much smaller) is called for. Copy A and B to it.
+            final int g = f + a + d; // Location of B section x[-b]
+
+            // Choose the new offset f' to distribute space evenly.
+            int f2 = (L2 - s2) / 2;
+
+            // New storage as specified
+            byte[] newStorage = new byte[L2];
+
+            // Copy across the data from existing to new storage.
+            if (a > 0) {
+                System.arraycopy(storage, f, newStorage, f2, a);
+            }
+            if (b > 0) {
+                System.arraycopy(storage, g, newStorage, f2 + a, b);
+            }
+            setStorage(newStorage, s2, f2);
+
+        } else {
+
+            // Everything must go
+            setStorage(emptyStorage);
+
         }
     }
 
@@ -1234,46 +1451,48 @@
      * <code>a</code> by moving together the surrounding elements. The method manipulates the
      * <code>storage</code> array, <code>size</code> and <code>offset</code>, and will allocate a
      * new storage array if the deletion is big enough. If the initial storage looks like this:
-     * 
+     *
      * <pre>
      * |-                               L                                -|
      *       |-                    s                    -|
      * |--f--|-----a-----|---------e---------|-----b-----|----------------|
      * </pre>
-     * 
+     *
      * then after the call the (possibly new) storage looks like this:
-     * 
+     *
      * <pre>
-     * |-                  L'                  -|
+     * |-                   L'                         -|
      *      |-                s'               -|
      * |-f'-|-----a-----|---(e-d)---|-----b-----|-------|
      * </pre>
-     * 
+     *
      * where the regions of length <code>a</code> and <code>b=size-(a+e)</code> have been preserved
      * and the <code>e</code> intervening elements reduced to <code>e-d</code> elements, by removing
      * exactly the elements with indices (relative to the start of valid data) <code>a+k*c</code>
      * for <code>k=0...d-1</code>. The effect on this PyByteArray is that:
-     * 
+     *
      * <pre>
      * this.offset = f'
      * this.size = s' = a+b
      * </pre>
-     * 
+     *
      * The method does not implement the Python repertoire of slice indices but avoids indexing
      * outside the bytearray by silently adjusting a to be within it. Negative d is treated as 0 and
      * if d is too large, it is truncated to the array end.
-     * 
+     *
      * @param a index of hole in byte array
      * @param c (>0) step size between the locations of elements to delete
      * @param d number to discard (will discard x[a+k*c] for k=0...d-1)
      */
     private void storageDeleteEx(int a, int c, int d) {
-        
+
         // XXX Base this on storageReplace with the same a<b logic but piecewise copy
         // XXX Change SequenceIndexDelegate to use (and PyList to implement) delslice()
     }
 }
 
+
+
 /*
  *  >>> for method in dir(bytearray):
         ...     print method
@@ -1355,4 +1574,4 @@
         upper
         zfill
         >>>
- */
+ */
\ No newline at end of file
diff --git a/src/org/python/core/PyByteArrayDerived.java b/src/org/python/core/PyByteArrayDerived.java
--- a/src/org/python/core/PyByteArrayDerived.java
+++ b/src/org/python/core/PyByteArrayDerived.java
@@ -1,1116 +1,1116 @@
-/* Generated file, do not modify.  See jython/src/templates/gderived.py. */
-package org.python.core;
-
-import java.io.Serializable;
-
-public class PyByteArrayDerived extends PyByteArray implements Slotted {
-
-    public PyObject getSlot(int index) {
-        return slots[index];
-    }
-
-    public void setSlot(int index,PyObject value) {
-        slots[index]=value;
-    }
-
-    private PyObject[]slots;
-
-    private PyObject dict;
-
-    public PyObject fastGetDict() {
-        return dict;
-    }
-
-    public PyObject getDict() {
-        return dict;
-    }
-
-    public void setDict(PyObject newDict) {
-        if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
-            dict=newDict;
-        } else {
-            throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
-        }
-    }
-
-    public void delDict() {
-        // deleting an object's instance dict makes it grow a new one
-        dict=new PyStringMap();
-    }
-
-    public PyByteArrayDerived(PyType subtype) {
-        super(subtype);
-        slots=new PyObject[subtype.getNumSlots()];
-        dict=subtype.instDict();
-    }
-
-    public PyString __str__() {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__str__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__();
-            if (res instanceof PyString)
-                return(PyString)res;
-            throw Py.TypeError("__str__"+" returned non-"+"string"+" (type "+res.getType().fastGetName()+")");
-        }
-        return super.__str__();
-    }
-
-    public PyString __repr__() {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__repr__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__();
-            if (res instanceof PyString)
-                return(PyString)res;
-            throw Py.TypeError("__repr__"+" returned non-"+"string"+" (type "+res.getType().fastGetName()+")");
-        }
-        return super.__repr__();
-    }
-
-    public PyString __hex__() {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__hex__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__();
-            if (res instanceof PyString)
-                return(PyString)res;
-            throw Py.TypeError("__hex__"+" returned non-"+"string"+" (type "+res.getType().fastGetName()+")");
-        }
-        return super.__hex__();
-    }
-
-    public PyString __oct__() {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__oct__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__();
-            if (res instanceof PyString)
-                return(PyString)res;
-            throw Py.TypeError("__oct__"+" returned non-"+"string"+" (type "+res.getType().fastGetName()+")");
-        }
-        return super.__oct__();
-    }
-
-    public PyFloat __float__() {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__float__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__();
-            if (res instanceof PyFloat)
-                return(PyFloat)res;
-            throw Py.TypeError("__float__"+" returned non-"+"float"+" (type "+res.getType().fastGetName()+")");
-        }
-        return super.__float__();
-    }
-
-    public PyComplex __complex__() {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__complex__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__();
-            if (res instanceof PyComplex)
-                return(PyComplex)res;
-            throw Py.TypeError("__complex__"+" returned non-"+"complex"+" (type "+res.getType().fastGetName()+")");
-        }
-        return super.__complex__();
-    }
-
-    public PyObject __pos__() {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__pos__");
-        if (impl!=null)
-            return impl.__get__(this,self_type).__call__();
-        return super.__pos__();
-    }
-
-    public PyObject __neg__() {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__neg__");
-        if (impl!=null)
-            return impl.__get__(this,self_type).__call__();
-        return super.__neg__();
-    }
-
-    public PyObject __abs__() {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__abs__");
-        if (impl!=null)
-            return impl.__get__(this,self_type).__call__();
-        return super.__abs__();
-    }
-
-    public PyObject __invert__() {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__invert__");
-        if (impl!=null)
-            return impl.__get__(this,self_type).__call__();
-        return super.__invert__();
-    }
-
-    public PyObject __reduce__() {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__reduce__");
-        if (impl!=null)
-            return impl.__get__(this,self_type).__call__();
-        return super.__reduce__();
-    }
-
-    public PyObject __add__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__add__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__add__(other);
-    }
-
-    public PyObject __radd__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__radd__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__radd__(other);
-    }
-
-    public PyObject __sub__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__sub__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__sub__(other);
-    }
-
-    public PyObject __rsub__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__rsub__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__rsub__(other);
-    }
-
-    public PyObject __mul__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__mul__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__mul__(other);
-    }
-
-    public PyObject __rmul__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__rmul__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__rmul__(other);
-    }
-
-    public PyObject __div__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__div__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__div__(other);
-    }
-
-    public PyObject __rdiv__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__rdiv__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__rdiv__(other);
-    }
-
-    public PyObject __floordiv__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__floordiv__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__floordiv__(other);
-    }
-
-    public PyObject __rfloordiv__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__rfloordiv__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__rfloordiv__(other);
-    }
-
-    public PyObject __truediv__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__truediv__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__truediv__(other);
-    }
-
-    public PyObject __rtruediv__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__rtruediv__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__rtruediv__(other);
-    }
-
-    public PyObject __mod__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__mod__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__mod__(other);
-    }
-
-    public PyObject __rmod__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__rmod__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__rmod__(other);
-    }
-
-    public PyObject __divmod__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__divmod__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__divmod__(other);
-    }
-
-    public PyObject __rdivmod__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__rdivmod__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__rdivmod__(other);
-    }
-
-    public PyObject __rpow__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__rpow__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__rpow__(other);
-    }
-
-    public PyObject __lshift__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__lshift__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__lshift__(other);
-    }
-
-    public PyObject __rlshift__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__rlshift__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__rlshift__(other);
-    }
-
-    public PyObject __rshift__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__rshift__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__rshift__(other);
-    }
-
-    public PyObject __rrshift__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__rrshift__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__rrshift__(other);
-    }
-
-    public PyObject __and__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__and__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__and__(other);
-    }
-
-    public PyObject __rand__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__rand__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__rand__(other);
-    }
-
-    public PyObject __or__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__or__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__or__(other);
-    }
-
-    public PyObject __ror__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__ror__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__ror__(other);
-    }
-
-    public PyObject __xor__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__xor__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__xor__(other);
-    }
-
-    public PyObject __rxor__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__rxor__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__rxor__(other);
-    }
-
-    public PyObject __lt__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__lt__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__lt__(other);
-    }
-
-    public PyObject __le__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__le__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__le__(other);
-    }
-
-    public PyObject __gt__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__gt__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__gt__(other);
-    }
-
-    public PyObject __ge__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__ge__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__ge__(other);
-    }
-
-    public PyObject __eq__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__eq__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__eq__(other);
-    }
-
-    public PyObject __ne__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__ne__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__ne__(other);
-    }
-
-    public PyObject __iadd__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__iadd__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__iadd__(other);
-    }
-
-    public PyObject __isub__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__isub__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__isub__(other);
-    }
-
-    public PyObject __imul__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__imul__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__imul__(other);
-    }
-
-    public PyObject __idiv__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__idiv__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__idiv__(other);
-    }
-
-    public PyObject __ifloordiv__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__ifloordiv__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__ifloordiv__(other);
-    }
-
-    public PyObject __itruediv__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__itruediv__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__itruediv__(other);
-    }
-
-    public PyObject __imod__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__imod__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__imod__(other);
-    }
-
-    public PyObject __ipow__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__ipow__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__ipow__(other);
-    }
-
-    public PyObject __ilshift__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__ilshift__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__ilshift__(other);
-    }
-
-    public PyObject __irshift__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__irshift__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__irshift__(other);
-    }
-
-    public PyObject __iand__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__iand__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__iand__(other);
-    }
-
-    public PyObject __ior__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__ior__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__ior__(other);
-    }
-
-    public PyObject __ixor__(PyObject other) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__ixor__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(other);
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__ixor__(other);
-    }
-
-    public PyObject __int__() {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__int__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__();
-            if (res instanceof PyInteger||res instanceof PyLong)
-                return res;
-            throw Py.TypeError("__int__"+" should return an integer");
-        }
-        return super.__int__();
-    }
-
-    public PyObject __long__() {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__long__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__();
-            if (res instanceof PyLong||res instanceof PyInteger)
-                return res;
-            throw Py.TypeError("__long__"+" returned non-"+"long"+" (type "+res.getType().fastGetName()+")");
-        }
-        return super.__long__();
-    }
-
-    public int hashCode() {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__hash__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__();
-            if (res instanceof PyInteger) {
-                return((PyInteger)res).getValue();
-            } else
-                if (res instanceof PyLong) {
-                    return((PyLong)res).getValue().intValue();
-                }
-            throw Py.TypeError("__hash__ should return a int");
-        }
-        if (self_type.lookup("__eq__")!=null||self_type.lookup("__cmp__")!=null) {
-            throw Py.TypeError(String.format("unhashable type: '%.200s'",getType().fastGetName()));
-        }
-        return super.hashCode();
-    }
-
-    public PyUnicode __unicode__() {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__unicode__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__();
-            if (res instanceof PyUnicode)
-                return(PyUnicode)res;
-            if (res instanceof PyString)
-                return new PyUnicode((PyString)res);
-            throw Py.TypeError("__unicode__"+" should return a "+"unicode");
-        }
-        return super.__unicode__();
-    }
-
-    public int __cmp__(PyObject other) {
-        PyType self_type=getType();
-        PyObject[]where_type=new PyObject[1];
-        PyObject impl=self_type.lookup_where("__cmp__",where_type);
-        // Full Compatibility with CPython __cmp__:
-        // If the derived type don't override __cmp__, the
-        // *internal* super().__cmp__ should be called, not the
-        // exposed one. The difference is that the exposed __cmp__
-        // throws a TypeError if the argument is an instance of the same type.
-        if (impl==null||where_type[0]==TYPE||Py.isSubClass(TYPE,where_type[0])) {
-            return super.__cmp__(other);
-        }
-        PyObject res=impl.__get__(this,self_type).__call__(other);
-        if (res==Py.NotImplemented) {
-            return-2;
-        }
-        int c=res.asInt();
-        return c<0?-1:c>0?1:0;
-    }
-
-    public boolean __nonzero__() {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__nonzero__");
-        if (impl==null) {
-            impl=self_type.lookup("__len__");
-            if (impl==null)
-                return super.__nonzero__();
-        }
-        PyObject o=impl.__get__(this,self_type).__call__();
-        Class c=o.getClass();
-        if (c!=PyInteger.class&&c!=PyBoolean.class) {
-            throw Py.TypeError(String.format("__nonzero__ should return bool or int, returned %s",self_type.getName()));
-        }
-        return o.__nonzero__();
-    }
-
-    public boolean __contains__(PyObject o) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__contains__");
-        if (impl==null)
-            return super.__contains__(o);
-        return impl.__get__(this,self_type).__call__(o).__nonzero__();
-    }
-
-    public int __len__() {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__len__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__();
-            if (res instanceof PyInteger)
-                return((PyInteger)res).getValue();
-            throw Py.TypeError("__len__ should return a int");
-        }
-        return super.__len__();
-    }
-
-    public PyObject __iter__() {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__iter__");
-        if (impl!=null)
-            return impl.__get__(this,self_type).__call__();
-        impl=self_type.lookup("__getitem__");
-        if (impl==null)
-            return super.__iter__();
-        return new PySequenceIter(this);
-    }
-
-    public PyObject __iternext__() {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("next");
-        if (impl!=null) {
-            try {
-                return impl.__get__(this,self_type).__call__();
-            } catch (PyException exc) {
-                if (exc.match(Py.StopIteration))
-                    return null;
-                throw exc;
-            }
-        }
-        return super.__iternext__(); // ???
-    }
-
-    public PyObject __finditem__(PyObject key) { // ???
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__getitem__");
-        if (impl!=null)
-            try {
-                return impl.__get__(this,self_type).__call__(key);
-            } catch (PyException exc) {
-                if (exc.match(Py.LookupError))
-                    return null;
-                throw exc;
-            }
-        return super.__finditem__(key);
-    }
-
-    public PyObject __finditem__(int key) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__getitem__");
-        if (impl!=null)
-            try {
-                return impl.__get__(this,self_type).__call__(new PyInteger(key));
-            } catch (PyException exc) {
-                if (exc.match(Py.LookupError))
-                    return null;
-                throw exc;
-            }
-        return super.__finditem__(key);
-    }
-
-    public PyObject __getitem__(PyObject key) {
-        // Same as __finditem__, without swallowing LookupErrors. This allows
-        // __getitem__ implementations written in Python to raise custom
-        // exceptions (such as subclasses of KeyError).
-        //
-        // We are forced to duplicate the code, instead of defining __finditem__
-        // in terms of __getitem__. That's because PyObject defines __getitem__
-        // in terms of __finditem__. Therefore, we would end with an infinite
-        // loop when self_type.lookup("__getitem__") returns null:
-        //
-        //  __getitem__ -> super.__getitem__ -> __finditem__ -> __getitem__
-        //
-        // By duplicating the (short) lookup and call code, we are safe, because
-        // the call chains will be:
-        //
-        // __finditem__ -> super.__finditem__
-        //
-        // __getitem__ -> super.__getitem__ -> __finditem__ -> super.__finditem__
-
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__getitem__");
-        if (impl!=null)
-            return impl.__get__(this,self_type).__call__(key);
-        return super.__getitem__(key);
-    }
-
-    public void __setitem__(PyObject key,PyObject value) { // ???
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__setitem__");
-        if (impl!=null) {
-            impl.__get__(this,self_type).__call__(key,value);
-            return;
-        }
-        super.__setitem__(key,value);
-    }
-
-    public PyObject __getslice__(PyObject start,PyObject stop,PyObject step) { // ???
-        if (step!=null) {
-            return __getitem__(new PySlice(start,stop,step));
-        }
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__getslice__");
-        if (impl!=null) {
-            PyObject[]indices=PySlice.indices2(this,start,stop);
-            return impl.__get__(this,self_type).__call__(indices[0],indices[1]);
-        }
-        return super.__getslice__(start,stop,step);
-    }
-
-    public void __setslice__(PyObject start,PyObject stop,PyObject step,PyObject value) {
-        if (step!=null) {
-            __setitem__(new PySlice(start,stop,step),value);
-            return;
-        }
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__setslice__");
-        if (impl!=null) {
-            PyObject[]indices=PySlice.indices2(this,start,stop);
-            impl.__get__(this,self_type).__call__(indices[0],indices[1],value);
-            return;
-        }
-        super.__setslice__(start,stop,step,value);
-    }
-
-    public void __delslice__(PyObject start,PyObject stop,PyObject step) {
-        if (step!=null) {
-            __delitem__(new PySlice(start,stop,step));
-            return;
-        }
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__delslice__");
-        if (impl!=null) {
-            PyObject[]indices=PySlice.indices2(this,start,stop);
-            impl.__get__(this,self_type).__call__(indices[0],indices[1]);
-            return;
-        }
-        super.__delslice__(start,stop,step);
-    }
-
-    public void __delitem__(PyObject key) { // ???
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__delitem__");
-        if (impl!=null) {
-            impl.__get__(this,self_type).__call__(key);
-            return;
-        }
-        super.__delitem__(key);
-    }
-
-    public PyObject __call__(PyObject args[],String keywords[]) {
-        ThreadState ts=Py.getThreadState();
-        if (ts.recursion_depth++>ts.systemState.getrecursionlimit())
-            throw Py.RuntimeError("maximum __call__ recursion depth exceeded");
-        try {
-            PyType self_type=getType();
-            PyObject impl=self_type.lookup("__call__");
-            if (impl!=null)
-                return impl.__get__(this,self_type).__call__(args,keywords);
-            return super.__call__(args,keywords);
-        } finally {
-            --ts.recursion_depth;
-        }
-    }
-
-    public PyObject __findattr_ex__(String name) {
-        return Deriveds.__findattr_ex__(this,name);
-    }
-
-    public void __setattr__(String name,PyObject value) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__setattr__");
-        if (impl!=null) {
-            impl.__get__(this,self_type).__call__(PyString.fromInterned(name),value);
-            return;
-        }
-        super.__setattr__(name,value);
-    }
-
-    public void __delattr__(String name) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__delattr__");
-        if (impl!=null) {
-            impl.__get__(this,self_type).__call__(PyString.fromInterned(name));
-            return;
-        }
-        super.__delattr__(name);
-    }
-
-    public PyObject __get__(PyObject obj,PyObject type) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__get__");
-        if (impl!=null) {
-            if (obj==null)
-                obj=Py.None;
-            if (type==null)
-                type=Py.None;
-            return impl.__get__(this,self_type).__call__(obj,type);
-        }
-        return super.__get__(obj,type);
-    }
-
-    public void __set__(PyObject obj,PyObject value) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__set__");
-        if (impl!=null) {
-            impl.__get__(this,self_type).__call__(obj,value);
-            return;
-        }
-        super.__set__(obj,value);
-    }
-
-    public void __delete__(PyObject obj) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__delete__");
-        if (impl!=null) {
-            impl.__get__(this,self_type).__call__(obj);
-            return;
-        }
-        super.__delete__(obj);
-    }
-
-    public PyObject __pow__(PyObject other,PyObject modulo) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__pow__");
-        if (impl!=null) {
-            PyObject res;
-            if (modulo==null) {
-                res=impl.__get__(this,self_type).__call__(other);
-            } else {
-                res=impl.__get__(this,self_type).__call__(other,modulo);
-            }
-            if (res==Py.NotImplemented)
-                return null;
-            return res;
-        }
-        return super.__pow__(other,modulo);
-    }
-
-    public void dispatch__init__(PyObject[]args,String[]keywords) {
-        Deriveds.dispatch__init__(this,args,keywords);
-    }
-
-    public PyObject __index__() {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__index__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__();
-            if (res instanceof PyInteger||res instanceof PyLong) {
-                return res;
-            }
-            throw Py.TypeError(String.format("__index__ returned non-(int,long) (type %s)",res.getType().fastGetName()));
-        }
-        return super.__index__();
-    }
-
-    public Object __tojava__(Class c) {
-        // If we are not being asked by the "default" conversion to java, then
-        // we can provide this as the result, as long as it is a instance of the
-        // specified class. Without this, derived.__tojava__(PyObject.class)
-        // would broke. (And that's not pure speculation: PyReflectedFunction's
-        // ReflectedArgs asks for things like that).
-        if ((c!=Object.class)&&(c!=Serializable.class)&&(c.isInstance(this))) {
-            return this;
-        }
-        // Otherwise, we call the derived __tojava__, if it exists:
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__tojava__");
-        if (impl!=null)
-            return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class);
-        return super.__tojava__(c);
-    }
-
-    public Object __coerce_ex__(PyObject o) {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__coerce__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__(o);
-            if (res==Py.NotImplemented)
-                return Py.None;
-            if (!(res instanceof PyTuple))
-                throw Py.TypeError("__coerce__ didn't return a 2-tuple");
-            return((PyTuple)res).getArray();
-        }
-        return super.__coerce_ex__(o);
-    }
-
-    public String toString() {
-        PyType self_type=getType();
-        PyObject impl=self_type.lookup("__repr__");
-        if (impl!=null) {
-            PyObject res=impl.__get__(this,self_type).__call__();
-            if (!(res instanceof PyString))
-                throw Py.TypeError("__repr__ returned non-string (type "+res.getType().fastGetName()+")");
-            return((PyString)res).toString();
-        }
-        return super.toString();
-    }
-
-}
+/* Generated file, do not modify.  See jython/src/templates/gderived.py. */
+package org.python.core;
+
+import java.io.Serializable;
+
+public class PyByteArrayDerived extends PyByteArray implements Slotted {
+
+    public PyObject getSlot(int index) {
+        return slots[index];
+    }
+
+    public void setSlot(int index,PyObject value) {
+        slots[index]=value;
+    }
+
+    private PyObject[]slots;
+
+    private PyObject dict;
+
+    public PyObject fastGetDict() {
+        return dict;
+    }
+
+    public PyObject getDict() {
+        return dict;
+    }
+
+    public void setDict(PyObject newDict) {
+        if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
+            dict=newDict;
+        } else {
+            throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
+        }
+    }
+
+    public void delDict() {
+        // deleting an object's instance dict makes it grow a new one
+        dict=new PyStringMap();
+    }
+
+    public PyByteArrayDerived(PyType subtype) {
+        super(subtype);
+        slots=new PyObject[subtype.getNumSlots()];
+        dict=subtype.instDict();
+    }
+
+    public PyString __str__() {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__str__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__();
+            if (res instanceof PyString)
+                return(PyString)res;
+            throw Py.TypeError("__str__"+" returned non-"+"string"+" (type "+res.getType().fastGetName()+")");
+        }
+        return super.__str__();
+    }
+
+    public PyString __repr__() {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__repr__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__();
+            if (res instanceof PyString)
+                return(PyString)res;
+            throw Py.TypeError("__repr__"+" returned non-"+"string"+" (type "+res.getType().fastGetName()+")");
+        }
+        return super.__repr__();
+    }
+
+    public PyString __hex__() {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__hex__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__();
+            if (res instanceof PyString)
+                return(PyString)res;
+            throw Py.TypeError("__hex__"+" returned non-"+"string"+" (type "+res.getType().fastGetName()+")");
+        }
+        return super.__hex__();
+    }
+
+    public PyString __oct__() {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__oct__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__();
+            if (res instanceof PyString)
+                return(PyString)res;
+            throw Py.TypeError("__oct__"+" returned non-"+"string"+" (type "+res.getType().fastGetName()+")");
+        }
+        return super.__oct__();
+    }
+
+    public PyFloat __float__() {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__float__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__();
+            if (res instanceof PyFloat)
+                return(PyFloat)res;
+            throw Py.TypeError("__float__"+" returned non-"+"float"+" (type "+res.getType().fastGetName()+")");
+        }
+        return super.__float__();
+    }
+
+    public PyComplex __complex__() {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__complex__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__();
+            if (res instanceof PyComplex)
+                return(PyComplex)res;
+            throw Py.TypeError("__complex__"+" returned non-"+"complex"+" (type "+res.getType().fastGetName()+")");
+        }
+        return super.__complex__();
+    }
+
+    public PyObject __pos__() {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__pos__");
+        if (impl!=null)
+            return impl.__get__(this,self_type).__call__();
+        return super.__pos__();
+    }
+
+    public PyObject __neg__() {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__neg__");
+        if (impl!=null)
+            return impl.__get__(this,self_type).__call__();
+        return super.__neg__();
+    }
+
+    public PyObject __abs__() {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__abs__");
+        if (impl!=null)
+            return impl.__get__(this,self_type).__call__();
+        return super.__abs__();
+    }
+
+    public PyObject __invert__() {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__invert__");
+        if (impl!=null)
+            return impl.__get__(this,self_type).__call__();
+        return super.__invert__();
+    }
+
+    public PyObject __reduce__() {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__reduce__");
+        if (impl!=null)
+            return impl.__get__(this,self_type).__call__();
+        return super.__reduce__();
+    }
+
+    public PyObject __add__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__add__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__add__(other);
+    }
+
+    public PyObject __radd__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__radd__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__radd__(other);
+    }
+
+    public PyObject __sub__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__sub__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__sub__(other);
+    }
+
+    public PyObject __rsub__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__rsub__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__rsub__(other);
+    }
+
+    public PyObject __mul__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__mul__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__mul__(other);
+    }
+
+    public PyObject __rmul__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__rmul__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__rmul__(other);
+    }
+
+    public PyObject __div__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__div__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__div__(other);
+    }
+
+    public PyObject __rdiv__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__rdiv__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__rdiv__(other);
+    }
+
+    public PyObject __floordiv__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__floordiv__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__floordiv__(other);
+    }
+
+    public PyObject __rfloordiv__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__rfloordiv__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__rfloordiv__(other);
+    }
+
+    public PyObject __truediv__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__truediv__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__truediv__(other);
+    }
+
+    public PyObject __rtruediv__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__rtruediv__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__rtruediv__(other);
+    }
+
+    public PyObject __mod__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__mod__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__mod__(other);
+    }
+
+    public PyObject __rmod__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__rmod__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__rmod__(other);
+    }
+
+    public PyObject __divmod__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__divmod__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__divmod__(other);
+    }
+
+    public PyObject __rdivmod__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__rdivmod__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__rdivmod__(other);
+    }
+
+    public PyObject __rpow__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__rpow__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__rpow__(other);
+    }
+
+    public PyObject __lshift__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__lshift__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__lshift__(other);
+    }
+
+    public PyObject __rlshift__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__rlshift__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__rlshift__(other);
+    }
+
+    public PyObject __rshift__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__rshift__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__rshift__(other);
+    }
+
+    public PyObject __rrshift__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__rrshift__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__rrshift__(other);
+    }
+
+    public PyObject __and__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__and__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__and__(other);
+    }
+
+    public PyObject __rand__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__rand__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__rand__(other);
+    }
+
+    public PyObject __or__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__or__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__or__(other);
+    }
+
+    public PyObject __ror__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__ror__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__ror__(other);
+    }
+
+    public PyObject __xor__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__xor__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__xor__(other);
+    }
+
+    public PyObject __rxor__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__rxor__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__rxor__(other);
+    }
+
+    public PyObject __lt__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__lt__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__lt__(other);
+    }
+
+    public PyObject __le__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__le__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__le__(other);
+    }
+
+    public PyObject __gt__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__gt__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__gt__(other);
+    }
+
+    public PyObject __ge__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__ge__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__ge__(other);
+    }
+
+    public PyObject __eq__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__eq__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__eq__(other);
+    }
+
+    public PyObject __ne__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__ne__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__ne__(other);
+    }
+
+    public PyObject __iadd__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__iadd__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__iadd__(other);
+    }
+
+    public PyObject __isub__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__isub__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__isub__(other);
+    }
+
+    public PyObject __imul__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__imul__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__imul__(other);
+    }
+
+    public PyObject __idiv__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__idiv__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__idiv__(other);
+    }
+
+    public PyObject __ifloordiv__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__ifloordiv__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__ifloordiv__(other);
+    }
+
+    public PyObject __itruediv__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__itruediv__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__itruediv__(other);
+    }
+
+    public PyObject __imod__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__imod__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__imod__(other);
+    }
+
+    public PyObject __ipow__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__ipow__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__ipow__(other);
+    }
+
+    public PyObject __ilshift__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__ilshift__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__ilshift__(other);
+    }
+
+    public PyObject __irshift__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__irshift__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__irshift__(other);
+    }
+
+    public PyObject __iand__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__iand__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__iand__(other);
+    }
+
+    public PyObject __ior__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__ior__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__ior__(other);
+    }
+
+    public PyObject __ixor__(PyObject other) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__ixor__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(other);
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__ixor__(other);
+    }
+
+    public PyObject __int__() {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__int__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__();
+            if (res instanceof PyInteger||res instanceof PyLong)
+                return res;
+            throw Py.TypeError("__int__"+" should return an integer");
+        }
+        return super.__int__();
+    }
+
+    public PyObject __long__() {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__long__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__();
+            if (res instanceof PyLong||res instanceof PyInteger)
+                return res;
+            throw Py.TypeError("__long__"+" returned non-"+"long"+" (type "+res.getType().fastGetName()+")");
+        }
+        return super.__long__();
+    }
+
+    public int hashCode() {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__hash__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__();
+            if (res instanceof PyInteger) {
+                return((PyInteger)res).getValue();
+            } else
+                if (res instanceof PyLong) {
+                    return((PyLong)res).getValue().intValue();
+                }
+            throw Py.TypeError("__hash__ should return a int");
+        }
+        if (self_type.lookup("__eq__")!=null||self_type.lookup("__cmp__")!=null) {
+            throw Py.TypeError(String.format("unhashable type: '%.200s'",getType().fastGetName()));
+        }
+        return super.hashCode();
+    }
+
+    public PyUnicode __unicode__() {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__unicode__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__();
+            if (res instanceof PyUnicode)
+                return(PyUnicode)res;
+            if (res instanceof PyString)
+                return new PyUnicode((PyString)res);
+            throw Py.TypeError("__unicode__"+" should return a "+"unicode");
+        }
+        return super.__unicode__();
+    }
+
+    public int __cmp__(PyObject other) {
+        PyType self_type=getType();
+        PyObject[]where_type=new PyObject[1];
+        PyObject impl=self_type.lookup_where("__cmp__",where_type);
+        // Full Compatibility with CPython __cmp__:
+        // If the derived type don't override __cmp__, the
+        // *internal* super().__cmp__ should be called, not the
+        // exposed one. The difference is that the exposed __cmp__
+        // throws a TypeError if the argument is an instance of the same type.
+        if (impl==null||where_type[0]==TYPE||Py.isSubClass(TYPE,where_type[0])) {
+            return super.__cmp__(other);
+        }
+        PyObject res=impl.__get__(this,self_type).__call__(other);
+        if (res==Py.NotImplemented) {
+            return-2;
+        }
+        int c=res.asInt();
+        return c<0?-1:c>0?1:0;
+    }
+
+    public boolean __nonzero__() {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__nonzero__");
+        if (impl==null) {
+            impl=self_type.lookup("__len__");
+            if (impl==null)
+                return super.__nonzero__();
+        }
+        PyObject o=impl.__get__(this,self_type).__call__();
+        Class c=o.getClass();
+        if (c!=PyInteger.class&&c!=PyBoolean.class) {
+            throw Py.TypeError(String.format("__nonzero__ should return bool or int, returned %s",self_type.getName()));
+        }
+        return o.__nonzero__();
+    }
+
+    public boolean __contains__(PyObject o) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__contains__");
+        if (impl==null)
+            return super.__contains__(o);
+        return impl.__get__(this,self_type).__call__(o).__nonzero__();
+    }
+
+    public int __len__() {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__len__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__();
+            if (res instanceof PyInteger)
+                return((PyInteger)res).getValue();
+            throw Py.TypeError("__len__ should return a int");
+        }
+        return super.__len__();
+    }
+
+    public PyObject __iter__() {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__iter__");
+        if (impl!=null)
+            return impl.__get__(this,self_type).__call__();
+        impl=self_type.lookup("__getitem__");
+        if (impl==null)
+            return super.__iter__();
+        return new PySequenceIter(this);
+    }
+
+    public PyObject __iternext__() {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("next");
+        if (impl!=null) {
+            try {
+                return impl.__get__(this,self_type).__call__();
+            } catch (PyException exc) {
+                if (exc.match(Py.StopIteration))
+                    return null;
+                throw exc;
+            }
+        }
+        return super.__iternext__(); // ???
+    }
+
+    public PyObject __finditem__(PyObject key) { // ???
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__getitem__");
+        if (impl!=null)
+            try {
+                return impl.__get__(this,self_type).__call__(key);
+            } catch (PyException exc) {
+                if (exc.match(Py.LookupError))
+                    return null;
+                throw exc;
+            }
+        return super.__finditem__(key);
+    }
+
+    public PyObject __finditem__(int key) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__getitem__");
+        if (impl!=null)
+            try {
+                return impl.__get__(this,self_type).__call__(new PyInteger(key));
+            } catch (PyException exc) {
+                if (exc.match(Py.LookupError))
+                    return null;
+                throw exc;
+            }
+        return super.__finditem__(key);
+    }
+
+    public PyObject __getitem__(PyObject key) {
+        // Same as __finditem__, without swallowing LookupErrors. This allows
+        // __getitem__ implementations written in Python to raise custom
+        // exceptions (such as subclasses of KeyError).
+        //
+        // We are forced to duplicate the code, instead of defining __finditem__
+        // in terms of __getitem__. That's because PyObject defines __getitem__
+        // in terms of __finditem__. Therefore, we would end with an infinite
+        // loop when self_type.lookup("__getitem__") returns null:
+        //
+        //  __getitem__ -> super.__getitem__ -> __finditem__ -> __getitem__
+        //
+        // By duplicating the (short) lookup and call code, we are safe, because
+        // the call chains will be:
+        //
+        // __finditem__ -> super.__finditem__
+        //
+        // __getitem__ -> super.__getitem__ -> __finditem__ -> super.__finditem__
+
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__getitem__");
+        if (impl!=null)
+            return impl.__get__(this,self_type).__call__(key);
+        return super.__getitem__(key);
+    }
+
+    public void __setitem__(PyObject key,PyObject value) { // ???
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__setitem__");
+        if (impl!=null) {
+            impl.__get__(this,self_type).__call__(key,value);
+            return;
+        }
+        super.__setitem__(key,value);
+    }
+
+    public PyObject __getslice__(PyObject start,PyObject stop,PyObject step) { // ???
+        if (step!=null) {
+            return __getitem__(new PySlice(start,stop,step));
+        }
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__getslice__");
+        if (impl!=null) {
+            PyObject[]indices=PySlice.indices2(this,start,stop);
+            return impl.__get__(this,self_type).__call__(indices[0],indices[1]);
+        }
+        return super.__getslice__(start,stop,step);
+    }
+
+    public void __setslice__(PyObject start,PyObject stop,PyObject step,PyObject value) {
+        if (step!=null) {
+            __setitem__(new PySlice(start,stop,step),value);
+            return;
+        }
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__setslice__");
+        if (impl!=null) {
+            PyObject[]indices=PySlice.indices2(this,start,stop);
+            impl.__get__(this,self_type).__call__(indices[0],indices[1],value);
+            return;
+        }
+        super.__setslice__(start,stop,step,value);
+    }
+
+    public void __delslice__(PyObject start,PyObject stop,PyObject step) {
+        if (step!=null) {
+            __delitem__(new PySlice(start,stop,step));
+            return;
+        }
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__delslice__");
+        if (impl!=null) {
+            PyObject[]indices=PySlice.indices2(this,start,stop);
+            impl.__get__(this,self_type).__call__(indices[0],indices[1]);
+            return;
+        }
+        super.__delslice__(start,stop,step);
+    }
+
+    public void __delitem__(PyObject key) { // ???
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__delitem__");
+        if (impl!=null) {
+            impl.__get__(this,self_type).__call__(key);
+            return;
+        }
+        super.__delitem__(key);
+    }
+
+    public PyObject __call__(PyObject args[],String keywords[]) {
+        ThreadState ts=Py.getThreadState();
+        if (ts.recursion_depth++>ts.systemState.getrecursionlimit())
+            throw Py.RuntimeError("maximum __call__ recursion depth exceeded");
+        try {
+            PyType self_type=getType();
+            PyObject impl=self_type.lookup("__call__");
+            if (impl!=null)
+                return impl.__get__(this,self_type).__call__(args,keywords);
+            return super.__call__(args,keywords);
+        } finally {
+            --ts.recursion_depth;
+        }
+    }
+
+    public PyObject __findattr_ex__(String name) {
+        return Deriveds.__findattr_ex__(this,name);
+    }
+
+    public void __setattr__(String name,PyObject value) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__setattr__");
+        if (impl!=null) {
+            impl.__get__(this,self_type).__call__(PyString.fromInterned(name),value);
+            return;
+        }
+        super.__setattr__(name,value);
+    }
+
+    public void __delattr__(String name) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__delattr__");
+        if (impl!=null) {
+            impl.__get__(this,self_type).__call__(PyString.fromInterned(name));
+            return;
+        }
+        super.__delattr__(name);
+    }
+
+    public PyObject __get__(PyObject obj,PyObject type) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__get__");
+        if (impl!=null) {
+            if (obj==null)
+                obj=Py.None;
+            if (type==null)
+                type=Py.None;
+            return impl.__get__(this,self_type).__call__(obj,type);
+        }
+        return super.__get__(obj,type);
+    }
+
+    public void __set__(PyObject obj,PyObject value) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__set__");
+        if (impl!=null) {
+            impl.__get__(this,self_type).__call__(obj,value);
+            return;
+        }
+        super.__set__(obj,value);
+    }
+
+    public void __delete__(PyObject obj) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__delete__");
+        if (impl!=null) {
+            impl.__get__(this,self_type).__call__(obj);
+            return;
+        }
+        super.__delete__(obj);
+    }
+
+    public PyObject __pow__(PyObject other,PyObject modulo) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__pow__");
+        if (impl!=null) {
+            PyObject res;
+            if (modulo==null) {
+                res=impl.__get__(this,self_type).__call__(other);
+            } else {
+                res=impl.__get__(this,self_type).__call__(other,modulo);
+            }
+            if (res==Py.NotImplemented)
+                return null;
+            return res;
+        }
+        return super.__pow__(other,modulo);
+    }
+
+    public void dispatch__init__(PyObject[]args,String[]keywords) {
+        Deriveds.dispatch__init__(this,args,keywords);
+    }
+
+    public PyObject __index__() {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__index__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__();
+            if (res instanceof PyInteger||res instanceof PyLong) {
+                return res;
+            }
+            throw Py.TypeError(String.format("__index__ returned non-(int,long) (type %s)",res.getType().fastGetName()));
+        }
+        return super.__index__();
+    }
+
+    public Object __tojava__(Class c) {
+        // If we are not being asked by the "default" conversion to java, then
+        // we can provide this as the result, as long as it is a instance of the
+        // specified class. Without this, derived.__tojava__(PyObject.class)
+        // would broke. (And that's not pure speculation: PyReflectedFunction's
+        // ReflectedArgs asks for things like that).
+        if ((c!=Object.class)&&(c!=Serializable.class)&&(c.isInstance(this))) {
+            return this;
+        }
+        // Otherwise, we call the derived __tojava__, if it exists:
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__tojava__");
+        if (impl!=null)
+            return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class);
+        return super.__tojava__(c);
+    }
+
+    public Object __coerce_ex__(PyObject o) {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__coerce__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__(o);
+            if (res==Py.NotImplemented)
+                return Py.None;
+            if (!(res instanceof PyTuple))
+                throw Py.TypeError("__coerce__ didn't return a 2-tuple");
+            return((PyTuple)res).getArray();
+        }
+        return super.__coerce_ex__(o);
+    }
+
+    public String toString() {
+        PyType self_type=getType();
+        PyObject impl=self_type.lookup("__repr__");
+        if (impl!=null) {
+            PyObject res=impl.__get__(this,self_type).__call__();
+            if (!(res instanceof PyString))
+                throw Py.TypeError("__repr__ returned non-string (type "+res.getType().fastGetName()+")");
+            return((PyString)res).toString();
+        }
+        return super.toString();
+    }
+
+}
diff --git a/tests/java/org/python/core/BaseBytesTest.java b/tests/java/org/python/core/BaseBytesTest.java
--- a/tests/java/org/python/core/BaseBytesTest.java
+++ b/tests/java/org/python/core/BaseBytesTest.java
@@ -42,8 +42,10 @@
         super(name);
     }
 
-    static PythonInterpreter interp = null;
+    /** Sometimes we need the interpreter to be initialised **/
+    PythonInterpreter interp;
 
+    /** State for random data fills */
     Random random;
 
     public static char toChar(int b) {
@@ -102,17 +104,20 @@
     /**
      * Compare expected and result array sections at specified locations and length.
      * 
-     * @param expected reference values
+     * @param expected reference values (may be null iff len==0)
      * @param first first value to compare in expected values
      * @param result bytearray from method under test
      * @param start first value to compare in result values
      * @param len number of values to compare
      */
     static void checkInts(int[] expected, int first, BaseBytes result, int start, int len) {
-        int end = first + len;
-        if (end > expected.length) end = expected.length;
-        for (int i = first, j = start; i < end; i++, j++)
-            assertEquals("element value", expected[i], result.intAt(j));
+        if (len > 0) {
+            int end = first + len;
+            if (end > expected.length) end = expected.length;
+            for (int i = first, j = start; i < end; i++, j++) {
+                assertEquals("element value", expected[i], result.intAt(j));
+            }
+        }
     }
 
     /**
@@ -125,8 +130,9 @@
         // Size must be the same
         assertEquals("size", expected.length, result.size());
         // And each element
-        for (int i = 0; i < expected.length; i++)
+        for (int i = 0; i < expected.length; i++) {
             assertEquals("element value", expected[i], result.intAt(i));
+        }
     }
 
     /**
@@ -168,7 +174,7 @@
         List<PyObject> list = new ArrayList<PyObject>(source.length);
         int choose = 0;
         for (int b : source) {
-            switch(choose++){
+            switch (choose++) {
                 case 0:
                     PyInteger i = new PyInteger(b);
                     list.add(i);
@@ -210,6 +216,7 @@
         BaseBytes a = getInstance(aRef);
         System.out.println(toString(a));
         assertEquals(aRef.length, a.size());
+
         // init(int) at various sizes
         for (int n : new int[] {0, 1, 2, 7, 8, 9, MEDIUM, LARGE, HUGE}) {
             a = getInstance(n);
@@ -231,8 +238,9 @@
         assertEquals(a.size(), b.size());
         // assertEquals(a.storage, b.storage); // Supposed to share?
         // Check we got the same bytes
-        for (int i = 0; i < a.size(); i++)
+        for (int i = 0; i < a.size(); i++) {
             assertEquals(a.intAt(i), b.intAt(i));
+        }
     }
 
     /**
@@ -424,9 +432,11 @@
         for (int count = 0; count <= maxCount; count++) {
             // Reference answer
             int[] bRef = new int[count * L];
-            for (int i = 0; i < count; i++)
-                for (int j = 0; j < L; j++)
+            for (int i = 0; i < count; i++) {
+                for (int j = 0; j < L; j++) {
                     bRef[i * L + j] = aRef[j];
+                }
+            }
             // Test
             BaseBytes b = a.repeat(count);
             // System.out.println(toString(b));
@@ -704,13 +714,16 @@
             if (step == 1) {
                 // This is a contiguous slice [start:stop] so we can share storage
                 r = new MyBytes();
-                if (stop > start) r.setStorage(storage, stop - start, start + offset);
+                if (stop > start) {
+                    r.setStorage(storage, stop - start, start + offset);
+                }
             } else {
                 // This is an extended slice [start:stop:step] so we have to copy elements from it
                 r = new MyBytes(sliceLength(start, stop, step));
                 int iomax = r.size + r.offset;
-                for (int io = r.offset, jo = start; io < iomax; jo += step, io++)
+                for (int io = r.offset, jo = start; io < iomax; jo += step, io++) {
                     r.storage[io] = storage[jo]; // Assign r[i] = this[j]
+                }
             }
             return r;
         }
@@ -747,13 +760,16 @@
             super(TYPE);
             int n = value.length;
             store = new byte[n];
-            for (int i = 0; i < n; i++)
+            for (int i = 0; i < n; i++) {
                 store[i] = (byte)value[i];
+            }
         }
 
         @Override
         public MemoryView getMemoryView() {
-            if (mv == null) mv = new MemoryViewImpl();
+            if (mv == null) {
+                mv = new MemoryViewImpl();
+            }
             return mv;
         }
 
@@ -823,26 +839,31 @@
         private StringBuilder image = new StringBuilder(100);
 
         private void repeat(char c, int n) {
-            for (int i = 0; i < n; i++)
+            for (int i = 0; i < n; i++) {
                 image.append(i == 0 ? '|' : ' ').append(c);
+            }
         }
 
         // Show in image s[pos:pos+n] (as 2*n characters)
         private void append(byte[] s, int pos, int n) {
-            if (pos < 0 || pos + n > s.length) return;
+            if (pos < 0 || pos + n > s.length)
+                return;
             for (int i = 0; i < n; i++) {
                 int c = 0xff & ((int)s[pos + i]);
-                if (c == 0)
+                if (c == 0) {
                     c = '.';
-                else if (Character.isISOControl(c)) c = '#';
+                } else if (Character.isISOControl(c)) {
+                    c = '#';
+                }
                 image.append(i == 0 ? '|' : ' ').append(toChar(c));
             }
         }
 
         // Show an extent of n bytes (as 2*n charactrs)
         public void padTo(int n) {
-            while (n > image.length())
+            while (n > image.length()) {
                 image.append(' ');
+            }
         }
 
         /**
diff --git a/tests/java/org/python/core/PyByteArrayTest.java b/tests/java/org/python/core/PyByteArrayTest.java
--- a/tests/java/org/python/core/PyByteArrayTest.java
+++ b/tests/java/org/python/core/PyByteArrayTest.java
@@ -21,12 +21,11 @@
         super(name);
     }
 
-    
     /**
      * Generate character codes for in a pattern matching an intended deletion or slice to be
      * replaced. If c="adb", something like b'aaaaaaddddbbbb' where the 'd' characters should be
      * deleted or replaced in the slice operation.
-     * 
+     *
      * @param na number of c.charAt(0) characters
      * @param nd number of c.charAt(1) characters
      * @param nb number of c.charAt(2) characters
@@ -36,12 +35,15 @@
     public static int[] patternInts(int na, int nd, int nb, String c) {
         int[] r = new int[na + nd + nb];
         int p = 0;
-        for (int i = 0; i < na; i++)
+        for (int i = 0; i < na; i++) {
             r[p++] = c.charAt(0);
-        for (int i = 0; i < nd; i++)
+        }
+        for (int i = 0; i < nd; i++) {
             r[p++] = c.charAt(1);
-        for (int i = 0; i < nb; i++)
+        }
+        for (int i = 0; i < nb; i++) {
             r[p++] = c.charAt(2);
+        }
         return r;
     }
 
@@ -49,7 +51,7 @@
      * Generate character codes for 'a', 'D', 'b' in a pattern matching an intended deletion or
      * slice to be replaced. Something like b'aaaaaaddddbbbb' where the 'E' characters should be
      * deleted or replaced in the slice operation.
-     * 
+     *
      * @param na number of a characters
      * @param nd number of D characters
      * @param nb number of b characters
@@ -63,7 +65,7 @@
      * Generate character codes for 'a', 'E', 'b' in a pattern matching an intended result of slice
      * replacement. Something like b'aaaaaaEEEbbbb' where the 'E' characters are the replacement in
      * the slice operation.
-     * 
+     *
      * @param na number of a characters
      * @param ne number of E characters
      * @param nb number of b characters
@@ -74,11 +76,11 @@
     }
 
     /**
-     * Generate a tuple of int arrays at random in the range 0..255 for testing slice operations.
-     * In effect, the method generates 4 arrays of random data A, B, D, E and returns an array of three arrays formed thus:
-     * { A + D + B, A + E + B, E } where + means concatenation. This can be used to test slice
-     * assignment and deletion.
-     * 
+     * Generate a tuple of int arrays at random in the range 0..255 for testing slice operations. In
+     * effect, the method generates 4 arrays of random data A, B, D, E and returns an array of three
+     * arrays formed thus: { A + D + B, A + E + B, E } where + means concatenation. This can be used
+     * to test slice assignment and deletion.
+     *
      * @param random the random generator
      * @param na the number of elements in A
      * @param nd the number of elements in D (the deleted material)
@@ -90,34 +92,33 @@
         int[] adb = new int[na + nd + nb];
         int[] aeb = new int[na + ne + nb];
         int[] e = new int[ne];
-        int[][] ret = { adb, aeb, e };
-        int p=0, q = 0;
+        int[][] ret = {adb, aeb, e};
+        int p = 0, q = 0;
         // The A values go into adb and aeb
         for (int i = 0; i < na; i++) {
             int a = random.nextInt(256);
-            adb[p++] =a;
-            aeb[q++] =a;
+            adb[p++] = a;
+            aeb[q++] = a;
         }
         // The D values go into adb only
         for (int i = 0; i < nd; i++) {
             int d = random.nextInt(256);
-            adb[p++] =d;
+            adb[p++] = d;
         }
         // The E values go into e and aeb
         for (int i = 0; i < ne; i++) {
             int x = random.nextInt(256);
-            e[p++] =x;
-            aeb[q++] =x;
+            e[p++] = x;
+            aeb[q++] = x;
         }
         // The B values go into adb and aeb
         for (int i = 0; i < nb; i++) {
             int b = random.nextInt(256);
-            adb[p++] =b;
-            aeb[q++] =b;
+            adb[p++] = b;
+            aeb[q++] = b;
         }
         return ret;
     }
-    
 
     /**
      * Check result of slice operations, synthesised from the elements passed. This method accepts
@@ -127,7 +128,7 @@
      * B=X[-nb:N], D=X[na:nb] and E=Y[:ne], and posed the problem setslice( A + D + B, E ), where +
      * means concatenation in this expression, to which the answer should be A + E + B. This method
      * checks that the result is exactly that.
-     * 
+     *
      * @param na the number of elements in A
      * @param nd the number of elements in D (the deleted material)
      * @param nb the number of elements in B
@@ -146,13 +147,13 @@
         // Check that B is preserved
         checkInts(x, na + nd, result, na + ne, nb);
     }
-    
+
     /**
      * Check result of extended slice operations, synthesised from the elements passed. This method
      * accepts the 'dimensions' of a slice problem and tests whether a resulting byte array contains
      * the correct result. The result array has been filled from (the whole of) array x[], then
      * slice assignment took place from y[k] to element u[start + k*step].
-     * 
+     *
      * @param start
      * @param step
      * @param n number of steps
@@ -163,57 +164,142 @@
     public static void checkSlice(int start, int step, int n, int[] x, int[] y, BaseBytes u) {
         // Check the size is right
         assertEquals("size", x.length, u.size());
+
         if (step > 0) {
+
             // Check before start of slice
             int px = 0, py = 0;
-            for (; px < start; px++)
+            for (; px < start; px++) {
                 assertEquals("before slice", x[px], u.intAt(px));
+            }
+
             // Check slice-affected region at n assignments and n-1 gaps of length step-1.
-            if (n>0) assertEquals("first affected", y[py++], u.intAt(px++));
+            if (n > 0) {
+                assertEquals("first affected", y[py++], u.intAt(px++));
+            }
+
             for (int i = 1; i < n; i++) {
                 for (int j = 1; j < step; j++, px++) {
                     assertEquals("in gap", x[px], u.intAt(px));
                 }
                 assertEquals("next affected", y[py++], u.intAt(px++));
             }
+
             // Check after slice-affected region
-            for (; px < x.length; px++)
+            for (; px < x.length; px++) {
                 assertEquals("after slice", x[px], u.intAt(px));
-            
+            }
+
         } else {
             // Negative step but easier to think about as a positive number
             step = -step;
 
             // Check after start of slice
             int px = x.length - 1, py = 0;
-            for (; px > start; --px)
+            for (; px > start; --px) {
                 assertEquals("after slice", x[px], u.intAt(px));
+            }
+
             // Check slice-affected region at n assignments and n-1 gaps of length step-1.
-            if (n>0) assertEquals("first affected", y[py++], u.intAt(px--));
+            if (n > 0) {
+                assertEquals("first affected", y[py++], u.intAt(px--));
+            }
+
             for (int i = 1; i < n; i++) {
                 for (int j = 1; j < step; j++, px--) {
                     assertEquals("in gap", x[px], u.intAt(px));
                 }
                 assertEquals("next affected", y[py++], u.intAt(px--));
             }
+
             // Check before slice-affected region
-            for (; px >= 0; px--)
+            for (; px >= 0; px--) {
                 assertEquals("before slice", x[px], u.intAt(px));
-
+            }
         }
     }
 
-    /* (non-Javadoc)
+    /**
+     * Check result of extended slice deletion operations, synthesised from the elements passed.
+     * This method accepts the 'dimensions' of a slice deletion problem and tests whether a
+     * resulting byte array contains the correct result. The result array has been filled from (the
+     * whole of) array x[], then slice deletion took place at original element u[start + k*step].
+     *
+     * @param start
+     * @param step
+     * @param n number of steps (deletions)
+     * @param x source of the original data
+     * @param u the result to be tested against properly selected elements of x
+     */
+    public static void checkDelSlice(int start, int step, int n, int[] x, BaseBytes u) {
+        // Check the size is right
+        assertEquals("size", x.length - n, u.size());
+
+        if (step > 0) {
+
+            // Check before start of slice
+            int px = 0, pu = 0;
+            for (; px < start; px++) {
+                assertEquals("before slice", x[px], u.intAt(pu++));
+            }
+
+            // Check slice-affected region at n deletions and n-1 gaps of length step-1.
+            // px now points to the first element that should be missing from u
+            px++;
+            for (int i = 1; i < n; i++) {
+                for (int j = 1; j < step; j++, px++) {
+                    assertEquals("in gap", x[px], u.intAt(pu++));
+                }
+                // px now points to the i.th element that should be missing from u
+                px++;
+            }
+
+            // Check after slice-affected region
+            for (; px < x.length; px++) {
+                assertEquals("after slice", x[px], u.intAt(pu++));
+            }
+
+        } else {
+
+            // Negative step but easier to think about as a positive number
+            step = -step;
+
+            // Check after start of slice
+            int px = x.length - 1, pu = u.size - 1;
+            for (; px > start; --px) {
+                assertEquals("after slice", x[px], u.intAt(pu--));
+            }
+
+            // Check slice-affected region at n assignments and n-1 gaps of length step-1.
+            // px now points to the first element that should be missing from u
+            px--;
+            for (int i = 1; i < n; i++) {
+                for (int j = 1; j < step; j++, px--) {
+                    assertEquals("in gap", x[px], u.intAt(pu--));
+                }
+                // px now points to the i.th element that should be missing from u
+                px--;
+            }
+
+            // Check before slice-affected region
+            for (; px >= 0; px--) {
+                assertEquals("before slice", x[px], u.intAt(pu--));
+            }
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     *
      * @see org.python.core.BaseBytesTest#setUp()
      */
     protected void setUp() throws Exception {
         super.setUp();
     }
 
-    
     /**
      * Test method for {@link PyObject#__getslice__(PyObject, PyObject)}.
-     * 
+     *
      * @see BaseBytes#getslice(int, int)
      */
     public void test__getslice__2() {
@@ -233,29 +319,33 @@
         for (int start : posStart) {
             PyObject pyStart, pyStop, pyStart_L, pyStop_L;
             pyStart = new PyInteger(start);
-            if (start > 0)
+            if (start > 0) {
                 // The other way of saying [start:stop] is [start-L:stop]
                 pyStart_L = new PyInteger(start - L);
-            else
+            } else {
                 // The other way of saying [0:stop] is [:stop]
                 pyStart_L = Py.None;
+            }
 
             for (int stop = start; stop <= L; stop++) {
 
                 // Make a reference answer by picking elements of aRef in slice pattern
                 bList.clear();
                 for (int i = start; i < stop; i++) {
-                    if (verbose >= 5) System.out.printf("    (%d,%d) i=%d\n", start, stop, i);
+                    if (verbose >= 5) {
+                        System.out.printf("    (%d,%d) i=%d\n", start, stop, i);
+                    }
                     bList.add(new PyInteger(aRef[i]));
                 }
 
                 // PyObject versions of stop
-                if (stop < L)
+                if (stop < L) {
                     // The other way of saying [start:stop:+s] is [start:stop-L:+s]
                     pyStop_L = new PyInteger(stop - L);
-                else
+                } else {
                     // The other way of saying [start:L:+s] is [start::+s]
                     pyStop_L = Py.None;
+                }
                 pyStop = new PyInteger(stop);
 
                 // Generate test result and check it
@@ -273,7 +363,7 @@
     /**
      * Common code to check {@link PyByteArray#__getslice__(PyObject, PyObject)} against a reference
      * answer.
-     * 
+     *
      * @param a object under test
      * @param pyStart
      * @param pyStop
@@ -285,21 +375,25 @@
                                      PyObject pyStop,
                                      List<PyInteger> bList,
                                      int verbose) {
-        if (verbose >= 4) System.out.printf("    __getslice__(%s,%s)\n", pyStart, pyStop);
+        if (verbose >= 4) {
+            System.out.printf("    __getslice__(%s,%s)\n", pyStart, pyStop);
+        }
         PyObject b = a.__getslice__(pyStart, pyStop);
-        if (verbose >= 3) System.out.println(toString((BaseBytes)b));
+        if (verbose >= 3) {
+            System.out.println(toString((BaseBytes)b));
+        }
         checkInts(bList, b);
     }
 
     /**
      * Test method for {@link PyObject#__getslice__(PyObject, PyObject, PyObject)}.
-     * 
+     *
      * @see BaseBytes#getslice(int, int, int)
      */
     public void test__getslice__3() {
         int verbose = 0;
         // __getslice__() deals with start, stop values also relative to the end.
-        String ver = "Quand je br�le et que tu t'enflammes ;";
+        String ver = "Quand je brûle et que tu t'enflammes ;";
         final int L = ver.length();
         int[] aRef = toInts(ver);
         BaseBytes a = getInstance(aRef);
@@ -318,30 +412,33 @@
             for (int start : posStart) {
                 PyObject pyStart, pyStop, pyStart_L, pyStop_L;
                 pyStart = new PyInteger(start);
-                if (start > 0)
+                if (start > 0) {
                     // The other way of saying [start:stop:+s] is [start-L:stop:+s]
                     pyStart_L = new PyInteger(start - L);
-                else
+                } else {
                     // The other way of saying [0:stop:+s] is [:stop:+s]
                     pyStart_L = Py.None;
+                }
 
                 for (int stop = start; stop <= L; stop++) {
 
                     // Make a reference answer by picking elements of aRef in slice pattern
                     bList.clear();
                     for (int i = start; i < stop; i += step) {
-                        if (verbose >= 5) System.out.printf("    (%d,%d,%d) i=%d\n", start, stop,
-                                                            step, i);
+                        if (verbose >= 5) {
+                            System.out.printf("    (%d,%d,%d) i=%d\n", start, stop, step, i);
+                        }
                         bList.add(new PyInteger(aRef[i]));
                     }
 
                     // PyObject versions of stop
-                    if (stop < L)
+                    if (stop < L) {
                         // The other way of saying [start:stop:+s] is [start:stop-L:+s]
                         pyStop_L = new PyInteger(stop - L);
-                    else
+                    } else {
                         // The other way of saying [start:L:+s] is [start::+s]
                         pyStop_L = Py.None;
+                    }
                     pyStop = new PyInteger(stop);
 
                     // Generate test result and check it
@@ -363,37 +460,41 @@
 
         for (int step = -1; step > -4; step--) {
             PyInteger pyStep = new PyInteger(step);
+
             for (int start : negStart) {
                 PyObject pyStart, pyStop, pyStart_L, pyStop_L;
                 pyStart = new PyInteger(start);
-                if (start < L - 1)
+
+                if (start < L - 1) {
                     // The other way of saying [start:stop:-s] is [start-L:stop:-s]
                     pyStart_L = new PyInteger(start - L);
-                else
+                } else {
                     // The other way of saying [L-1:stop:-s] is [:stop:-s]
                     pyStart_L = Py.None;
+                }
 
                 for (int stop = start; stop >= -1; stop--) {
 
                     // Make a reference answer by picking elements of aRef in slice pattern
                     bList.clear();
                     for (int i = start; i > stop; i += step) {
-                        if (verbose >= 5) System.out.printf("    (%d,%d,%d) i=%d\n", start, stop,
-                                                            step, i);
+                        if (verbose >= 5) {
+                            System.out.printf("    (%d,%d,%d) i=%d\n", start, stop, step, i);
+                        }
                         bList.add(new PyInteger(aRef[i]));
                     }
 
                     // PyObject versions of stop
-                    if (stop >= 0)
+                    if (stop >= 0) {
                         // The other way of saying [start:stop:-s] is [start:stop-L:-s]
                         pyStop_L = new PyInteger(stop - L);
-                    else {
+                    } else {
                         // intended final value is 0, but [start:-1:-s] doesn't mean that
-                        stop = -(L+1);      // This does.
+                        stop = -(L + 1);      // This does.
                         pyStop_L = Py.None; // And so does [start::-s]
                     }
                     pyStop = new PyInteger(stop);
-                    
+
                     // Generate test result and check it
                     doTest__getslice__3(a, pyStart, pyStop, pyStep, bList, verbose + 2);
                     // Repeat same result specifying start relative to end
@@ -410,7 +511,7 @@
     /**
      * Common code to check {@link PyByteArray#__getslice__(PyObject, PyObject, PyObject)} against a
      * reference answer.
-     * 
+     *
      * @param a answer from method under test
      * @param pyStart
      * @param pyStop
@@ -424,13 +525,16 @@
                                      PyObject pyStep,
                                      List<PyInteger> bList,
                                      int verbose) {
-        if (verbose >= 4) System.out.printf("    __getslice__(%s,%s,%s)\n", pyStart, pyStop, pyStep);
+        if (verbose >= 4) {
+            System.out.printf("    __getslice__(%s,%s,%s)\n", pyStart, pyStop, pyStep);
+        }
         PyObject b = a.__getslice__(pyStart, pyStop, pyStep);
-        if (verbose >= 3) System.out.println(toString((BaseBytes)b));
+        if (verbose >= 3) {
+            System.out.println(toString((BaseBytes)b));
+        }
         checkInts(bList, b);
     }
-    
-    
+
     /**
      * Test method for {@link PyByteArray#__setitem__(int,PyObject)}, and through it of
      * {@link PyByteArray#pyset(int,PyObject)}.
@@ -464,7 +568,9 @@
                 fail("Exception not thrown for __setitem__(" + 0 + ", " + b + ")");
             } catch (PyException pye) {
                 assertEquals(Py.ValueError, pye.type);
-                if (verbose >= 2) System.out.printf("    Exception: %s\n", pye);
+                if (verbose >= 2) {
+                    System.out.printf("    Exception: %s\n", pye);
+                }
             }
         }
 
@@ -476,7 +582,9 @@
                 fail("Exception not thrown for __setitem__(" + i + ", x)");
             } catch (PyException pye) {
                 assertEquals(Py.IndexError, pye.type);
-                if (verbose >= 2) System.out.printf("    Exception: %s\n", pye);
+                if (verbose >= 2) {
+                    System.out.printf("    Exception: %s\n", pye);
+                }
             }
         }
 
@@ -501,8 +609,8 @@
             Arrays.fill(eInts, 'E');
             PyByteArray e = new PyByteArray(eInts);
 
-            for (int nd : ndList)
-                for (int na : naList)
+            for (int nd : ndList) {
+                for (int na : naList) {
                     for (int nb : nbList) {
                         int[] aRef = adbInts(na, nd, nb);
                         int[] bRef = aebInts(na, ne, nb);
@@ -512,9 +620,10 @@
                         byte[] oldStorage = b.storage;
 
                         if (verbose >= 2) {
-                            System.out.printf("setslice(%d,%d,%d,e[len=%d])\n",
-                                              na, na + nd, 1, ne);
-                            if (verbose >= 3) System.out.println(toString(b));
+                            System.out.printf("setslice(%d,%d,%d,e[len=%d])\n", na, na + nd, 1, ne);
+                            if (verbose >= 3) {
+                                System.out.println(toString(b));
+                            }
                         }
 
                         b.setslice(na, na + nd, 1, e);
@@ -522,11 +631,15 @@
                         if (verbose >= 2) {
                             boolean avAlloc = (b.storage != oldStorage)
                                     && (bRef.length <= oldStorage.length);
-                            if (b.storage.length * 2 < oldStorage.length) avAlloc = false;
+                            if (b.storage.length * 2 < oldStorage.length) {
+                                avAlloc = false;
+                            }
                             System.out.println(toString(b) + (avAlloc ? " avoidable new" : ""));
                         }
                         checkInts(bRef, b);
                     }
+                }
+            }
         }
 
         // Insertions at a range of positions and all sizes with random data
@@ -543,9 +656,9 @@
 
         int[] nbList2 = {0, 1, BMAX};
 
-        for (int na = 0; na <= AMAX; na++)
+        for (int na = 0; na <= AMAX; na++) {
             for (int nb : nbList2) {
-                for (int nd = 0; nd < DMAX; nd++)
+                for (int nd = 0; nd < DMAX; nd++) {
                     for (int ne = 0; ne < EMAX; ne++) {
                         PyByteArray u = x.getslice(0, na + nd + nb, 1);
                         PyByteArray e = y.getslice(0, ne, 1);
@@ -558,10 +671,14 @@
                             }
                         }
                         u.setslice(na, na + nd, 1, e);
-                        if (verbose >= 1) System.out.println("u'= " + toString(u));
+                        if (verbose >= 1) {
+                            System.out.println("u'= " + toString(u));
+                        }
                         checkSlice(na, nd, nb, ne, xInts, yInts, u);
                     }
+                }
             }
+        }
     }
 
     /**
@@ -579,7 +696,7 @@
         interp = new PythonInterpreter();
 
         // Source of assigned values.
-        int[] eRef = randomInts(random, 2*SMALL, 'V', 'Z');
+        int[] eRef = randomInts(random, 2 * SMALL, 'V', 'Z');
         BaseBytes eFull = new BaseBytesTest.MyBytes(eRef);
 
         final int[] posStart = new int[] {0, 4, 10, 18, L - 9};
@@ -588,23 +705,28 @@
         for (int start : posStart) {
             PyObject pyStart, pyStop, pyStart_L, pyStop_L;
             pyStart = new PyInteger(start);
-            if (start > 0)
+            if (start > 0) {
                 // The other way of saying [start:stop] is [start-L:stop]
                 pyStart_L = new PyInteger(start - L);
-            else
+            } else {
                 // The other way of saying [0:stop] is [:stop]
                 pyStart_L = Py.None;
+            }
 
             for (int stop : posStop) {
-                if (stop < start) continue; // Skip backwards cases
+                if (stop < start)
+                 {
+                    continue; // Skip backwards cases
+                }
 
                 // PyObject versions of stop
-                if (stop < L)
+                if (stop < L) {
                     // The other way of saying [start:stop] is [start:stop-L]
                     pyStop_L = new PyInteger(stop - L);
-                else
+                } else {
                     // The other way of saying [start:L] is [start:]
                     pyStop_L = Py.None;
+                }
                 pyStop = new PyInteger(stop);
 
                 for (int n = 0; n <= eRef.length; n++) {
@@ -628,7 +750,7 @@
     /**
      * Common code to check {@link PyByteArray#__setslice__(PyObject, PyObject, PyObject)} against a
      * reference answer.
-     * 
+     *
      * @param uRef to initialise the object to test
      * @param pyStart
      * @param pyStop
@@ -643,7 +765,9 @@
                                      BaseBytes eFull,
                                      int n,
                                      int[] eRef,
-                                     int start, int stop, int verbose) {
+                                     int start,
+                                     int stop,
+                                     int verbose) {
         PyByteArray u = getInstance(uRef);
         BaseBytes e = eFull.getslice(0, n, 1);
         if (verbose >= 4) {
@@ -653,12 +777,14 @@
         }
         // Now do the test
         u.__setslice__(pyStart, pyStop, e);
-        if (verbose >= 3) System.out.println("u'= " + toString(u));
-        int nd = stop-start;
-        int nb = uRef.length-stop;
+        if (verbose >= 3) {
+            System.out.println("u'= " + toString(u));
+        }
+        int nd = stop - start;
+        int nb = uRef.length - stop;
         checkSlice(start, nd, nb, n, uRef, eRef, u);
     }
-    
+
     /**
      * Test method for {@link org.python.core.PyByteArray#setslice(int,int,int,PyObject)}, when the
      * slice to replace is extended (3-argument slice and step!=0). Note that PySequence checks and
@@ -701,7 +827,9 @@
                             }
                         }
                         u.setslice(start, stop, step, e);
-                        if (verbose >= 1) System.out.println("u'= " + toString(u));
+                        if (verbose >= 1) {
+                            System.out.println("u'= " + toString(u));
+                        }
                         checkSlice(start, step, n, uRef, eRef, u);
                     }
                 }
@@ -734,7 +862,9 @@
                             }
                         }
                         u.setslice(start, stop, step, e);
-                        if (verbose >= 1) System.out.println("u'= " + toString(u));
+                        if (verbose >= 1) {
+                            System.out.println("u'= " + toString(u));
+                        }
                         checkSlice(start, step, n, uRef, eRef, u);
                     }
                 }
@@ -742,8 +872,7 @@
         }
 
     }
-    
-    
+
     /**
      * Test method for {@link org.python.core.PyByteArray#setslice(int,int,int,PyObject)}, when the
      * slice to replace is extended (3-argument slice and step!=0). Note that PySequence checks and
@@ -784,15 +913,17 @@
                         PyByteArray u = getInstance(uRef);
                         BaseBytes e = eFull.getslice(0, n, 1);
                         if (verbose >= 2) {
-                            System.out.printf("setslice(%d,%d,%d, e[len=%d])\n",
-                                              start, stop, step, n);
+                            System.out.printf("setslice(%d,%d,%d, e[len=%d])\n", start, stop, step,
+                                              n);
                             if (verbose >= 3) {
                                 System.out.println("u = " + toString(u));
                                 System.out.println("e = " + toString(e));
                             }
                         }
                         u.__setslice__(pyStart, pyStop, pyStep, e);
-                        if (verbose >= 1) System.out.println("u'= " + toString(u));
+                        if (verbose >= 1) {
+                            System.out.println("u'= " + toString(u));
+                        }
                         checkSlice(start, step, n, uRef, eRef, u);
                     }
                 }
@@ -820,21 +951,22 @@
                         PyByteArray u = getInstance(uRef);
                         BaseBytes e = eFull.getslice(0, n, 1);
                         if (verbose >= 2) {
-                            System.out.printf("setslice(%d,%d,%d, e[len=%d])\n",
-                                              start, stop, step, n);
+                            System.out.printf("setslice(%d,%d,%d, e[len=%d])\n", start, stop, step,
+                                              n);
                             if (verbose >= 3) {
                                 System.out.println("u = " + toString(u));
                                 System.out.println("e = " + toString(e));
                             }
                         }
                         u.__setslice__(pyStart, pyStop, pyStep, e);
-                        if (verbose >= 1) System.out.println("u'= " + toString(u));
+                        if (verbose >= 1) {
+                            System.out.println("u'= " + toString(u));
+                        }
                         checkSlice(start, step, n, uRef, eRef, u);
                     }
                 }
             }
         }
-
     }
 
     /**
@@ -842,40 +974,48 @@
      * slice to replace is simple and contiguous (2-argument slice).
      */
     public void testSetsliceTime() {
-        int verbose = 0;
-        timeSetslice(100, SMALL, 2*SMALL, verbose);
-        timeSetslice(100, MEDIUM, MEDIUM, verbose);
-        timeSetslice(10, LARGE, LARGE/5, verbose);
-        timeSetslice(10, HUGE, HUGE/5, verbose);
+        int verbose = 1;
+        timeSetslice(100, 200, SMALL, 2*SMALL, verbose);
+        timeSetslice(100, 200, MEDIUM, MEDIUM, verbose);
+        timeSetslice(1000, 20, LARGE, LARGE/5, verbose);
+//        timeSetslice(1000, 4, HUGE, HUGE/5, verbose);
     }
 
     /**
      * Tabulate the elapsed time for calls to setslice, for a given array size and maximum slice
-     * length to insert arrays of a range of sizes.
-     * 
-     * @param repeats number of repeats over which to average
+     * length to insert arrays of a range of sizes. The aim is to demonstrate benefit from the
+     * centring of the occupied storage in the storage array as a whole and catch any drop-off in
+     * implementation that while functionally correct (gets the right value) is massively
+     * inefficient.
+     *
+     * @param trials number of trials over which to take minimum "uninterrupted" time
+     * @param repeats number of repeat calls in each trial, over which to average
      * @param N of bytearray subjected to the change
      * @param M Size of change (inserted, removed or replaced slice)
-     * @param verbose Control level of textual output 0=none CSV-style, 1=just the timings, etc..
+     * @param verbose Control level of textual output 1=just the timings, 2=enumerate calls, etc..
      */
-    protected void timeSetslice(int repeats, int M, int N, int verbose) {
+    private void timeSetslice(int trials, int repeats, int N, int M, int verbose) {
 
         // Trials we intend to do: insertion at a variety of points.
         int[] startList = new int[11]; // 11 means 0%, 10%, 20%, ... 100% of N
-        for (int i = 0; i < startList.length; i++)
+        for (int i = 0; i < startList.length; i++) {
             startList[i] = N * i / (startList.length - 1);
+        }
 
         // Insertion slice sizes.
         int[] changeList = new int[11]; // 0%, ... 100% of M
-        for (int i = 0; i < changeList.length; i++)
+        for (int i = 0; i < changeList.length; i++) {
             changeList[i] = M * i / (changeList.length - 1);
+        }
 
         // We are going to tabulate this for each startList and changeList entry.
         long[][] elapsed = new long[startList.length][changeList.length];
         // Initialise the timing record
-        for (int row = 0; row < startList.length; row++)
-            for (int col = 0; col < changeList.length; col++)
+        for (int row = 0; row < startList.length; row++) {
+            for (int col = 0; col < changeList.length; col++) {
                 elapsed[row][col] = Long.MAX_VALUE;
+            }
+        }
 
         // Create test material as bytearrays
         int[] xRef = randomInts(random, N, 'u', 'z');
@@ -886,21 +1026,20 @@
         // We will time repeated calls: need a fresh bytearray each time
         PyByteArray[] u = new PyByteArray[repeats];
 
-        // Now take the shortest of 10 trials in each row and column
-
-        // Work through the combinations necessary
-        for (int trial = 0; trial < 10; trial++) {
-        for (int row = 0; row < startList.length; row++) {
-            int na = startList[row];
-            int nd = 0;
-            // nd = changeList[3];     // XXX experiment
-            // if (na+nd>N) nd = N-na; // XXX experiment
-            for (int col = 0; col < changeList.length; col++) {
-                int ne = changeList[col];
-                int start = na;
-                int stop = na + nd;
-                // Data to replace the slice with
-                PyByteArray e = y.getslice(0, ne, 1);
+        // Now take the shortest of some number of trials in each row and column
+        for (int trial = 0; trial < trials; trial++) {
+            // Work through the combinations necessary
+            for (int irow = 0; irow < startList.length; irow++) {
+                int row = (irow + 5 * trial) % startList.length;     // Shuffle order
+                int na = startList[row];
+                int nd = 0;
+                for (int icol = 0; icol < changeList.length; icol++) {
+                    int col = (icol + trial) % changeList.length;     // Shuffle order
+                    int ne = changeList[col];
+                    int start = na;
+                    int stop = na + nd;
+                    // Data to replace the slice with
+                    PyByteArray e = y.getslice(0, ne, 1);
 
                     if (trial == 0) {
                         // First trial: do once untimed in order ensure classes loaded.
@@ -912,34 +1051,39 @@
                     long t = doTimeSetslice(u, start, stop, e, x, -1);
 
                     // Retain the shortest time so far
-                    if (t < elapsed[row][col]) elapsed[row][col] = t;
+                    if (t < elapsed[row][col]) {
+                        elapsed[row][col] = t;
+                    }
                 }
             }
         }
 
         // Tabulate the time for each array size and change size
 
-        System.out.print("     N  ,     na  ");
-        for (int col = 0; col < changeList.length; col++)
-            System.out.printf(", ne=%7d", changeList[col]);
-        System.out.println(", elements inserted: time in microseconds.");
+        if (verbose >= 1) {
+            System.out.print("     N  ,     na  ");
+            for (int col = 0; col < changeList.length; col++) {
+                System.out.printf(", ne=%7d", changeList[col]);
+            }
+            System.out.println(", elements inserted: time in microseconds.");
 
-        for (int row = 0; row < startList.length; row++) {
-            System.out.printf("%8d, %8d", N, startList[row]);
-            for (int col = 0; col < changeList.length; col++) {
-                double usPerCall = (1e-3 * elapsed[row][col]) / repeats;
-                System.out.printf(", %10.3f", usPerCall);
+            for (int row = 0; row < startList.length; row++) {
+                System.out.printf("%8d, %8d", N, startList[row]);
+                for (int col = 0; col < changeList.length; col++) {
+                    double usPerCall = (1e-3 * elapsed[row][col]) / repeats;
+                    System.out.printf(", %10.3f", usPerCall);
+                    // System.out.printf(", %10d", elapsed[row][col]);
+                }
+                System.out.println();
             }
-            System.out.println();
         }
-
     }
 
     /**
      * Time trial of {@link PyByteArray#setslice(int,int,int)}. Every element of the array of test
      * objects will be initialised to the same value then the specified slice replacement will take
      * place, with the block of repetitions timed.
-     * 
+     *
      * @param u array of test objects
      * @param start
      * @param stop
@@ -949,26 +1093,25 @@
      * @return elapsed time in nanoseconds for setslice operation on array of objects
      */
     private long doTimeSetslice(PyByteArray[] u,
-                                      int start,
-                                      int stop,
-                                      BaseBytes e,
-                                      BaseBytes x,
-                                      int verbose) {
+                                int start,
+                                int stop,
+                                BaseBytes e,
+                                BaseBytes x,
+                                int verbose) {
 
-        // The call is either to do a time trial (block of test objects) or one test
+        // The call is either to do a time trial (block of test objects) or one test of correctness
         int repeats = 1;
-        if (verbose < 0)
+        if (verbose < 0) {
             // We're doing a timed trial on an array of identical objects.
             repeats = u.length;
-        else
-            // We're testing the correctness of the code with one object.
-            repeats = 1;
+        }
 
         // Set up clean bytearray objects
-        for (int i = 0; i < repeats; i++)
+        for (int i = 0; i < repeats; i++) {
             u[i] = new PyByteArray(x);
+        }
 
-        // First trial: do once untimed in order ensure classes loaded.
+        // Display effects (if verbose) using first element only.
         PyByteArray v = u[0];
         byte[] oldStorage = v.storage;
 
@@ -981,23 +1124,29 @@
         // Start the clock
         long beginTime = System.nanoTime();
         // Do the work lots of times
-        for (int i = 0; i < repeats; i++)
+        for (int i = 0; i < repeats; i++) {
             u[i].setslice(start, stop, 1, e);
+        }
         // Stop the clock
         long t = System.nanoTime() - beginTime;
 
         // Diagnostic printout
         if (verbose >= 2) {
-            byte[] newStorage = v.storage;
-            boolean avAlloc = (newStorage != oldStorage);
-            if (newStorage.length * 2 < oldStorage.length) avAlloc = false;
+            // Was there a reallocation?
+            boolean avAlloc = (v.storage != oldStorage);
+            // Justified if ...
+            if (v.size * 2 <= oldStorage.length) {
+                avAlloc = false;
+            }
+            if (v.size > oldStorage.length) {
+                avAlloc = false;
+            }
             System.out.println("u'= " + toString(v) + (avAlloc ? " new" : ""));
         }
 
         return t;
     }
-    
-    
+
 //    /**
 //     * Test method for {@link org.python.core.PyByteArray#del(int)}.
 //     */
@@ -1012,9 +1161,453 @@
 //        fail("Not yet implemented");
 //    }
 //
-    
-    
-    
+
+    /**
+     * Test method for {@link org.python.core.PyByteArray#delslice(int,int,int)}, when the
+     * slice to delete is simple (a contiguous 2-argument slice).
+     */
+    public void testDelslice2() {
+        int verbose = 0;
+
+        // Tests where we transform aaaaaDDDDbbbbb into aaaaabbbbb.
+        // Lists of the lengths to try, for each of the aaaa, DDDD, bbbb sections
+        int[] naList = {2, 5, 0};   // Interesting cases: slice is at start, or not at start
+        int[] ndList = {5, 20, 0};  // Slice to delete is small, large or zero
+        int[] nbList = {4, 7, 0};   // Interesting cases: slice is at end, or not at end
+
+            for (int nd : ndList) {
+                for (int na : naList) {
+                    for (int nb : nbList) {
+                        int[] aRef = adbInts(na, nd, nb);
+                        int[] bRef = aebInts(na, 0, nb);
+
+                        PyByteArray b = getInstance(aRef);
+
+                        byte[] oldStorage = b.storage;
+
+                        if (verbose >= 2) {
+                            System.out.printf("delslice(%d,%d,%d)\n",
+                                              na, na + nd, 1);
+                            if (verbose >= 3) {
+                                System.out.println(toString(b));
+                            }
+                        }
+
+                        b.delslice(na, na + nd, 1);
+
+                        if (verbose >= 2) {
+                            // Was there a reallocation?
+                            boolean avAlloc = (b.storage != oldStorage);
+                            // Justified if ...
+                            if (bRef.length * 2 <= oldStorage.length) {
+                                avAlloc = false;
+                            }
+                            System.out.println(toString(b) + (avAlloc ? " avoidable new" : ""));
+                        }
+                        checkInts(bRef, b);
+                    }
+                }
+            }
+
+        // Deletions at a range of positions and all sizes with random data
+
+        final int AMAX = SMALL;
+        final int BMAX = SMALL;
+        final int DMAX = MEDIUM;
+
+        int[] xInts = randomInts(random, AMAX + DMAX + BMAX, 'u', 'z');
+        PyByteArray x = getInstance(xInts);
+        // Use the checker for assignments, pretending to have assigned a zero length array.
+        // int[] yInts = new int[0];
+
+        int[] nbList2 = {0, 1, BMAX};
+
+        for (int na = 0; na <= AMAX; na++) {
+            for (int nb : nbList2) {
+                for (int nd = 0; nd < DMAX; nd++){
+                        PyByteArray u = x.getslice(0, na + nd + nb, 1);
+                        if (verbose >= 2) {
+                            System.out.printf("delslice(start=%d, stop=%d, step=%d)\n",
+                                              na, na + nd, 1);
+                            if (verbose >= 3) {
+                                System.out.println("u = " + toString(u));
+                            }
+                        }
+                        u.delslice(na, na + nd, 1);
+                        if (verbose >= 1) {
+                            System.out.println("u'= " + toString(u));
+                        }
+                        checkSlice(na, nd, nb, 0, xInts, null, u);
+                    }
+            }
+        }
+    }
+
+    /**
+     * Test method for {@link PyByteArray#__delslice__(PyObject, PyObject, PyObject)}, when the
+     * slice to delete is simple (a contiguous 2-argument slice).
+     */
+    public void test__delslice__2() {
+        int verbose = 0;
+        // __delslice__() deals with start, stop values also relative to the end.
+
+        String ver = "Et tes pâleurs, alors que lasse,";
+        final int L = ver.length();
+        int[] uRef = toInts(ver);
+
+        // Need interpreter (for Py.None and exceptions)
+        interp = new PythonInterpreter();
+
+        final int[] posStart = new int[] {0, 3, 7, 16, L - 1};
+        final int[] posStop = new int[] {0, 3, 7, 16, L - 6, L};
+//        final int[] posStart = new int[] {16};
+//        final int[] posStop = new int[] {L};
+
+        for (int start : posStart) {
+            PyObject pyStart, pyStop, pyStart_L, pyStop_L;
+            pyStart = new PyInteger(start);
+            if (start > 0) {
+                // The other way of saying [start:stop] is [start-L:stop]
+                pyStart_L = new PyInteger(start - L);
+            } else {
+                // The other way of saying [0:stop] is [:stop]
+                pyStart_L = Py.None;
+            }
+
+            for (int stop : posStop) {
+                if (stop < start)
+                 {
+                    continue; // Skip backwards cases
+                }
+
+                // PyObject versions of stop
+                if (stop < L) {
+                    // The other way of saying [start:stop] is [start:stop-L]
+                    pyStop_L = new PyInteger(stop - L);
+                } else {
+                    // The other way of saying [start:L] is [start:]
+                    pyStop_L = Py.None;
+                }
+                pyStop = new PyInteger(stop);
+
+                // Generate test result and check it
+                doTest__delslice__2(uRef, pyStart, pyStop, start, stop, verbose + 2);
+                // Repeat same result specifying start relative to end
+                doTest__delslice__2(uRef, pyStart_L, pyStop, start, stop, verbose);
+                // Repeat same result specifying stop relative to end
+                doTest__delslice__2(uRef, pyStart, pyStop_L, start, stop, verbose);
+                // Repeat same result specifying start and stop relative to end
+                doTest__delslice__2(uRef, pyStart_L, pyStop_L, start, stop, verbose);
+            }
+        }
+    }
+
+    /**
+     * Common code to check {@link PyByteArray#__delslice__(PyObject, PyObject, PyObject)} against a
+     * reference answer.
+     *
+     * @param uRef to initialise the object to test
+     * @param pyStart
+     * @param pyStop
+     * @param verbose 0..4 control output
+     */
+    private void doTest__delslice__2(int[] uRef,
+                                     PyObject pyStart,
+                                     PyObject pyStop,
+                                     int start, int stop, int verbose) {
+        PyByteArray u = getInstance(uRef);
+        if (verbose >= 4) {
+            System.out.printf("    __delslice__(%s,%s,1)\n", pyStart, pyStop);
+            System.out.println("u = " + toString(u));
+        }
+        // Now do the test
+        u.__delslice__(pyStart, pyStop);
+        if (verbose >= 3) {
+            System.out.println("u'= " + toString(u));
+        }
+        int nd = stop-start;
+        int nb = uRef.length-stop;
+        checkSlice(start, nd, nb, 0, uRef, null, u);
+    }
+
+
+    /**
+     * Test method for {@link org.python.core.PyByteArray#delslice(int,int,int)}, when the
+     * slice to delete is extended (3-argument slice and step!=0). Note that PySequence checks and
+     * converts arguments first, so we need only test with valid combinations of indices.
+     */
+    public void test__delslice__3() {
+        int verbose = 0;
+
+        // Need interpreter
+        interp = new PythonInterpreter();
+
+        // Source of assigned values.
+//        int[] eRef = randomInts(random, MEDIUM, 'A', 'H');
+//        BaseBytes eFull = new BaseBytesTest.MyBytes(eRef);
+
+        // Forwards cases
+
+        int[] uRef = randomInts(random, MEDIUM, 'm', 's');
+
+        // Positive step sizes we will try
+        int[] posStep = {2, 3, 5, 8, 25, 100};
+
+        for (int start = 0; start < uRef.length; start++) {
+            PyInteger pyStart = new PyInteger(start);
+            // Bytes from start to end of array
+            int len = uRef.length - start;
+            for (int step : posStep) {
+                PyInteger pyStep = new PyInteger(step);
+                // Allowable number of deletions to end of array at given step size
+                int nmax = (len + step - 1) / step;
+                for (int n = 1; n <= nmax; n++) {
+                    // Location of last i
+                    int last = start + step * (n - 1) + 1;
+                    // But any stop value in this range results in n deletions
+                    for (int stop = last + 1; stop < last + step; stop++) {
+                        PyInteger pyStop = new PyInteger(stop);
+                        // Now do the test
+                        PyByteArray u = getInstance(uRef);
+                        if (verbose >= 2) {
+                            System.out.printf("delslice(%d,%d,%d) (%d deletions)\n",
+                                              start, stop, step, n);
+                            if (verbose >= 3) {
+                                System.out.println("u = " + toString(u));
+                            }
+                        }
+                        u.__delslice__(pyStart, pyStop, pyStep);
+                        if (verbose >= 1) {
+                            System.out.println("u'= " + toString(u));
+                        }
+                        checkDelSlice(start, step, n, uRef, u);
+                    }
+                }
+            }
+        }
+
+        // Negative step sizes we will try
+        int[] negStep = {-1, -2, -5, -8, -25, -100};
+
+        for (int start = uRef.length - 1; start >= 0; start--) {
+            PyInteger pyStart = new PyInteger(start);
+            // Bytes from slice start to start of array
+            int len = start + 1;
+            for (int step : negStep) {
+                PyInteger pyStep = new PyInteger(step);
+                // Allowable number of assignments to end of array at given step size
+                int nmax = (len + (-step) - 1) / (-step);
+                for (int n = 1; n <= nmax; n++) {
+                    // Location of last i
+                    int last = start + step * (n - 1) - 1;
+                    // But any stop value in this range results in n deletions
+                    for (int stop = last; stop > last - (-step) && stop >= 0; stop--) {
+                        PyInteger pyStop = new PyInteger(stop);
+                        // Now do the test
+                        PyByteArray u = getInstance(uRef);
+                        if (verbose >= 2) {
+                            System.out.printf("delslice(%d,%d,%d) (%d deletions)\n",
+                                              start, stop, step, n);
+                            if (verbose >= 3) {
+                                System.out.println("u = " + toString(u));
+                            }
+                        }
+                        u.__delslice__(pyStart, pyStop, pyStep);
+                        if (verbose >= 1) {
+                            System.out.println("u'= " + toString(u));
+                        }
+                        checkDelSlice(start, step, n, uRef, u);
+                    }
+                }
+            }
+        }
+
+    }
+
+    /**
+     * Performance for {@link org.python.core.PyByteArray#delslice(int,int,int,PyObject)}, when the
+     * slice to replace is extended (3-argument slice).
+     */
+    public void testDelsliceTime3() {
+        int verbose = 1;
+        timeDelslice3(100, 200, SMALL, verbose);
+        timeDelslice3(100, 200, MEDIUM, verbose);
+        timeDelslice3(10, 4, LARGE, verbose);
+        // timeDelslice3(10, 1, HUGE, verbose);
+    }
+
+    /**
+     * Tabulate the elapsed time for calls to __delslice__, for a given array size and maximum
+     * step-size between deleted items length to delete. The aim is to demonstrate benefit from the
+     * centring of the occupied storage in the storage array as a whole and catch any drop-off in
+     * implementation that while functionally correct (gets the right value) is massively
+     * inefficient.
+     *
+     * @param trials number of trials over which to take minimum "uninterrupted" time
+     * @param repeats number of repeat calls in each trial, over which to average
+     * @param N of bytearray subjected to the change
+     * @param verbose Control level of textual output 1=just the timings, 2=eumerate calls, etc..
+     */
+    private void timeDelslice3(int trials, int repeats, int N, int verbose) {
+
+        // Trials we intend to do: deletion from a variety of points.
+        int[] startList = new int[10]; // 10 means 0%, 10%, 20%, ... 90% of N
+        for (int i = 0; i < startList.length; i++) {
+            startList[i] = N * i / startList.length;
+        }
+
+        // Deletion step sizes. Positive and negative of these will be used
+        int[] posStep = {1, 2, 3, 5, 10};
+        int[] stepList = new int[2 * posStep.length];
+        for (int i = 0; i < posStep.length; i++) {
+            stepList[posStep.length - i - 1] = posStep[i];
+            stepList[posStep.length + i] = -posStep[i];
+        }
+
+        // We are going to tabulate this for each startList and changeList entry.
+        long[][] elapsed = new long[startList.length][stepList.length];
+        // Initialise the timing record
+        for (int row = 0; row < startList.length; row++) {
+            for (int col = 0; col < stepList.length; col++) {
+                elapsed[row][col] = Long.MAX_VALUE;
+            }
+        }
+
+        // Create test material as bytearrays
+        int[] xRef = randomInts(random, N, 'u', 'z');
+        PyByteArray x = getInstance(xRef);
+
+        // We will time repeated calls: need a fresh bytearray each time
+        PyByteArray[] u = new PyByteArray[repeats];
+
+        // Now take the shortest of some number of trials in each row and column
+        for (int trial = 0; trial < trials; trial++) {
+
+            // Work through the combinations necessary
+            for (int irow = 0; irow < startList.length; irow++) {
+                int row = (irow + 5 * trial) % startList.length;     // Shuffle order
+                int start = startList[row];
+                for (int icol = 0; icol < stepList.length; icol++) {
+                    int col = (icol + trial) % stepList.length;    // Shuffle order
+                    int step = stepList[col];
+                    int n;
+
+                    if (step > 0) {
+                        // Deletions available from start location to end of array
+                        n = (xRef.length - start + step-1) / step;
+                    } else {
+                        // Deletions available from start location to beginning of array
+                        n = (start + (-step) ) / (-step);
+                    }
+
+                    // Make objects of the arguments
+                    PyInteger pyStart = new PyInteger(start);
+                    PyObject pyStop = Py.None;
+                    PyInteger pyStep = new PyInteger(step);
+
+                    if (trial == 0) {
+                        // First trial: do once untimed in order ensure classes loaded.
+                        doTimeDelslice3(u, pyStart, pyStop, pyStep, x, verbose);
+                        checkDelSlice(start, step, n, xRef, u[0]);
+                    }
+
+                    // Now do the trial properly
+                    long t = doTimeDelslice3(u, pyStart, pyStop, pyStep, x, -1);
+
+                    // Retain the shortest time so far
+                    if (t < elapsed[row][col]) {
+                        elapsed[row][col] = t;
+                    }
+                }
+            }
+        }
+
+        // Tabulate the time for each array size and change size
+
+        System.out.print("     N  ,    start");
+        for (int col = 0; col < stepList.length; col++) {
+            System.out.printf(", step=%5d", stepList[col]);
+        }
+        System.out.println(", deletion time in microseconds.");
+
+        for (int row = 0; row < startList.length; row++) {
+            System.out.printf("%8d, %8d", N, startList[row]);
+            for (int col = 0; col < stepList.length; col++) {
+                double usPerCall = (1e-3 * elapsed[row][col]) / repeats;
+                System.out.printf(", %10.3f", usPerCall);
+                // System.out.printf(", %10d", elapsed[row][col]);
+            }
+            System.out.println();
+        }
+    }
+
+    /**
+     * Time trial of {@link PyByteArray#__delslice__(PyObject,PyObject,PyObject)}. Every element of
+     * the array of test objects will be initialised to the same value then the specified slice
+     * replacement will take place, with the block of repetitions timed.
+     *
+     * @param u array of test objects
+     * @param pyStart
+     * @param pyStop
+     * @param pyStep
+     * @param x value from which to initialise each test object
+     * @param verbose amount of output
+     * @return elapsed time in nanoseconds for delslice operation on array of objects
+     */
+    private long doTimeDelslice3(PyByteArray[] u,
+                                 PyObject pyStart,
+                                 PyObject pyStop,
+                                 PyObject pyStep,
+                                 BaseBytes x,
+                                 int verbose) {
+
+        // The call is either to do a time trial (block of test objects) or one test of correctness
+        int repeats = 1;
+        if (verbose < 0) {
+            // We're doing a timed trial on an array of identical objects.
+            repeats = u.length;
+        }
+
+        // Set up clean bytearray objects
+        for (int i = 0; i < repeats; i++) {
+            u[i] = new PyByteArray(x);
+        }
+
+        // Display effects (if verbose) using first element only.
+        PyByteArray v = u[0];
+        byte[] oldStorage = v.storage;
+
+        if (verbose >= 3) {
+            System.out.printf("__delslice__(%s,%s,%s)\n", pyStart, pyStop, pyStep);
+            System.out.println("u = " + toString(v));
+        }
+
+        // Start the clock
+        long beginTime = System.nanoTime();
+        // Do the work lots of times
+        for (int i = 0; i < repeats; i++) {
+            u[i].__delslice__(pyStart, pyStop, pyStep);
+        }
+        // Stop the clock
+        long t = System.nanoTime() - beginTime;
+
+        // Diagnostic printout
+        if (verbose >= 2) {
+            // Was there a reallocation?
+            boolean avAlloc = (v.storage != oldStorage);
+            // Justified if ...
+            if (v.size * 2 <= oldStorage.length) {
+                avAlloc = false;
+            }
+            if (v.size > oldStorage.length) {
+                avAlloc = false;
+            }
+            System.out.println("u'= " + toString(v) + (avAlloc ? " new" : ""));
+        }
+
+        return t;
+    }
+
     /*
      * Note that JUnit test classes extending this one inherit all the test* methods, and they will
      * be run by JUnit. Each test uses getInstance() methods where it might have used a constructor
@@ -1056,6 +1649,6 @@
     public PyByteArray getInstance(PyObject arg) throws PyException {
         return new PyByteArray(arg);
     }
-    
-    
+
+
 }

-- 
Repository URL: http://hg.python.org/jython


More information about the Jython-checkins mailing list