[Jython-checkins] jython: Implement _io.PyFileIO.readinto() and inherit read methods in place of local
jeff.allen
jython-checkins at python.org
Sun Dec 9 21:29:47 CET 2012
http://hg.python.org/jython/rev/580ce865cfb1
changeset: 6897:580ce865cfb1
user: Jeff Allen <ja...py at farowl.co.uk>
date: Sun Dec 09 18:38:21 2012 +0000
summary:
Implement _io.PyFileIO.readinto() and inherit read methods in place of local implementation.
This is part of the progressive change to the hierarchical implementation with delegation. Score in test_io.py is a little lower at fail/error/skip = 19/18/99.
files:
src/org/python/modules/_io/PyFileIO.java | 190 ++++++----
src/org/python/modules/_io/PyIOBase.java | 27 +-
src/org/python/modules/_io/_io.java | 9 -
3 files changed, 122 insertions(+), 104 deletions(-)
diff --git a/src/org/python/modules/_io/PyFileIO.java b/src/org/python/modules/_io/PyFileIO.java
--- a/src/org/python/modules/_io/PyFileIO.java
+++ b/src/org/python/modules/_io/PyFileIO.java
@@ -8,8 +8,10 @@
import org.python.core.BuiltinDocs;
import org.python.core.Py;
import org.python.core.PyArray;
+import org.python.core.PyBuffer;
import org.python.core.PyInteger;
import org.python.core.PyJavaType;
+import org.python.core.PyLong;
import org.python.core.PyObject;
import org.python.core.PyString;
import org.python.core.PyType;
@@ -102,6 +104,95 @@
+ (updating ? "+" : "");
}
+ /*
+ * ===========================================================================================
+ * Exposed methods in the order they appear in CPython's fileio.c method table
+ * ===========================================================================================
+ */
+
+ // _RawIOBase.read is correct for us
+ // _RawIOBase.readall is correct for us
+
+ @Override
+ public PyObject readinto(PyObject buf) {
+ return FileIO_readinto(buf);
+ }
+
+ @ExposedMethod(doc = readinto_doc)
+ final PyLong FileIO_readinto(PyObject buf) {
+ // Check we can do this
+ _checkClosed();
+ _checkReadable();
+ // Perform the operation through a buffer view on the object
+ PyBuffer pybuf = writablePyBuffer(buf);
+ try {
+ PyBuffer.Pointer bp = pybuf.getBuf();
+ ByteBuffer byteBuffer = ByteBuffer.wrap(bp.storage, bp.offset, pybuf.getLen());
+ int count;
+ synchronized (ioDelegate) {
+ count = ioDelegate.readinto(byteBuffer);
+ }
+ return new PyLong(count);
+ } finally {
+ // Must unlock the PyBuffer view from client's object
+ pybuf.release();
+ }
+ }
+
+ @Override
+ public PyObject write(PyObject buf) {
+ return FileIO_write(buf);
+ }
+
+ @ExposedMethod(doc = write_doc)
+ final PyLong FileIO_write(PyObject obj) {
+ _checkWritable();
+ // Get or synthesise a buffer API on the object to be written
+ PyBuffer pybuf = readablePyBuffer(obj);
+ try {
+ // Access the data as a java.nio.ByteBuffer [pos:limit] within possibly larger array
+ PyBuffer.Pointer bp = pybuf.getBuf();
+ ByteBuffer byteBuffer = ByteBuffer.wrap(bp.storage, bp.offset, pybuf.getLen());
+ int count;
+ synchronized (ioDelegate) {
+ count = ioDelegate.write(byteBuffer);
+ }
+ return new PyLong(count);
+ } finally {
+ // Even if that went badly, we should release the lock on the client buffer
+ pybuf.release();
+ }
+ }
+
+ @Override
+ public long truncate() {
+ return _truncate();
+ }
+
+ @Override
+ public long truncate(long size) {
+ return _truncate(size);
+ }
+
+ @ExposedMethod(defaults = "null", doc = truncate_doc)
+ final long FileIO_truncate(PyObject size) {
+ return (size != null) ? _truncate(size.asLong()) : _truncate();
+ }
+
+ /** Common to FileIO_truncate(null) and truncate(). */
+ private final long _truncate() {
+ synchronized (ioDelegate) {
+ return ioDelegate.truncate(ioDelegate.tell());
+ }
+ }
+
+ /** Common to FileIO_truncate(size) and truncate(size). */
+ private final long _truncate(long size) {
+ synchronized (ioDelegate) {
+ return ioDelegate.truncate(size);
+ }
+ }
+
/**
* Close the underlying ioDelegate only if <code>closefd</code> was specified as (or defaulted
* to) <code>True</code>.
@@ -133,7 +224,7 @@
@ExposedMethod(defaults = {"0"}, doc = BuiltinDocs.file_seek_doc)
final synchronized PyObject FileIO_seek(long pos, int how) {
- checkClosed();
+ _checkClosed();
return Py.java2py(ioDelegate.seek(pos, how));
}
@@ -152,7 +243,7 @@
@ExposedMethod(doc = BuiltinDocs.file_tell_doc)
final synchronized long FileIO_tell() {
- checkClosed();
+ _checkClosed();
return ioDelegate.tell();
}
@@ -162,35 +253,6 @@
}
@Override
- public long truncate() {
- return _truncate();
- }
-
- @Override
- public long truncate(long size) {
- return _truncate(size);
- }
-
- @ExposedMethod(defaults = "null", doc = truncate_doc)
- final long FileIO_truncate(PyObject size) {
- return (size != null) ? _truncate(size.asLong()) : _truncate();
- }
-
- /** Common to FileIO_truncate(null) and truncate(). */
- private final long _truncate() {
- synchronized (ioDelegate) {
- return ioDelegate.truncate(ioDelegate.tell());
- }
- }
-
- /** Common to FileIO_truncate(size) and truncate(size). */
- private final long _truncate(long size) {
- synchronized (ioDelegate) {
- return ioDelegate.truncate(size);
- }
- }
-
- @Override
public boolean isatty() {
return FileIO_isatty();
}
@@ -220,55 +282,20 @@
return PyJavaType.wrapJavaObject(ioDelegate.fileno());
}
- @ExposedMethod(defaults = {"-1"}, doc = BuiltinDocs.file_read_doc)
- final synchronized PyString FileIO_read(int size) {
- checkClosed();
- ByteBuffer buf = ioDelegate.read(size);
- return new PyString(StringUtil.fromBytes(buf));
+ // fileio.c has no flush(), but why not, when there is fdflush()?
+ // And it is a no-op for Jython io.FileIO, but why when there is FileChannel.force()?
+ @Override
+ public void flush() {
+ FileIO_flush();
}
- @Override
- public PyString read(int size) {
- return FileIO_read(size);
- }
-
- @ExposedMethod(doc = BuiltinDocs.file_read_doc)
- final synchronized PyString FileIO_readall() {
- return FileIO_read(-1);
- }
-
- /**
- * 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 PyArray) {
- return ((PyArray)obj).tostring();
- } else if (obj instanceof BaseBytes) {
- return StringUtil.fromBytes((BaseBytes)obj);
+ @ExposedMethod(doc = "Flush write buffers.")
+ final void FileIO_flush() {
+ if (writable()) {
+ // Check for *downstream* close. (Locally, closed means "closed to client actions".)
+ ioDelegate.checkClosed();
+ ioDelegate.flush();
}
- if (message == null) {
- message =
- String.format("argument 1 must be string or buffer, not %.200s", obj.getType()
- .fastGetName());
- }
- throw Py.TypeError(message);
- }
-
- @ExposedMethod(doc = BuiltinDocs.file_write_doc)
- final PyObject FileIO_write(PyObject obj) {
- String writable = asWritable(obj, null);
- byte[] bytes = StringUtil.toBytes(writable);
- int written = write(ByteBuffer.wrap(bytes));
- return new PyInteger(written);
- }
-
- final synchronized int write(ByteBuffer buf) {
- checkClosed();
- return ioDelegate.write(buf);
}
@ExposedMethod(names = {"__str__", "__repr__"}, doc = BuiltinDocs.file___str___doc)
@@ -285,13 +312,4 @@
return FileIO_toString();
}
- private void checkClosed() {
- ioDelegate.checkClosed();
- }
-
- @ExposedGet(name = "closed", doc = BuiltinDocs.file_closed_doc)
- public boolean getClosed() {
- return ioDelegate.closed();
- }
-
}
diff --git a/src/org/python/modules/_io/PyIOBase.java b/src/org/python/modules/_io/PyIOBase.java
--- a/src/org/python/modules/_io/PyIOBase.java
+++ b/src/org/python/modules/_io/PyIOBase.java
@@ -201,12 +201,21 @@
@ExposedMethod(doc = close_doc)
final void _IOBase_close() {
if (!__closed) {
- // Cancel the wake-up call
- closer.dismiss();
- // Close should invoke (possibly overridden) flush here.
- invoke("flush");
- // Prevent further access from upstream
- __closed = true;
+ /*
+ * The downstream file (file descriptor) will sometimes have been closed by another
+ * client. This should raise an error for us, (since data potentially in our buffers
+ * will be discarded) but we still must end up closed. the local close comes after the
+ * flush, in case operations within flush() test for "the wrong kind of closed".
+ */
+ try {
+ // Cancel the wake-up call
+ closer.dismiss();
+ // Close should invoke (possibly overridden) flush here.
+ invoke("flush");
+ } finally {
+ // Become closed to further client operations (other than certain enquiries)
+ __closed = true;
+ }
}
}
@@ -441,7 +450,7 @@
@ExposedMethod(defaults = "null", doc = readline_doc)
final PyObject _IOBase_readline(PyObject limit) {
- if (limit == null || limit==Py.None) {
+ if (limit == null || limit == Py.None) {
return _readline(-1);
} else if (limit.isIndex()) {
return _readline(limit.asInt());
@@ -587,7 +596,7 @@
public PyObject __iter__() {
_checkClosed();
// Not like this, in spite of what base comment says, because file *is* an iterator
- // return new PySequenceIter(this);
+ // return new PySequenceIter(this);
return this;
}
@@ -614,7 +623,7 @@
int h = 0;
- if (hint==null || hint == Py.None) {
+ if (hint == null || hint == Py.None) {
return new PyList(this);
} else if (!hint.isIndex()) {
diff --git a/src/org/python/modules/_io/_io.java b/src/org/python/modules/_io/_io.java
--- a/src/org/python/modules/_io/_io.java
+++ b/src/org/python/modules/_io/_io.java
@@ -221,15 +221,6 @@
+ "Argument names are not part of the specification, and only the arguments\n"
+ "of open() are intended to be used as keyword arguments.\n";
-// + "\n"
-// + "data:\n"
-// + "\n"
-// + "DEFAULT_BUFFER_SIZE\n"
-// + "\n"
-// + " An int containing the default buffer size used by the module's buffered\n"
-// + " I/O classes. open() uses the file's blksize (as obtained by os.stat) if\n"
-// + " possible.\n";
-
public static final String __doc__open =
"Open file and return a stream. Raise IOError upon failure.\n" + "\n"
+ "file is either a text or byte string giving the name (and the path\n"
--
Repository URL: http://hg.python.org/jython
More information about the Jython-checkins
mailing list