pygobject r950 - in trunk: . gio tests



Author: paulp
Date: Wed Aug 27 21:22:08 2008
New Revision: 950
URL: http://svn.gnome.org/viewvc/pygobject?rev=950&view=rev

Log:
2008-08-28  Paul Pogonyshev  <pogonyshev gmx net>

	* gio/gio.defs (gio.InputStream.read_part): Rename from read(),
	document.
	(gio.InputStream.read): Rename from read_all(), document.
	(gio.OutputStream.write_part): Rename from write(), document.
	(gio.OutputStream.write): Rename from write_all(), document.

	* gio/ginputstream.override (_wrap_g_input_stream_read): Fix
	several bugs.
	(_wrap_g_input_stream_read_all): New function.

	* gio/goutputstream.override (_wrap_g_output_stream_write_all):
	New function.

	* tests/test_gio.py (TestInputStream.testRead): Add more tests.
	(TestInputStream.test_read_part): New test.
	(TestInputStream._read_in_loop): New helper method.
	(TestOutputStream.test_write_part): New test.


Modified:
   trunk/ChangeLog
   trunk/gio/ginputstream.override
   trunk/gio/gio.defs
   trunk/gio/gio.override
   trunk/gio/goutputstream.override
   trunk/tests/test_gio.py

Modified: trunk/gio/ginputstream.override
==============================================================================
--- trunk/gio/ginputstream.override	(original)
+++ trunk/gio/ginputstream.override	Wed Aug 27 21:22:08 2008
@@ -91,7 +91,7 @@
                                      &pycancellable))
         return NULL;
 
-    buffersize = BUFSIZE;
+    buffersize = (count < 0 ? BUFSIZE : count);
 
     if (!pygio_check_cancellable(pycancellable, &cancellable))
         return NULL;
@@ -111,31 +111,99 @@
                                             &error);
             pyg_end_allow_threads;
 
-            if (pyg_error_check(&error))
-                {
-                    Py_DECREF(v);
-                    return NULL;
-                }
-            else if (chunksize == 0)
-                {
-                    PyErr_SetFromErrno(PyExc_IOError);
-                    Py_DECREF(v);
-                    return NULL;
-                }
+            if (pyg_error_check(&error)) {
+		Py_DECREF(v);
+		return NULL;
+	    }
+	    if (chunksize == 0) {
+		/* End of file. */
+                break;
+	    }
+
+            bytesread += chunksize;
+            if (bytesread < buffersize) {
+		/* g_input_stream_read() decided to not read full buffer.  We
+		 * then return early too, even if 'count' is less than 0.
+		 */
+                break;
+	    }
+
+            if (count < 0) {
+		buffersize += BUFSIZE;
+		if (_PyString_Resize(&v, buffersize) < 0)
+		    return NULL;
+	    }
+            else {
+                /* Got what was requested. */
+                break;
+	    }
+        }
+
+    if (bytesread != buffersize)
+        _PyString_Resize(&v, bytesread);
+
+    return v;
+}
+%%
+override g_input_stream_read_all kwargs
+static PyObject *
+_wrap_g_input_stream_read_all(PyGObject *self, PyObject *args, PyObject *kwargs)
+{
+    static char *kwlist[] = { "count", "cancellable", NULL };
+    PyGObject *pycancellable = NULL;
+    PyObject *v;
+    GCancellable *cancellable;
+    long count = -1;
+    GError *error = NULL;
+    size_t bytesread, buffersize, chunksize;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+                                     "|lO:InputStream.read",
+                                     kwlist, &count,
+                                     &pycancellable))
+        return NULL;
+
+    buffersize = (count < 0 ? BUFSIZE : count);
+
+    if (!pygio_check_cancellable(pycancellable, &cancellable))
+        return NULL;
+
+    v = PyString_FromStringAndSize((char *)NULL, buffersize);
+    if (v == NULL)
+        return NULL;
+
+    bytesread = 0;
+    for (;;)
+        {
+            pyg_begin_allow_threads;
+            errno = 0;
+            g_input_stream_read_all(G_INPUT_STREAM(self->obj),
+				    PyString_AS_STRING((PyStringObject *)v) + bytesread,
+				    buffersize - bytesread,
+				    &chunksize,
+				    cancellable, &error);
+            pyg_end_allow_threads;
+
+            if (pyg_error_check(&error)) {
+		Py_DECREF(v);
+		return NULL;
+	    }
 
             bytesread += chunksize;
-            if (bytesread < buffersize)
+            if (bytesread < buffersize || chunksize == 0) {
+		/* End of file. */
                 break;
+	    }
 
-            if (count < 0)
-                {
-                    buffersize += BUFSIZE;
-                    if (_PyString_Resize(&v, buffersize) < 0)
-                        return NULL;
-                }
-            else
+            if (count < 0) {
+		buffersize += BUFSIZE;
+		if (_PyString_Resize(&v, buffersize) < 0)
+		    return NULL;
+	    }
+            else {
                 /* Got what was requested. */
                 break;
+	    }
         }
 
     if (bytesread != buffersize)
