diff options
author | Paul Pogonyshev <pogonyshev@gmx.net> | 2008-08-27 21:22:08 +0000 |
---|---|---|
committer | Paul Pogonyshev <paulp@src.gnome.org> | 2008-08-27 21:22:08 +0000 |
commit | 30eb71d505abcbaf42d098dac62d0c747338d910 (patch) | |
tree | d0866a230255838c94dee43f1db5b3be199e3541 | |
parent | 70ede7ebbceb28e420c31d5ceb68e8abdd6216a5 (diff) | |
download | pygobject-30eb71d505abcbaf42d098dac62d0c747338d910.tar.gz pygobject-30eb71d505abcbaf42d098dac62d0c747338d910.tar.xz pygobject-30eb71d505abcbaf42d098dac62d0c747338d910.zip |
Rename from read(), document. (gio.InputStream.read): Rename from
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.
svn path=/trunk/; revision=950
-rw-r--r-- | ChangeLog | 20 | ||||
-rw-r--r-- | gio/ginputstream.override | 109 | ||||
-rw-r--r-- | gio/gio.defs | 65 | ||||
-rw-r--r-- | gio/gio.override | 1 | ||||
-rw-r--r-- | gio/goutputstream.override | 34 | ||||
-rw-r--r-- | tests/test_gio.py | 57 |
6 files changed, 260 insertions, 26 deletions
@@ -1,3 +1,23 @@ +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. + 2008-08-16 Paul Pogonyshev <pogonyshev@gmx.net> * gio/gfile.override (_wrap_g_file_enumerate_children_async): Fix diff --git a/gio/ginputstream.override b/gio/ginputstream.override index 44378cd..b320034 100644 --- a/gio/ginputstream.override +++ b/gio/ginputstream.override @@ -91,7 +91,7 @@ _wrap_g_input_stream_read(PyGObject *self, PyObject *args, PyObject *kwargs) &pycancellable)) return NULL; - buffersize = BUFSIZE; + buffersize = (count < 0 ? BUFSIZE : count); if (!pygio_check_cancellable(pycancellable, &cancellable)) return NULL; @@ -111,31 +111,99 @@ _wrap_g_input_stream_read(PyGObject *self, PyObject *args, PyObject *kwargs) &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) + 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; - if (count < 0) - { - buffersize += BUFSIZE; - if (_PyString_Resize(&v, buffersize) < 0) - return NULL; - } - else + 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 || chunksize == 0) { + /* End of file. */ + break; + } + + 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 @@ _wrap_g_memory_input_stream_add_data(PyGObject *self, Py_INCREF(Py_None); return Py_None; } -/* GInputStream.read_all: No ArgType for void* */ /* GInputStream.skip_async: No ArgType for GAsyncReadyCallback */ diff --git a/gio/gio.defs b/gio/gio.defs index 9ca1397..ce4ee5a 100644 --- a/gio/gio.defs +++ b/gio/gio.defs @@ -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 diff --git a/gio/gio.override b/gio/gio.override index 86009cb..431d220 100644 --- a/gio/gio.override +++ b/gio/gio.override @@ -105,7 +105,6 @@ ignore-glob 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 diff --git a/gio/goutputstream.override b/gio/goutputstream.override index 03a5da7..e525739 100644 --- a/gio/goutputstream.override +++ b/gio/goutputstream.override @@ -54,6 +54,40 @@ _wrap_g_output_stream_write(PyGObject *self, 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, diff --git a/tests/test_gio.py b/tests/test_gio.py index 03d09be..c4e9125 100644 --- a/tests/test_gio.py +++ b/tests/test_gio.py @@ -485,6 +485,46 @@ class TestInputStream(unittest.TestCase): 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 @@ class TestOutputStream(unittest.TestCase): 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) |