[Jython-checkins] jython: Make bytearray acceptable to f.readinto(b) and f.write(b)

jeff.allen jython-checkins at python.org
Wed Aug 1 10:12:30 CEST 2012


http://hg.python.org/jython/rev/5018fda4fc52
changeset:   6818:5018fda4fc52
user:        Jeff Allen <ja...py at farowl.co.uk>
date:        Sun Jul 29 21:56:01 2012 +0100
summary:
  Make bytearray acceptable to f.readinto(b) and f.write(b)
This fixes a test failure in test.test_bytes, but I'm not at all sure it finishes the job as far as bytearray and the io module go. There is much about the design that remains a puzzle to me.

files:
  src/org/python/core/PyFile.java        |  19 ++++
  src/org/python/core/io/TextIOBase.java |  56 ++++++++++----
  2 files changed, 59 insertions(+), 16 deletions(-)


diff --git a/src/org/python/core/PyFile.java b/src/org/python/core/PyFile.java
--- a/src/org/python/core/PyFile.java
+++ b/src/org/python/core/PyFile.java
@@ -22,6 +22,7 @@
 import org.python.core.io.TextIOBase;
 import org.python.core.io.TextIOWrapper;
 import org.python.core.io.UniversalIOWrapper;
+import org.python.core.util.StringUtil;
 import org.python.expose.ExposedDelete;
 import org.python.expose.ExposedGet;
 import org.python.expose.ExposedMethod;
@@ -379,10 +380,28 @@
      * Return a String for writing to the underlying file from obj.
      */
     private String asWritable(PyObject obj, String message) {
+
         if (obj instanceof PyUnicode) {
             return ((PyUnicode)obj).encode();
+
         } else if (obj instanceof PyString) {
             return ((PyString) obj).getString();
+
+        } else if (obj instanceof BufferProtocol) {
+            // Try to get a simple byte-oriented buffer
+            PyBuffer buf = null;
+            try {
+                buf = ((BufferProtocol)obj).getBuffer(PyBUF.SIMPLE);
+                return StringUtil.fromBytes(buf);
+            } catch (Exception e) {
+                // Wrong kind of buffer: generic error message will do
+            } finally {
+                // If we got a buffer, we should release it
+                if (buf != null) {
+                    buf.release();
+                }
+            }
+
         } else if (binary && obj instanceof PyArray) {
             return ((PyArray)obj).tostring();
         }
diff --git a/src/org/python/core/io/TextIOBase.java b/src/org/python/core/io/TextIOBase.java
--- a/src/org/python/core/io/TextIOBase.java
+++ b/src/org/python/core/io/TextIOBase.java
@@ -5,10 +5,15 @@
 import java.io.OutputStream;
 import java.nio.ByteBuffer;
 
+import org.python.core.BufferPointer;
+import org.python.core.BufferProtocol;
 import org.python.core.Py;
 import org.python.core.PyArray;
+import org.python.core.PyBUF;
+import org.python.core.PyBuffer;
 import org.python.core.PyObject;
 import org.python.core.PyString;
+import org.python.core.util.StringUtil;
 
 /**
  * Base class for text I/O.
@@ -91,29 +96,48 @@
     }
 
     /**
-     * Read into the given PyObject that implements the read-write
-     * buffer interface (currently just a PyArray).
-     *
-     * @param buf a PyObject implementing the read-write buffer interface
+     * Read into the given PyObject that implements the Jython buffer API (with write access) or is
+     * a PyArray.
+     * 
+     * @param buf a PyObject compatible with the buffer API
      * @return the amount of data read as an int
      */
     public int readinto(PyObject buf) {
         // This is an inefficient version of readinto: but readinto is
         // not recommended for use in Python 2.x anyway
-        if (!(buf instanceof PyArray)) {
-            // emulate PyArg_ParseTuple
-            if (buf instanceof PyString) {
-                throw Py.TypeError("Cannot use string as modifiable buffer");
+        if (buf instanceof BufferProtocol) {
+            PyBuffer view = ((BufferProtocol)buf).getBuffer(PyBUF.SIMPLE);
+            if (view.isReadonly()) {
+                // More helpful than falling through to CPython message
+                throw Py.TypeError("cannot read into read-only "
+                        + buf.getType().fastGetName());
+            } else {
+                try {
+                    // Inefficiently, we have to go via a String
+                    String read = read(view.getLen());
+                    int n = read.length();
+                    for (int i = 0; i < n; i++) {
+                        view.storeAt((byte)read.charAt(i), i);
+                    }
+                    return read.length();
+                } finally {
+                    // We should release the buffer explicitly
+                    view.release();
+                }
             }
-            throw Py.TypeError("argument 1 must be read-write buffer, not "
-                               + buf.getType().fastGetName());
+
+        } else if (buf instanceof PyArray) {
+            PyArray array = (PyArray)buf;
+            String read = read(array.__len__());
+            for (int i = 0; i < read.length(); i++) {
+                array.set(i, new PyString(read.charAt(i)));
+            }
+            return read.length();
         }
-        PyArray array = (PyArray)buf;
-        String read = read(array.__len__());
-        for (int i = 0; i < read.length(); i++) {
-            array.set(i, new PyString(read.charAt(i)));
-        }
-        return read.length();
+
+        // No valid alternative worked
+        throw Py.TypeError("argument 1 must be read-write buffer, not "
+                + buf.getType().fastGetName());
     }
 
     /**

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


More information about the Jython-checkins mailing list