[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