[pygobject] Remove static io_add_watch() binding
- From: Martin Pitt <martinpitt src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pygobject] Remove static io_add_watch() binding
- Date: Fri, 26 Oct 2012 08:36:40 +0000 (UTC)
commit 366f5d2d3902c6293d0031e0b7dc5d6641a05ac7
Author: Martin Pitt <martinpitt gnome org>
Date: Fri Oct 26 09:26:17 2012 +0200
Remove static io_add_watch() binding
Use the GLib API through GI instead, and provide override to keep backwards
compatible API. Also allow using the actual GLib API, and deprecate all other
variants:
- calling with an fd as first argument instead of an IOChannel
- calling without a priority as second argument
docs/reference/pyglib-functions.xml | 106 -----------------------------------
gi/_glib/__init__.py | 1 -
gi/_glib/glibmodule.c | 98 --------------------------------
gi/_gobject/__init__.py | 1 -
gi/overrides/GLib.py | 51 ++++++++++++++--
gi/overrides/GObject.py | 3 +-
tests/test_glib.py | 15 ++++-
tests/test_iochannel.py | 70 ++++++++++++++++++++++-
8 files changed, 126 insertions(+), 219 deletions(-)
---
diff --git a/docs/reference/pyglib-functions.xml b/docs/reference/pyglib-functions.xml
index 7d70a66..936f750 100644
--- a/docs/reference/pyglib-functions.xml
+++ b/docs/reference/pyglib-functions.xml
@@ -13,13 +13,6 @@
<programlisting>
<methodsynopsis language="python">
- <methodname><link
-linkend="function-glib--io-add-watch">glib.io_add_watch</link></methodname>
- <methodparam><parameter>fd</parameter></methodparam>
- <methodparam><parameter>condition</parameter></methodparam>
- <methodparam><parameter>callback</parameter></methodparam>
- <methodparam><parameter>...</parameter></methodparam>
- </methodsynopsis><methodsynopsis language="python">
<methodname><link linkend="function-glib--child-watch-add">glib.child_watch_add</link></methodname>
<methodparam><parameter role="keyword">pid</parameter></methodparam>
<methodparam><parameter role="keyword">function</parameter></methodparam>
@@ -62,105 +55,6 @@ module but are not directly associated with a specific class.</para>
<refsect1>
<title>Functions</title>
- <refsect2 id="function-glib--io-add-watch">
- <title>glib.io_add_watch</title>
-
- <programlisting><methodsynopsis language="python">
- <methodname>glib.io_add_watch</methodname>
- <methodparam><parameter>fd</parameter></methodparam>
- <methodparam><parameter>condition</parameter></methodparam>
- <methodparam><parameter>callback</parameter></methodparam>
- <methodparam><parameter>...</parameter></methodparam>
- </methodsynopsis></programlisting>
- <variablelist>
- <varlistentry>
- <term><parameter>fd</parameter> :</term>
- <listitem><simpara>a Python file object or an integer file
-descriptor ID</simpara></listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>condition</parameter> :</term>
- <listitem><simpara>a condition mask</simpara></listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>callback</parameter> :</term>
- <listitem><simpara>a function to call</simpara></listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>...</parameter> :</term>
- <listitem><simpara>additional arguments to pass to
-<parameter>callback</parameter></simpara></listitem>
- </varlistentry>
- <varlistentry>
- <term><emphasis>Returns</emphasis> :</term>
- <listitem><simpara>an integer ID of the event source</simpara></listitem>
- </varlistentry>
- </variablelist>
-
- <para>The <function>glib.io_add_watch</function>() function
-arranges for the file (specified by <parameter>fd</parameter>) to be
-monitored by the main loop for the specified
-<parameter>condition</parameter>. <parameter>fd</parameter> may be a Python
-file object or an integer file descriptor. The value of condition is a
-combination of:</para>
-
- <variablelist>
- <varlistentry>
- <term><literal>glib.IO_IN</literal></term>
- <listitem>
- <simpara>There is data to read.</simpara>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>glib.IO_OUT</literal></term>
- <listitem>
- <simpara>Data can be written (without blocking). </simpara>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>glib.IO_PRI</literal></term>
- <listitem>
- <simpara>There is urgent data to read.</simpara>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>glib.IO_ERR</literal></term>
- <listitem>
- <simpara>Error condition.</simpara>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>glib.IO_HUP</literal></term>
- <listitem>
- <simpara>Hung up (the connection has been broken, usually for
-pipes and sockets).</simpara>
- </listitem>
- </varlistentry>
- </variablelist>
-
- <para>Additional arguments to pass to <parameter>callback</parameter>
-can be specified after <parameter>callback</parameter>. The idle priority
-may be specified as a keyword-value pair with the keyword "priority". The
-signature of the callback function is:</para>
-
- <programlisting>
- def callback(source, cb_condition, ...)
-</programlisting>
-
- <para>where <parameter>source</parameter> is
-<parameter>fd</parameter>, the file descriptor;
-<parameter>cb_condition</parameter> is the condition that triggered the
-signal; and, <parameter>...</parameter> are the zero or more arguments that
-were passed to the <function>glib.io_add_watch</function>()
-function.</para>
-
- <para>If the callback function returns <literal>False</literal> it
-will be automatically removed from the list of event sources and will not be
-called again. If it returns <literal>True</literal> it will be called again
-when the condition is matched.</para>
-
- </refsect2>
-
<refsect2 id="function-glib--markup-escape-text">
<title>glib.markup_escape_text</title>
diff --git a/gi/_glib/__init__.py b/gi/_glib/__init__.py
index 7844c12..0d6d302 100644
--- a/gi/_glib/__init__.py
+++ b/gi/_glib/__init__.py
@@ -49,7 +49,6 @@ child_watch_add = _glib.child_watch_add
filename_from_utf8 = _glib.filename_from_utf8
get_current_time = _glib.get_current_time
glib_version = _glib.glib_version
-io_add_watch = _glib.io_add_watch
pyglib_version = _glib.pyglib_version
spawn_async = _glib.spawn_async
threads_init = _glib.threads_init
diff --git a/gi/_glib/glibmodule.c b/gi/_glib/glibmodule.c
index 40c9638..4e20444 100644
--- a/gi/_glib/glibmodule.c
+++ b/gi/_glib/glibmodule.c
@@ -96,97 +96,6 @@ pyglib_threads_init(PyObject *unused, PyObject *args, PyObject *kwargs)
return Py_None;
}
-static gboolean
-iowatch_marshal(GIOChannel *source,
- GIOCondition condition,
- gpointer user_data)
-{
- PyGILState_STATE state;
- PyObject *tuple, *func, *firstargs, *args, *ret;
- gboolean res;
-
- g_return_val_if_fail(user_data != NULL, FALSE);
-
- state = pyglib_gil_state_ensure();
-
- tuple = (PyObject *)user_data;
- func = PyTuple_GetItem(tuple, 0);
-
- /* arg vector is (fd, condtion, *args) */
- firstargs = Py_BuildValue("(Oi)", PyTuple_GetItem(tuple, 1), condition);
- args = PySequence_Concat(firstargs, PyTuple_GetItem(tuple, 2));
- Py_DECREF(firstargs);
-
- ret = PyObject_CallObject(func, args);
- Py_DECREF(args);
- if (!ret) {
- PyErr_Print();
- res = FALSE;
- } else {
- if (ret == Py_None) {
- if (PyErr_Warn(PyExc_Warning,
- "_glib.io_add_watch callback returned None; "
- "should return True/False")) {
- PyErr_Print();
- }
- }
- res = PyObject_IsTrue(ret);
- Py_DECREF(ret);
- }
-
- pyglib_gil_state_release(state);
-
- return res;
-}
-
-static PyObject *
-pyglib_io_add_watch(PyObject *self, PyObject *args, PyObject *kwargs)
-{
- PyObject *first, *pyfd, *callback, *cbargs = NULL, *data;
- gint fd, priority = G_PRIORITY_DEFAULT, condition;
- Py_ssize_t len;
- GIOChannel *iochannel;
- guint handler_id;
-
- len = PyTuple_Size(args);
- if (len < 3) {
- PyErr_SetString(PyExc_TypeError,
- "io_add_watch requires at least 3 args");
- return NULL;
- }
- first = PySequence_GetSlice(args, 0, 3);
- if (!PyArg_ParseTuple(first, "OiO:io_add_watch", &pyfd, &condition,
- &callback)) {
- Py_DECREF(first);
- return NULL;
- }
- Py_DECREF(first);
- fd = PyObject_AsFileDescriptor(pyfd);
- if (fd < 0) {
- return NULL;
- }
- if (!PyCallable_Check(callback)) {
- PyErr_SetString(PyExc_TypeError, "third argument not callable");
- return NULL;
- }
- if (get_handler_priority(&priority, kwargs) < 0)
- return NULL;
-
- cbargs = PySequence_GetSlice(args, 3, len);
- if (cbargs == NULL)
- return NULL;
- data = Py_BuildValue("(OON)", callback, pyfd, cbargs);
- if (data == NULL)
- return NULL;
- iochannel = g_io_channel_unix_new(fd);
- handler_id = g_io_add_watch_full(iochannel, priority, condition,
- iowatch_marshal, data,
- (GDestroyNotify)_pyglib_destroy_notify);
- g_io_channel_unref(iochannel);
-
- return PYGLIB_PyLong_FromLong(handler_id);
-}
-
static void
child_watch_func(GPid pid, gint status, gpointer data)
{
@@ -290,13 +199,6 @@ static PyMethodDef _glib_functions[] = {
"Initialize GLib for use from multiple threads. If you also use GTK+\n"
"itself (i.e. GUI, not just PyGObject), use gtk.gdk.threads_init()\n"
"instead." },
- { "io_add_watch",
- (PyCFunction)pyglib_io_add_watch, METH_VARARGS|METH_KEYWORDS,
- "io_add_watch(fd, condition, callback, user_data=None) -> source id\n"
- " callable receives (fd, condition, user_data)\n"
- "Arranges for the fd to be monitored by the main loop for the\n"
- "specified condition. Condition is a combination of glib.IO_IN,\n"
- "glib.IO_OUT, glib.IO_PRI, gio.IO_ERR and gio.IO_HUB.\n" },
{ "child_watch_add",
(PyCFunction)pyglib_child_watch_add, METH_VARARGS|METH_KEYWORDS,
"child_watch_add(pid, callable, user_data=None,\n"
diff --git a/gi/_gobject/__init__.py b/gi/_gobject/__init__.py
index 75f6643..c774df6 100644
--- a/gi/_gobject/__init__.py
+++ b/gi/_gobject/__init__.py
@@ -82,7 +82,6 @@ type_parent = _gobject.type_parent
type_register = _gobject.type_register
spawn_async = _glib.spawn_async
-io_add_watch = _glib.io_add_watch
child_watch_add = _glib.child_watch_add
get_current_time = _glib.get_current_time
filename_from_utf8 = _glib.filename_from_utf8
diff --git a/gi/overrides/GLib.py b/gi/overrides/GLib.py
index 996bc3d..65c7e8e 100644
--- a/gi/overrides/GLib.py
+++ b/gi/overrides/GLib.py
@@ -20,6 +20,7 @@
# USA
import signal
+import warnings
from ..module import get_introspection_module
from .._gi import (variant_new_tuple, variant_type_from_string, source_new,
@@ -596,6 +597,46 @@ def timeout_add_seconds(interval, function, user_data=_unspecified, priority=GLi
__all__.append('timeout_add_seconds')
+# The real GLib API is io_add_watch(IOChannel, priority, condition, callback,
+# user_data). This needs to take into account several deprecated APIs:
+# - calling with an fd as first argument
+# - calling without a priority as second argument
+# and the usual "call without user_data", in which case the callback does not
+# get an user_data either.
+def io_add_watch(channel, priority, condition, callback=_unspecified, user_data=_unspecified):
+ if not isinstance(priority, int) or isinstance(priority, GLib.IOCondition):
+ warnings.warn('Calling io_add_watch without priority as second argument is deprecated',
+ DeprecationWarning)
+ # shift the arguments around
+ user_data = callback
+ callback = condition
+ condition = priority
+ 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
+
+ # backwards compatibility: Allow calling with fd
+ if isinstance(channel, int):
+ warnings.warn('Calling io_add_watch with a file descriptor is deprecated; call it with a GLib.IOChannel object',
+ DeprecationWarning)
+ func_fdtransform = lambda _, cond, data: func(channel, cond, data)
+ real_channel = GLib.IOChannel.unix_new(channel)
+ else:
+ assert isinstance(channel, GLib.IOChannel)
+ func_fdtransform = func
+ real_channel = channel
+
+ return GLib.io_add_watch(real_channel, priority, condition,
+ func_fdtransform, user_data)
+
+__all__.append('io_add_watch')
+
+
# backwards compatible API
class IOChannel(GLib.IOChannel):
def __new__(cls, filedes=None, filename=None, mode=None, hwnd=None):
@@ -655,13 +696,9 @@ class IOChannel(GLib.IOChannel):
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)
+ return io_add_watch(self, priority, condition, callback, user_data)
+
+ add_watch = deprecated(add_watch, 'GLib.io_add_watch()')
def __iter__(self):
return self
diff --git a/gi/overrides/GObject.py b/gi/overrides/GObject.py
index 305a25f..7925dab 100644
--- a/gi/overrides/GObject.py
+++ b/gi/overrides/GObject.py
@@ -31,7 +31,8 @@ for name in ['markup_escape_text', 'get_application_name',
'filename_display_name', 'uri_list_extract_uris',
'MainLoop', 'MainContext', 'main_context_default',
'source_remove', 'Source', 'Idle', 'Timeout', 'PollFD',
- 'idle_add', 'timeout_add', 'timeout_add_seconds']:
+ 'idle_add', 'timeout_add', 'timeout_add_seconds',
+ 'io_add_watch']:
globals()[name] = gi.overrides.deprecated(getattr(GLib, name), 'GLib.' + name)
__all__.append(name)
diff --git a/tests/test_glib.py b/tests/test_glib.py
index 9170496..f2f28aa 100644
--- a/tests/test_glib.py
+++ b/tests/test_glib.py
@@ -3,6 +3,7 @@
import unittest
import os.path
+import warnings
from gi.repository import GLib
@@ -110,7 +111,12 @@ https://my.org/q?x=1&y=2
call_data.append((fd, condition, os.read(fd, 1)))
return True
- GLib.io_add_watch(r, GLib.IOCondition.IN, cb)
+ # io_add_watch() takes an IOChannel, calling with an fd is deprecated
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.simplefilter('always')
+ GLib.io_add_watch(r, GLib.IOCondition.IN, cb)
+ self.assertTrue(issubclass(warn[0].category, DeprecationWarning))
+
ml = GLib.MainLoop()
GLib.timeout_add(10, lambda: os.write(w, b'a') and False)
GLib.timeout_add(100, lambda: os.write(w, b'b') and False)
@@ -128,7 +134,12 @@ https://my.org/q?x=1&y=2
call_data.append((fd, condition, os.read(fd, 1), data))
return True
- GLib.io_add_watch(r, GLib.IOCondition.IN, cb, 'moo')
+ # io_add_watch() takes an IOChannel, calling with an fd is deprecated
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.simplefilter('always')
+ GLib.io_add_watch(r, GLib.IOCondition.IN, cb, 'moo')
+ self.assertTrue(issubclass(warn[0].category, DeprecationWarning))
+
ml = GLib.MainLoop()
GLib.timeout_add(10, lambda: os.write(w, b'a') and False)
GLib.timeout_add(100, lambda: os.write(w, b'b') and False)
diff --git a/tests/test_iochannel.py b/tests/test_iochannel.py
index 85af822..e0eca2a 100644
--- a/tests/test_iochannel.py
+++ b/tests/test_iochannel.py
@@ -6,6 +6,7 @@ import tempfile
import os.path
import fcntl
import shutil
+import warnings
from gi.repository import GLib
@@ -198,7 +199,7 @@ second line
self.assertEqual(os.read(r, 10), b'\x03\x04')
os.close(r)
- def test_add_watch_no_data(self):
+ def test_deprecated_add_watch_no_data(self):
(r, w) = os.pipe()
ch = GLib.IOChannel(filedes=r)
@@ -213,7 +214,11 @@ second line
cb_reads.append(channel.read())
return True
- ch.add_watch(GLib.IOCondition.IN, cb)
+ # io_add_watch() method is deprecated, use GLib.io_add_watch
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.simplefilter('always')
+ ch.add_watch(GLib.IOCondition.IN, cb)
+ self.assertTrue(issubclass(warn[0].category, DeprecationWarning))
ml = GLib.MainLoop()
@@ -241,7 +246,11 @@ second line
return True
ml = GLib.MainLoop()
- id = ch.add_watch(GLib.IOCondition.IN, cb, 'hello', GLib.PRIORITY_HIGH)
+ # io_add_watch() method is deprecated, use GLib.io_add_watch
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.simplefilter('always')
+ id = ch.add_watch(GLib.IOCondition.IN, cb, 'hello', GLib.PRIORITY_HIGH)
+ self.assertTrue(issubclass(warn[0].category, DeprecationWarning))
self.assertEqual(ml.get_context().find_source_by_id(id).priority,
GLib.PRIORITY_HIGH)
@@ -253,6 +262,61 @@ second line
self.assertEqual(cb_reads, [b'a', b'b'])
+ def test_add_watch_no_data(self):
+ (r, w) = os.pipe()
+
+ ch = GLib.IOChannel(filedes=r)
+ ch.set_encoding(None)
+ ch.set_flags(ch.get_flags() | GLib.IOFlags.NONBLOCK)
+
+ cb_reads = []
+
+ def cb(channel, condition):
+ self.assertEqual(channel, ch)
+ self.assertEqual(condition, GLib.IOCondition.IN)
+ cb_reads.append(channel.read())
+ return True
+
+ id = GLib.io_add_watch(ch, GLib.PRIORITY_HIGH, GLib.IOCondition.IN, cb)
+
+ ml = GLib.MainLoop()
+ self.assertEqual(ml.get_context().find_source_by_id(id).priority,
+ GLib.PRIORITY_HIGH)
+ GLib.timeout_add(10, lambda: os.write(w, b'a') and False)
+ GLib.timeout_add(100, lambda: os.write(w, b'b') and False)
+ GLib.timeout_add(200, ml.quit)
+ ml.run()
+
+ self.assertEqual(cb_reads, [b'a', b'b'])
+
+ def test_add_watch_with_data(self):
+ (r, w) = os.pipe()
+
+ ch = GLib.IOChannel(filedes=r)
+ ch.set_encoding(None)
+ ch.set_flags(ch.get_flags() | GLib.IOFlags.NONBLOCK)
+
+ cb_reads = []
+
+ def cb(channel, condition, data):
+ self.assertEqual(channel, ch)
+ self.assertEqual(condition, GLib.IOCondition.IN)
+ self.assertEqual(data, 'hello')
+ cb_reads.append(channel.read())
+ return True
+
+ id = GLib.io_add_watch(ch, GLib.PRIORITY_HIGH, GLib.IOCondition.IN, cb, 'hello')
+
+ ml = GLib.MainLoop()
+ self.assertEqual(ml.get_context().find_source_by_id(id).priority,
+ GLib.PRIORITY_HIGH)
+ GLib.timeout_add(10, lambda: os.write(w, b'a') and False)
+ GLib.timeout_add(100, lambda: os.write(w, b'b') and False)
+ GLib.timeout_add(200, ml.quit)
+ ml.run()
+
+ self.assertEqual(cb_reads, [b'a', b'b'])
+
def test_backwards_compat_flags(self):
self.assertEqual(GLib.IOCondition.IN, GLib.IO_IN)
self.assertEqual(GLib.IOFlags.NONBLOCK, GLib.IO_FLAG_NONBLOCK)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]