Commit 80db2a50 authored by Simon Feltman's avatar Simon Feltman
Browse files

Fix GLib override incompatibilities with old static API

Change idle_add, timeout_add, timeout_add_seconds, and
io_add_watch to accept *args and **kwargs as arguments
to the callback functions instead of only accepting a single
user_data arg. This ensures the new overridden introspection
methods are backwards compatible with the static versions
they replaced.

https://bugzilla.gnome.org/show_bug.cgi?id=687047
parent 9c6399bb
......@@ -569,31 +569,55 @@ __all__.append('Timeout')
_unspecified = object()
# backwards compatible API
def _glib_idle_adjust_callback(function, user_data):
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, *args, **kwargs):
'''Add idle callback with variable arguments.
Accepts priority as keyword argument (default GLib.PRIORITY_DEFAULT_IDLE).
Remaining args and kwargs will be passed to callback.
'''
newkwargs = kwargs.copy()
if 'priority' in newkwargs:
priority = newkwargs.pop('priority')
else:
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)
return GLib.idle_add(priority, lambda _: function(*args, **newkwargs), None)
__all__.append('idle_add')
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)
def timeout_add(interval, function, *args, **kwargs):
'''Add timeout callback with variable arguments.
Accepts priority as keyword argument (default GLib.PRIORITY_DEFAULT).
Remaining args and kwargs will be passed to callback.
'''
newkwargs = kwargs.copy()
if 'priority' in newkwargs:
priority = newkwargs.pop('priority')
else:
priority = GLib.PRIORITY_DEFAULT
return GLib.timeout_add(priority, interval,
lambda _: function(*args, **newkwargs), None)
__all__.append('timeout_add')
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)
def timeout_add_seconds(interval, function, *args, **kwargs):
'''Add timeout callback in seconds with variable arguments.
Accepts "priority" as keyword argument (default GLib.PRIORITY_DEFAULT).
Remaining args and kwargs will be passed to callback.
'''
newkwargs = kwargs.copy()
if 'priority' in newkwargs:
priority = newkwargs.pop('priority')
else:
priority = GLib.PRIORITY_DEFAULT
return GLib.timeout_add_seconds(priority, interval,
lambda _: function(*args, **newkwargs), None)
__all__.append('timeout_add_seconds')
......@@ -605,42 +629,33 @@ __all__.append('timeout_add_seconds')
# - 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',
PyGIDeprecationWarning)
# 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
def io_add_watch(channel, condition, callback, *args, **kwargs):
newkwargs = kwargs.copy()
if 'priority' in newkwargs:
priority = newkwargs.pop('priority')
else:
func = callback
priority = GLib.PRIORITY_DEFAULT
# backwards compatibility: Allow calling with fd
if isinstance(channel, int):
if isinstance(channel, GLib.IOChannel):
func_fdtransform = lambda chan, cond, data: callback(chan, cond, *args, **newkwargs)
real_channel = channel
elif isinstance(channel, int):
# backwards compatibility: Allow calling with fd
warnings.warn('Calling io_add_watch with a file descriptor is deprecated; call it with a GLib.IOChannel object',
PyGIDeprecationWarning)
func_fdtransform = lambda _, cond, data: func(channel, cond, data)
func_fdtransform = lambda _, cond, data: callback(channel, cond, *args, **newkwargs)
real_channel = GLib.IOChannel.unix_new(channel)
elif hasattr(channel, 'fileno'):
# backwards compatibility: Allow calling with Python file
warnings.warn('Calling io_add_watch with a file object is deprecated; call it with a GLib.IOChannel object',
PyGIDeprecationWarning)
func_fdtransform = lambda _, cond, data: func(channel, cond, data)
func_fdtransform = lambda _, cond, data: callback(channel, cond, *args, **newkwargs)
real_channel = GLib.IOChannel.unix_new(channel.fileno())
else:
assert isinstance(channel, GLib.IOChannel)
func_fdtransform = func
real_channel = channel
raise TypeError('Expected a GLib.IOChannel, but got %s' % type(channel))
return GLib.io_add_watch(real_channel, priority, condition,
func_fdtransform, user_data)
func_fdtransform, None)
__all__.append('io_add_watch')
......@@ -702,9 +717,8 @@ class IOChannel(GLib.IOChannel):
raise ValueError("invalid 'whence' value")
return self.seek_position(offset, w)
def add_watch(self, condition, callback, user_data=_unspecified,
priority=GLib.PRIORITY_DEFAULT):
return io_add_watch(self, priority, condition, callback, user_data)
def add_watch(self, condition, callback, *args, **kwargs):
return io_add_watch(self, condition, callback, *args, **kwargs)
add_watch = deprecated(add_watch, 'GLib.io_add_watch()')
......
......@@ -251,7 +251,7 @@ second line
# 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)
id = ch.add_watch(GLib.IOCondition.IN, cb, 'hello', priority=GLib.PRIORITY_HIGH)
self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning))
self.assertEqual(ml.get_context().find_source_by_id(id).priority,
......@@ -279,7 +279,7 @@ second line
cb_reads.append(channel.read())
return True
id = GLib.io_add_watch(ch, GLib.PRIORITY_HIGH, GLib.IOCondition.IN, cb)
id = GLib.io_add_watch(ch, GLib.IOCondition.IN, cb, priority=GLib.PRIORITY_HIGH)
ml = GLib.MainLoop()
self.assertEqual(ml.get_context().find_source_by_id(id).priority,
......@@ -307,7 +307,38 @@ second line
cb_reads.append(channel.read())
return True
id = GLib.io_add_watch(ch, GLib.PRIORITY_HIGH, GLib.IOCondition.IN, cb, 'hello')
id = GLib.io_add_watch(ch, GLib.IOCondition.IN, cb, 'hello', priority=GLib.PRIORITY_HIGH)
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_multi_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, data1, data2, data3):
self.assertEqual(channel, ch)
self.assertEqual(condition, GLib.IOCondition.IN)
self.assertEqual(data1, 'a')
self.assertEqual(data2, 'b')
self.assertEqual(data3, 'c')
cb_reads.append(channel.read())
return True
id = GLib.io_add_watch(ch, GLib.IOCondition.IN, cb,
'a', 'b', 'c', priority=GLib.PRIORITY_HIGH)
ml = GLib.MainLoop()
self.assertEqual(ml.get_context().find_source_by_id(id).priority,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment