[pygobject] Remove static GIOChannel bindings
- From: Martin Pitt <martinpitt src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pygobject] Remove static GIOChannel bindings
- Date: Thu, 25 Oct 2012 13:57:38 +0000 (UTC)
commit 15e717ce2c2a26c02c913f79bc7cf6876d943e92
Author: Martin Pitt <martinpitt gnome org>
Date: Thu Oct 25 15:55:46 2012 +0200
Remove static GIOChannel bindings
Use the GLib API through GI instead, and provide overrides to keep backwards
compatible API, including its bugs.
We still need to keep a static wrapper around g_io_channel_read_chars() until
we teach PyGObject to correctly handle caller allocated out array arguments.
https://bugzilla.gnome.org/show_bug.cgi?id=686795
gi/_glib/Makefile.am | 2 -
gi/_glib/__init__.py | 1 -
gi/_glib/glibmodule.c | 2 -
gi/_glib/pygiochannel.c | 748 -----------------------------------------------
gi/_glib/pygiochannel.h | 29 --
gi/_gobject/__init__.py | 1 -
gi/gimodule.c | 72 +++++
gi/overrides/GLib.py | 95 ++++++-
8 files changed, 161 insertions(+), 789 deletions(-)
---
diff --git a/gi/_glib/Makefile.am b/gi/_glib/Makefile.am
index fed1b43..1f004a2 100644
--- a/gi/_glib/Makefile.am
+++ b/gi/_glib/Makefile.am
@@ -52,8 +52,6 @@ pyglib_LTLIBRARIES = _glib.la
_glib_la_SOURCES = \
glibmodule.c \
- pygiochannel.c \
- pygiochannel.h \
pygoptioncontext.c \
pygoptioncontext.h \
pygoptiongroup.c \
diff --git a/gi/_glib/__init__.py b/gi/_glib/__init__.py
index 145685e..7844c12 100644
--- a/gi/_glib/__init__.py
+++ b/gi/_glib/__init__.py
@@ -26,7 +26,6 @@ _PyGLib_API = _glib._PyGLib_API
# Types
GError = _glib.GError
-IOChannel = _glib.IOChannel
OptionContext = _glib.OptionContext
OptionGroup = _glib.OptionGroup
Pid = _glib.Pid
diff --git a/gi/_glib/glibmodule.c b/gi/_glib/glibmodule.c
index 1513748..40c9638 100644
--- a/gi/_glib/glibmodule.c
+++ b/gi/_glib/glibmodule.c
@@ -29,7 +29,6 @@
#include <glib.h>
#include "pyglib.h"
#include "pyglib-private.h"
-#include "pygiochannel.h"
#include "pygoptioncontext.h"
#include "pygoptiongroup.h"
#include "pygsource.h"
@@ -424,7 +423,6 @@ PYGLIB_MODULE_START(_glib, "_glib")
pyglib_register_api(d);
pyglib_register_error(d);
pyglib_register_version_tuples(d);
- pyglib_iochannel_register_types(d);
pyglib_source_register_types(d);
pyglib_spawn_register_types(d);
pyglib_option_context_register_types(d);
diff --git a/gi/_gobject/__init__.py b/gi/_gobject/__init__.py
index 50a130f..75f6643 100644
--- a/gi/_gobject/__init__.py
+++ b/gi/_gobject/__init__.py
@@ -89,7 +89,6 @@ filename_from_utf8 = _glib.filename_from_utf8
Pid = _glib.Pid
GError = _glib.GError
glib_version = _glib.glib_version
-IOChannel = _glib.IOChannel
OptionGroup = _glib.OptionGroup
OptionContext = _glib.OptionContext
diff --git a/gi/gimodule.c b/gi/gimodule.c
index fcab468..76530f1 100644
--- a/gi/gimodule.c
+++ b/gi/gimodule.c
@@ -23,6 +23,7 @@
#include "pygi-private.h"
#include "pygi.h"
+#include "pyglib.h"
#include <pygobject.h>
#include <pyglib-python-compat.h>
@@ -461,6 +462,76 @@ _wrap_pyg_source_new (PyObject *self, PyObject *args)
return pyg_source_new ();
}
+#define CHUNK_SIZE 8192
+
+static PyObject*
+pyg_channel_read(PyObject* self, PyObject *args, PyObject *kwargs)
+{
+ int max_count = -1;
+ PyObject *py_iochannel, *ret_obj = NULL;
+ gsize total_read = 0;
+ GError* error = NULL;
+ GIOStatus status = G_IO_STATUS_NORMAL;
+
+ if (!PyArg_ParseTuple (args, "Oi:pyg_channel_read", &py_iochannel, &max_count)) {
+ return NULL;
+ }
+ if (!pyg_boxed_check (py_iochannel, G_TYPE_IO_CHANNEL)) {
+ PyErr_SetString(PyExc_TypeError, "first argument is not a GLib.IOChannel");
+ return NULL;
+ }
+
+ if (max_count == 0)
+ return PYGLIB_PyBytes_FromString("");
+
+ while (status == G_IO_STATUS_NORMAL
+ && (max_count == -1 || total_read < max_count)) {
+ gsize single_read;
+ char* buf;
+ gsize buf_size;
+
+ if (max_count == -1)
+ buf_size = CHUNK_SIZE;
+ else {
+ buf_size = max_count - total_read;
+ if (buf_size > CHUNK_SIZE)
+ buf_size = CHUNK_SIZE;
+ }
+
+ if ( ret_obj == NULL ) {
+ ret_obj = PYGLIB_PyBytes_FromStringAndSize((char *)NULL, buf_size);
+ if (ret_obj == NULL)
+ goto failure;
+ }
+ else if (buf_size + total_read > PYGLIB_PyBytes_Size(ret_obj)) {
+ if (PYGLIB_PyBytes_Resize(&ret_obj, buf_size + total_read) == -1)
+ goto failure;
+ }
+
+ buf = PYGLIB_PyBytes_AsString(ret_obj) + total_read;
+
+ pyglib_unblock_threads();
+ status = g_io_channel_read_chars(pyg_boxed_get (py_iochannel, GIOChannel),
+ buf, buf_size, &single_read, &error);
+ pyglib_block_threads();
+ if (pyglib_error_check(&error))
+ goto failure;
+
+ total_read += single_read;
+ }
+
+ if ( total_read != PYGLIB_PyBytes_Size(ret_obj) ) {
+ if (PYGLIB_PyBytes_Resize(&ret_obj, total_read) == -1)
+ goto failure;
+ }
+
+ return ret_obj;
+
+ failure:
+ Py_XDECREF(ret_obj);
+ return NULL;
+}
+
static PyMethodDef _gi_functions[] = {
{ "enum_add", (PyCFunction) _wrap_pyg_enum_add, METH_VARARGS | METH_KEYWORDS },
@@ -474,6 +545,7 @@ static PyMethodDef _gi_functions[] = {
{ "variant_type_from_string", (PyCFunction) _wrap_pyg_variant_type_from_string, METH_VARARGS },
{ "source_new", (PyCFunction) _wrap_pyg_source_new, METH_NOARGS },
{ "source_set_callback", (PyCFunction) pyg_source_set_callback, METH_VARARGS },
+ { "io_channel_read", (PyCFunction) pyg_channel_read, METH_VARARGS },
{ NULL, NULL, 0 }
};
diff --git a/gi/overrides/GLib.py b/gi/overrides/GLib.py
index 22de6bf..996bc3d 100644
--- a/gi/overrides/GLib.py
+++ b/gi/overrides/GLib.py
@@ -22,7 +22,8 @@
import signal
from ..module import get_introspection_module
-from .._gi import variant_new_tuple, variant_type_from_string, source_new, source_set_callback
+from .._gi import (variant_new_tuple, variant_type_from_string, source_new,
+ source_set_callback, io_channel_read)
from ..overrides import override, deprecated
GLib = get_introspection_module('GLib')
@@ -563,37 +564,119 @@ class Timeout(Source):
__all__.append('Timeout')
-__unspecified = object()
+_unspecified = object()
# backwards compatible API
def _glib_idle_adjust_callback(function, user_data):
- if user_data is __unspecified:
+ if user_data is _unspecified:
# we have to call the callback without the user_data argument
return (lambda data: function(), None)
return (function, user_data)
-def idle_add(function, user_data=__unspecified, priority=GLib.PRIORITY_DEFAULT_IDLE):
+def idle_add(function, user_data=_unspecified, priority=GLib.PRIORITY_DEFAULT_IDLE):
(function, user_data) = _glib_idle_adjust_callback(function, user_data)
return GLib.idle_add(priority, function, user_data)
__all__.append('idle_add')
-def timeout_add(interval, function, user_data=__unspecified, priority=GLib.PRIORITY_DEFAULT):
+def timeout_add(interval, function, user_data=_unspecified, priority=GLib.PRIORITY_DEFAULT):
(function, user_data) = _glib_idle_adjust_callback(function, user_data)
return GLib.timeout_add(priority, interval, function, user_data)
__all__.append('timeout_add')
-def timeout_add_seconds(interval, function, user_data=__unspecified, priority=GLib.PRIORITY_DEFAULT):
+def timeout_add_seconds(interval, function, user_data=_unspecified, priority=GLib.PRIORITY_DEFAULT):
(function, user_data) = _glib_idle_adjust_callback(function, user_data)
return GLib.timeout_add_seconds(priority, interval, function, user_data)
__all__.append('timeout_add_seconds')
+
+# backwards compatible API
+class IOChannel(GLib.IOChannel):
+ def __new__(cls, filedes=None, filename=None, mode=None, hwnd=None):
+ if filedes is not None:
+ return GLib.IOChannel.unix_new(filedes)
+ if filename is not None:
+ return GLib.IOChannel.new_file(filename, mode or 'r')
+ if hwnd is not None:
+ return GLib.IOChannel.win32_new_fd(hwnd)
+ raise TypeError('either a valid file descriptor, file name, or window handle must be supplied')
+
+ def read(self, max_count=-1):
+ return io_channel_read(self, max_count)
+
+ def readline(self, size_hint=-1):
+ # note, size_hint is just to maintain backwards compatible API; the
+ # old static binding did not actually use it
+ (status, buf, length, terminator_pos) = self.read_line()
+ if buf is None:
+ return ''
+ return buf
+
+ def readlines(self, size_hint=-1):
+ # note, size_hint is just to maintain backwards compatible API;
+ # the old static binding did not actually use it
+ lines = []
+ status = GLib.IOStatus.NORMAL
+ while status == GLib.IOStatus.NORMAL:
+ (status, buf, length, terminator_pos) = self.read_line()
+ # note, this appends an empty line after EOF; this is
+ # bug-compatible with the old static bindings
+ if buf is None:
+ buf = ''
+ lines.append(buf)
+ return lines
+
+ def write(self, buf, buflen=-1):
+ if not isinstance(buf, bytes):
+ buf = buf.encode('UTF-8')
+ if buflen == -1:
+ buflen = len(buf)
+ (status, written) = self.write_chars(buf, buflen)
+ return written
+
+ def writelines(self, lines):
+ for line in lines:
+ self.write(line)
+
+ _whence_map = {0: GLib.SeekType.SET, 1: GLib.SeekType.CUR, 2: GLib.SeekType.END}
+
+ def seek(self, offset, whence=0):
+ try:
+ w = self._whence_map[whence]
+ except KeyError:
+ raise ValueError("invalid 'whence' value")
+ return self.seek_position(offset, w)
+
+ def add_watch(self, condition, callback, user_data=_unspecified,
+ priority=GLib.PRIORITY_DEFAULT):
+ if user_data is _unspecified:
+ # we have to call the callback without the user_data argument
+ func = lambda channel, cond, data: callback(channel, cond)
+ user_data = None
+ else:
+ func = callback
+ return GLib.io_add_watch(self, priority, condition, func, user_data)
+
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ (status, buf, length, terminator_pos) = self.read_line()
+ if status == GLib.IOStatus.NORMAL:
+ return buf
+ raise StopIteration
+
+
+IOChannel = override(IOChannel)
+__all__.append('IOChannel')
+
+
# work around wrong constants in GLib GIR, see
# https://bugzilla.gnome.org/show_bug.cgi?id=685022
MININT64 = -9223372036854775808
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]