@@ -384,5 +452,4 @@
     Py_INCREF(Py_None);
     return Py_None;
 }
-/* GInputStream.read_all: No ArgType for void* */
 /* GInputStream.skip_async: No ArgType for GAsyncReadyCallback */

Modified: trunk/gio/gio.defs
==============================================================================
--- trunk/gio/gio.defs	(original)
+++ trunk/gio/gio.defs	Wed Aug 27 21:22:08 2008
@@ -3177,8 +3177,26 @@
   (return-type "GType")
 )
 
-(define-method read
+;; Note: the following two methods are renamed for consistency with
+;; Python file objects' read().  I.e. g_input_stream_read_all() is
+;; more like Python file.read(), so it is renamed read().  Since now
+;; there is a name clash, g_input_stream_read() is renamed
+;; read_part().
+(define-method read_part
   (of-object "GInputStream")
+  (docstring
+   "STREAM.read_part([count, [cancellable]]) -> string\n"
+   "\n"
+   "Read 'count' bytes from the stream. If 'count' is not specified or is\n"
+   "omitted, read until the end of the stream. This method is allowed to\n"
+   "stop at any time after reading at least 1 byte from the stream. E.g.\n"
+   "when reading over a (relatively slow) HTTP connection, it will often\n"
+   "stop after receiving one packet. Therefore, to reliably read requested\n"
+   "number of bytes, you need to use a loop. See also gio.InputStream.read\n"
+   "for easier to use (though less efficient) method.\n"
+   "\n"
+   "Note: this method roughly corresponds to C GIO g_input_stream_read."
+  )
   (c-name "g_input_stream_read")
   (return-type "gssize")
   (parameters
@@ -3189,8 +3207,21 @@
   )
 )
 
-(define-method read_all
+;; See comments before the previous method definition.
+(define-method read
   (of-object "GInputStream")
+  (docstring
+   "STREAM.read([count, [cancellable]]) -> string\n"
+   "\n"
+   "Read 'count' bytes from the stream. If 'count' is not specified or is\n"
+   "omitted, read until the end of the stream. This method will stop only\n"
+   "after reading requested number of bytes, reaching end of stream or\n"
+   "triggering an I/O error. See also gio.InputStream.read_part for more\n"
+   "efficient, but more cumbersome to use method.\n"
+   "\n"
+   "Note: this method roughly corresponds to C GIO g_input_stream_read_all.\n"
+   "It was renamed for consistency with Python standard file.read."
+  )
   (c-name "g_input_stream_read_all")
   (return-type "gboolean")
   (parameters
@@ -3976,8 +4007,24 @@
   (return-type "GType")
 )
 
-(define-method write
+;; Note: the following two methods are renamed for consistency with
+;; Python file objects' write().  I.e. g_output_stream_write_all() is
+;; more like Python file.write(), so it is renamed write().  Since now
+;; there is a name clash, g_output_stream_write() is renamed
+;; write_part().
+(define-method write_part
   (of-object "GOutputStream")
+  (docstring
+   "STREAM.write_part(buffer, [cancellable]) -> int\n"
+   "\n"
+   "Write the bytes in 'buffer' to the stream. Return the number of bytes\n"
+   "successfully written. This method is allowed to stop at any time after\n"
+   "writing at least 1 byte. Therefore, to reliably write the whole buffer,\n"
+   "you need to use a loop. See also gio.OutputStream.write for easier to\n"
+   "use (though less efficient) method.\n"
+   "\n"
+   "Note: this method roughly corresponds to C GIO g_output_stream_write."
+  )
   (c-name "g_output_stream_write")
   (return-type "gssize")
   (parameters
@@ -3988,8 +4035,18 @@
   )
 )
 
-(define-method write_all
+;; See comments before the previous method definition.
+(define-method write
   (of-object "GOutputStream")
+   "STREAM.write(buffer, [cancellable]) -> int\n"
+   "\n"
+   "Write the bytes in 'buffer' to the stream. Return the number of bytes\n"
+   "successfully written. This method will stop only after writing the whole\n"
+   "buffer or triggering an I/O error. See also gio.OutputStream.write_part\n"
+   "for more efficient, but more cumbersome to use method.\n"
+   "\n"
+   "Note: this method roughly corresponds to C GIO g_output_stream_write_all.\n"
+   "It was renamed for consistency with Python standard file.write."
   (c-name "g_output_stream_write_all")
   (return-type "gboolean")
   (parameters

Modified: trunk/gio/gio.override
==============================================================================
--- trunk/gio/gio.override	(original)
+++ trunk/gio/gio.override	Wed Aug 27 21:22:08 2008
@@ -105,7 +105,6 @@
   g_file_new_from_path
   g_file_new_from_uri
   g_file_hash
-  g_input_stream_read_all
   g_io_error_quark
   g_simple_async_result_new_error
   g_simple_async_report_error_in_idle

Modified: trunk/gio/goutputstream.override
==============================================================================
--- trunk/gio/goutputstream.override	(original)
+++ trunk/gio/goutputstream.override	Wed Aug 27 21:22:08 2008
@@ -54,6 +54,40 @@
   return PyInt_FromLong(written);
 }
 %%
+override g_output_stream_write_all kwargs
+static PyObject *
+_wrap_g_output_stream_write_all(PyGObject *self,
+				PyObject *args,
+				PyObject *kwargs)
+{
+  static char *kwlist[] = { "buffer", "cancellable", NULL };
+  PyGObject *pycancellable = NULL;
+  gchar *buffer;
+  long count = 0; 
+  GCancellable *cancellable;
+  GError *error = NULL;
+  gssize written;
+
+  if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+				   "s#|O!:OutputStream.write",
+				   kwlist, &buffer, &count,
+				   &PyGCancellable_Type, &pycancellable))
+    return NULL;
+
+  if (!pygio_check_cancellable(pycancellable, &cancellable))
+      return NULL;
+
+  pyg_begin_allow_threads;
+  g_output_stream_write_all(G_OUTPUT_STREAM(self->obj),
+			    buffer, count, &written, cancellable, &error);
+  pyg_end_allow_threads;
+
+  if (pyg_error_check(&error))
+    return NULL;
+      
+  return PyInt_FromLong(written);
+}
+%%
 override g_output_stream_write_async kwargs
 static PyObject *
 _wrap_g_output_stream_write_async(PyGObject *self,

Modified: trunk/tests/test_gio.py
==============================================================================
--- trunk/tests/test_gio.py	(original)
+++ trunk/tests/test_gio.py	Wed Aug 27 21:22:08 2008
@@ -485,6 +485,46 @@
     def testRead(self):
         self.assertEquals(self.stream.read(), "testing")
 
+        self.stream = gio.MemoryInputStream()
+        self.assertEquals(self.stream.read(), '')
+
+        self.stream = gio.MemoryInputStream()
+        some_data = open("test_gio.py", "rb").read()
+        self.stream.add_data(some_data)
+        self.assertEquals(self.stream.read(), some_data)
+
+        stream = gio.MemoryInputStream()
+        stream.add_data(some_data)
+        self.assertEquals(self._read_in_loop(stream,
+                                             lambda: stream.read(50),
+                                             50),
+                          some_data)
+
+    def test_read_part(self):
+        self.assertEquals(self._read_in_loop(self.stream,
+                                             lambda: self.stream.read_part()),
+                          'testing')
+
+        stream = gio.MemoryInputStream()
+        some_data = open('test_gio.py', 'rb').read()
+        stream.add_data(some_data)
+        self.assertEquals(self._read_in_loop(stream,
+                                             lambda: stream.read_part(50),
+                                             50),
+                          some_data)
+
+    def _read_in_loop(self, stream, reader, size_limit=0):
+        read_data = ''
+        while True:
+            read_part = reader()
+            if read_part:
+                read_data += read_part
+                if size_limit > 0:
+                    self.assert_(len(read_part) <= size_limit,
+                                 '%d <= %d' % (len(read_part), size_limit))
+            else:
+                return read_data
+
     def testReadAsync(self):
         def callback(stream, result):
             self.assertEquals(result.get_op_res_gssize(), 7)
@@ -595,6 +635,23 @@
         self.failUnless(os.path.exists("outputstream.txt"))
         self.assertEquals(open("outputstream.txt").read(), "testing")
 
+    def test_write_part(self):
+        stream = gio.MemoryOutputStream()
+        some_data = open('test_gio.py', 'rb').read()
+        buffer = some_data
+
+        # In fact this makes only one looping (memory stream is fast,
+        # write_part behaves just like write), but let's still be
+        # complete.
+        while buffer:
+            written = stream.write_part(buffer)
+            if written == len(buffer):
+                break
+            else:
+                buffer = buffer[written:]
+
+        self.assertEquals(stream.get_contents(), some_data)
+
     def testWriteAsync(self):
         def callback(stream, result):
             self.assertEquals(result.get_op_res_gssize(), 7)



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]