Commits

Jeff Allen  committed e5c5580

PyIOBase made iterable
Implemented _io._IOBase.next. Also added skip to test_misbehaved_io_read()
as this tests a particular CPython implementation detail.
test.test_io scores fail/error/skip = 0/16/65

  • Participants
  • Parent commits a46ab72

Comments (0)

Files changed (2)

File Lib/test/test_io.py

         self.assertRaises(ValueError, bufio.__init__, rawio, buffer_size=-1)
         self.assertRaises(ValueError, bufio.read)
 
+    @support.cpython_only
     def test_misbehaved_io_read(self):
         rawio = self.MisbehavedRawIO((b"abc", b"d", b"efg"))
         bufio = self.tp(rawio)
         # _pyio.BufferedReader seems to implement reading different, so that
         # checking this is not so easy.
+        # Jython adds: not raised in _jyio.py stand-in. Maybe in eventual Java version.
+        # CPython raises "raw readinto() returned invalid length" here:
+        # http://hg.python.org/cpython/file/8527427914a2/Modules/_io/bufferedio.c#l1298
         self.assertRaises(IOError, bufio.read, 10)
 
     @unittest.skipIf(support.is_jython, "GC nondeterministic in Jython")

File src/org/python/modules/_io/PyIOBase.java

     }
 
     /**
-     * Provide a dictionary in the object, so that methods and attributes may be overridden at instance
-     * level.
+     * Provide a dictionary in the object, so that methods and attributes may be overridden at
+     * instance level.
      */
     @ExposedGet
     protected PyStringMap __dict__ = new PyStringMap();
      */
     @ExposedGet(name = "closed", doc = closed_doc)
     protected boolean __closed;
-    @ExposedSet(name="closed")
+
+    @ExposedSet(name = "closed")
     public final void closed_readonly(boolean value) {
         readonlyAttributeError("closed");
     }
             while (remainingLimit > 0) {
 
                 /*
-                 * peek() returns a str of bytes from the buffer (if any), doing at most one read to
-                 * refill, all without advancing the pointer, or it returns None (in vacuous
-                 * non-blocking read).
+                 * read() returns a str of one byte, doing at most one read to refill, or it returns
+                 * None (in vacuous non-blocking read).
                  */
                 PyObject curr = readMethod.__call__(Py.One);
 
 
     }
 
+    /**
+     * Return an iterator on which <code>next</code> may be repeatedly called to produce (usually)
+     * lines from this stream or file.
+     */
     @Override
     public PyObject __iter__() {
         _checkClosed();
-        // Not like this, in spite of what base comment says, because file *is* an iterator
-        // return new PySequenceIter(this);
+        // The object *is* an iterator so return itself
         return this;
     }
 
     }
 
     /**
+     * May be called repeatedly to produce (usually) lines from this stream or file.
+     *
+     * @return next line from the stream or file
+     * @throws PyException(StopIteration) when iteration has reached a natural conclusion
+     * @throws PyException(ValueError) if the file or stream is closed
+     * @throws PyException(IOError) reflecting an I/O error in during the read
+     */
+    public PyObject next() throws PyException {
+        return _IOBase_next();
+    }
+
+    @ExposedMethod(doc = "x.__next__() <==> next(x)")
+    final PyObject _IOBase_next() throws PyException {
+        // Implement directly. Calling __iternext__() fails when PyIOBaseDerived is considered.
+        PyObject line = invoke("readline");
+        if (!line.__nonzero__()) {
+            throw Py.StopIteration("");
+        }
+        return line;
+    }
+
+    /**
      * Read a stream as a sequence of lines.
      *
      * @param hint stop reading lines after this many bytes (if not EOF first)
     }
 
     /**
-     * Convenience method providing the exception when an argument is not the expected type.
-     * The format is "<b>type</b> argument expected, got <code>type(arg)</code>."
+     * Convenience method providing the exception when an argument is not the expected type. The
+     * format is "<b>type</b> argument expected, got <code>type(arg)</code>."
      *
      * @param type of thing expected (or could any text)
      * @param arg argument provided from which actual type will be reported
      * @return TypeError to throw
      */
-    protected static PyException tailoredTypeError(String type, PyObject arg){
-        return Py.TypeError(String.format("%s argument expected, got %.100s.",
-                type, arg.getType().fastGetName()));
+    protected static PyException tailoredTypeError(String type, PyObject arg) {
+        return Py.TypeError(String.format("%s argument expected, got %.100s.", type, arg.getType()
+                .fastGetName()));
     }
 
     /*