[Jython-checkins] jython: _io.open() clarify and document
jeff.allen
jython-checkins at python.org
Mon Jan 28 00:25:13 CET 2013
http://hg.python.org/jython/rev/a9545fe29638
changeset: 6959:a9545fe29638
parent: 6951:7854826b4699
user: Jeff Allen <ja...py at farowl.co.uk>
date: Sun Jan 20 00:04:12 2013 +0000
summary:
_io.open() clarify and document
Align logic of _io.open() to language specification and tighten error detection
in supporting PyFileIO constructor. No change to test_io scores. (0/6/65)
files:
src/org/python/modules/_io/PyFileIO.java | 16 +-
src/org/python/modules/_io/_io.java | 121 ++++++----
2 files changed, 81 insertions(+), 56 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
@@ -168,15 +168,18 @@
throw Py.OSError(Errno.EBADF);
}
}
+ }
+ }
- } else {
- // The file was a type we don't know how to use
- throw Py.TypeError(String.format("invalid file: %s", file.__repr__().asString()));
- }
+ // If we couldn't figure it out, ioDelegate will still be null
+ if (ioDelegate == null) {
+ // The file was a type we don't know how to use
+ throw Py.TypeError(String.format("invalid file: %s", file.__repr__().asString()));
}
// The name is either the textual name or a file descriptor (see Python docs)
fastGetDict().__setitem__("name", file);
+
}
private static final String[] openArgs = {"file", "mode", "closefd"};
@@ -432,6 +435,11 @@
return PyJavaType.wrapJavaObject(ioDelegate.fileno());
}
+ @Override
+ public boolean isatty() {
+ return FileIO_isatty();
+ }
+
@ExposedMethod(doc = isatty_doc)
final boolean FileIO_isatty() {
if (__closed) {
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
@@ -119,76 +119,93 @@
mode.checkValid();
- int line_buffering;
-
/*
* Create the Raw file stream. Let the constructor deal with the variants and argument
* checking.
*/
PyFileIO raw = new PyFileIO(file, mode, closefd);
- // XXX Can this work: boolean isatty = raw.isatty() ? Or maybe:
- // PyObject res = PyObject_CallMethod(raw, "isatty", NULL);
- boolean isatty = false;
+ /*
+ * From the Python documentation for io.open() buffering = 0 to switch buffering off (only
+ * allowed in binary mode), 1 to select line buffering (only usable in text mode), and an
+ * integer > 1 to indicate the size of a fixed-size buffer.
+ *
+ * When no buffering argument is given, the default buffering policy works as follows:
+ * Binary files are buffered in fixed-size chunks; "Interactive" text files (files for which
+ * isatty() returns True) use line buffering. Other text files use the policy described
+ * above for binary files.
+ *
+ * In Java, it seems a stream never is *known* to be interactive, but we ask anyway, and
+ * maybe one day we shall know.
+ */
+ boolean line_buffering = false;
- /*
- * Work out a felicitous buffer size
- */
- if (buffering == 1 || (buffering < 0 && isatty)) {
- buffering = -1;
- line_buffering = 1;
- } else {
- line_buffering = 0;
- }
-
- if (buffering < 0) {
- // Try to establish the default buffer size for this file using the OS.
- buffering = _DEFAULT_BUFFER_SIZE;
- // PyObject res = PyObject_CallMethod(raw, "fileno", NULL);
- // if (fstat(fileno, &st) >= 0 && st.st_blksize > 1)
- // buffering = st.st_blksize;
- }
-
- if (buffering < 0) {
- throw Py.ValueError("invalid buffering size");
- }
-
- // If not buffering, return the raw file object
if (buffering == 0) {
if (!mode.binary) {
throw Py.ValueError("can't have unbuffered text I/O");
}
return raw;
+
+ } else if (buffering == 1) {
+ // The stream is to be read line-by-line.
+ line_buffering = true;
+ // Force default size for actual buffer
+ buffering = -1;
+
+ } else if (buffering < 0 && raw.isatty()) {
+ // No buffering argument given but stream is inteeractive.
+ line_buffering = true;
}
- // We are buffering, so wrap raw into a buffered file
- PyObject bufferType = null;
- PyObject io = imp.load("io");
-
- if (mode.updating) {
- bufferType = io.__getattr__("BufferedRandom");
- } else if (mode.writing || mode.appending) {
- bufferType = io.__getattr__("BufferedWriter");
- } else { // = reading
- bufferType = io.__getattr__("BufferedReader");
+ if (buffering < 0) {
+ /*
+ * We are still being asked for the default buffer size. CPython establishes the default
+ * buffer size using fstat(fd), but Java appears to give no clue. A useful study of
+ * buffer sizes in NIO is http://www.evanjones.ca/software/java-bytebuffers.html . This
+ * leads us to the fixed choice of _DEFAULT_BUFFER_SIZE (=8KB).
+ */
+ buffering = _DEFAULT_BUFFER_SIZE;
}
- PyInteger pyBuffering = new PyInteger(buffering);
- PyObject buffer = bufferType.__call__(raw, pyBuffering);
+ /*
+ * We now know just what particular class of file we are opening, and therefore what stack
+ * (buffering and text encoding) we should build.
+ */
+ if (buffering == 0) {
+ // Not buffering, return the raw file object
+ return raw;
- // If binary, return the buffered file
- if (mode.binary) {
- return buffer;
+ } else {
+ // We are buffering, so wrap raw into a buffered file
+ PyObject bufferType = null;
+ PyObject io = imp.load("io");
+
+ if (mode.updating) {
+ bufferType = io.__getattr__("BufferedRandom");
+ } else if (mode.writing || mode.appending) {
+ bufferType = io.__getattr__("BufferedWriter");
+ } else { // = reading
+ bufferType = io.__getattr__("BufferedReader");
+ }
+
+ PyInteger pyBuffering = new PyInteger(buffering);
+ PyObject buffer = bufferType.__call__(raw, pyBuffering);
+
+ if (mode.binary) {
+ // If binary, return the just the buffered file
+ return buffer;
+
+ } else {
+ // We are opening in text mode, so wrap buffered file in a TextIOWrapper.
+ PyObject textType = io.__getattr__("TextIOWrapper");
+ PyObject[] textArgs =
+ {buffer, ap.getPyObject(3, Py.None), ap.getPyObject(4, Py.None),
+ ap.getPyObject(5, Py.None), Py.newBoolean(line_buffering)};
+ PyObject wrapper = textType.__call__(textArgs);
+ wrapper.__setattr__("mode", new PyString(m));
+ return wrapper;
+ }
}
-
- /* We are opening in text mode, so wrap buffer into a TextIOWrapper */
- PyObject textType = io.__getattr__("TextIOWrapper");
- PyObject[] textArgs =
- {buffer, ap.getPyObject(3, Py.None), ap.getPyObject(4, Py.None),
- ap.getPyObject(5, Py.None), Py.newInteger(line_buffering)};
- PyObject wrapper = textType.__call__(textArgs);
- wrapper.__setattr__("mode", new PyString(m));
- return wrapper;
}
private static final String[] openKwds = {"file", "mode", "buffering", "encoding", "errors",
--
Repository URL: http://hg.python.org/jython
More information about the Jython-checkins
mailing list