Index: tests/test_gio.py
===================================================================
--- tests/test_gio.py	(revision 945)
+++ tests/test_gio.py	(working copy)
@@ -545,6 +545,27 @@
         loop.run()
 
 
+class TestDataInputStream(unittest.TestCase):
+    def setUp(self):
+        self.base_stream = gio.MemoryInputStream()
+        self.data_stream = gio.DataInputStream(self.base_stream)
+
+    def test_read_line(self):
+        # Currently fails because GIO itself is buggy.  See bug 547481.
+        return
+        self.base_stream.add_data('foo\nbar\n\nbaz')
+        self.assertEquals('foo\n', self.data_stream.read_line())
+        self.assertEquals('bar\n', self.data_stream.read_line())
+        self.assertEquals('\n', self.data_stream.read_line())
+        self.assertEquals('baz', self.data_stream.read_line())
+
+    def test_read_until(self):
+        self.base_stream.add_data('sentence.end of line\nthe rest')
+        self.assertEquals('sentence', self.data_stream.read_until('.!?'))
+        self.assertEquals('end of line', self.data_stream.read_until('\n\r'))
+        self.assertEquals('the rest', self.data_stream.read_until('#$%^&'))
+
+
 class TestMemoryInputStream(unittest.TestCase):
     def setUp(self):
         self.stream = gio.MemoryInputStream()
Index: gio/ginputstream.override
===================================================================
--- gio/ginputstream.override	(revision 945)
+++ gio/ginputstream.override	(working copy)
@@ -286,6 +286,71 @@
     return Py_None;
 }
 %%
+override g_data_input_stream_read_line kwargs
+static PyObject *
+_wrap_g_data_input_stream_read_line(PyGObject *self,
+				    PyObject *args,
+				    PyObject *kwargs)
+{
+    static char *kwlist[] = { "cancellable", NULL };
+    PyGObject *pycancellable = NULL;
+    GCancellable *cancellable;
+    char *line;
+    gsize length;
+    PyObject *py_line;
+    GError *error = NULL;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+				     "|O:gio.DataInputStream.read_line",
+                                     kwlist, &pycancellable))
+        return NULL;
+
+    if (!pygio_check_cancellable(pycancellable, &cancellable))
+	return NULL;
+
+    line = g_data_input_stream_read_line(G_DATA_INPUT_STREAM(self->obj),
+					 &length, cancellable, &error);
+    if (pyg_error_check(&error))
+        return NULL;
+
+    py_line = PyString_FromStringAndSize(line, length);
+    g_free(line);
+    return py_line;
+}
+%%
+override g_data_input_stream_read_until kwargs
+static PyObject *
+_wrap_g_data_input_stream_read_until(PyGObject *self,
+				     PyObject *args,
+				     PyObject *kwargs)
+{
+    static char *kwlist[] = { "stop_chars", "cancellable", NULL };
+    const char *stop_chars;
+    PyGObject *pycancellable = NULL;
+    GCancellable *cancellable;
+    char *line;
+    gsize length;
+    PyObject *py_line;
+    GError *error = NULL;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+				     "s|O:gio.DataInputStream.read_line",
+                                     kwlist, &stop_chars, &pycancellable))
+        return NULL;
+
+    if (!pygio_check_cancellable(pycancellable, &cancellable))
+	return NULL;
+
+    line = g_data_input_stream_read_until(G_DATA_INPUT_STREAM(self->obj),
+					  stop_chars, &length, cancellable, &error);
+    if (pyg_error_check(&error))
+        return NULL;
+
+    py_line = PyString_FromStringAndSize(line, length);
+    g_free(line);
+    return py_line;
+}
+%%
 override g_memory_input_stream_add_data kwargs
 static PyObject *
 _wrap_g_memory_input_stream_add_data(PyGObject *self,
