Commit d7f095b0 authored by Martin Pitt's avatar Martin Pitt
Browse files

Restore actual GLib API after previous fix

Re-fix the acceptance of priority as first argument for idle_add(),
io_add_watch() and timeout_add(), as that is the real GLib API. Ensure that
this keeps supporting the backwards compatible API with supplying multiple user
data arguments.

https://bugzilla.gnome.org/show_bug.cgi?id=687047
parent 648b653d
......@@ -569,55 +569,36 @@ __all__.append('Timeout')
_unspecified = object()
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
# backwards compatible API
def idle_add(function, *user_data, **kwargs):
priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT_IDLE)
if len(user_data) == 1:
return GLib.idle_add(priority, function, user_data[0])
return GLib.idle_add(priority, lambda _: function(*args, **newkwargs), None)
# backwards compat: we have to call the callback with all the user_data arguments
return GLib.idle_add(priority, lambda data: function(*data), user_data)
__all__.append('idle_add')
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
def timeout_add(interval, function, *user_data, **kwargs):
priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT)
if len(user_data) == 1:
return GLib.timeout_add(priority, interval, function, user_data[0])
return GLib.timeout_add(priority, interval,
lambda _: function(*args, **newkwargs), None)
# backwards compat: we have to call the callback with all the user_data arguments
return GLib.timeout_add(priority, interval, lambda data: function(*data), user_data)
__all__.append('timeout_add')
def timeout_add_seconds(interval, function, *args, **kwargs):
'''Add timeout callback in seconds with variable arguments.
def timeout_add_seconds(interval, function, *user_data, **kwargs):
priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT)
if len(user_data) == 1:
return GLib.timeout_add_seconds(priority, interval, function, user_data[0])
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)
# backwards compat: we have to call the callback with all the user_data arguments
return GLib.timeout_add_seconds(priority, interval, lambda data: function(*data), user_data)
__all__.append('timeout_add_seconds')
......@@ -627,35 +608,56 @@ __all__.append('timeout_add_seconds')
# - calling with an fd as first argument
# - calling with a Python file object 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, condition, callback, *args, **kwargs):
newkwargs = kwargs.copy()
if 'priority' in newkwargs:
priority = newkwargs.pop('priority')
# and the usual "call without or multiple user_data", in which case the
# callback gets the same user data arguments.
def io_add_watch(channel, priority_, condition, callback=_unspecified, *user_data, **kwargs):
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
if callback == _unspecified:
user_data = ()
else:
user_data = (callback,) + user_data
callback = condition
condition = priority_
priority_ = GLib.PRIORITY_DEFAULT
if len(user_data) != 1:
# we have to call the callback with the user_data arguments
func = lambda channel, cond, data: callback(channel, cond, *data)
elif user_data[0] == _unspecified:
user_data = None
func = lambda channel, cond, data: callback(channel, cond)
else:
priority = GLib.PRIORITY_DEFAULT
user_data = user_data[0]
func = callback
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
# 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',
PyGIDeprecationWarning)
func_fdtransform = lambda _, cond, data: callback(channel, cond, *args, **newkwargs)
func_fdtransform = lambda _, cond, data: func(channel, cond, data)
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: callback(channel, cond, *args, **newkwargs)
func_fdtransform = lambda _, cond, data: func(channel, cond, data)
real_channel = GLib.IOChannel.unix_new(channel.fileno())
else:
raise TypeError('Expected a GLib.IOChannel, but got %s' % type(channel))
assert isinstance(channel, GLib.IOChannel)
func_fdtransform = func
real_channel = channel
# backwards compatibility: Call with priority kwarg
if 'priority' in kwargs:
warnings.warn('Calling io_add_watch with priority keyword argument is deprecated, put it as second positional argument',
PyGIDeprecationWarning)
priority_ = kwargs['priority']
return GLib.io_add_watch(real_channel, priority, condition,
func_fdtransform, None)
return GLib.io_add_watch(real_channel, priority_, condition,
func_fdtransform, user_data)
__all__.append('io_add_watch')
......@@ -717,8 +719,9 @@ class IOChannel(GLib.IOChannel):
raise ValueError("invalid 'whence' value")
return self.seek_position(offset, w)
def add_watch(self, condition, callback, *args, **kwargs):
return io_add_watch(self, condition, callback, *args, **kwargs)
def add_watch(self, condition, callback, user_data=_unspecified,
priority=GLib.PRIORITY_DEFAULT):
return io_add_watch(self, priority, condition, callback, user_data)
add_watch = deprecated(add_watch, 'GLib.io_add_watch()')
......
......@@ -201,7 +201,7 @@ second line
self.assertEqual(os.read(r, 10), b'\x03\x04')
os.close(r)
def test_deprecated_add_watch_no_data(self):
def test_deprecated_method_add_watch_no_data(self):
(r, w) = os.pipe()
ch = GLib.IOChannel(filedes=r)
......@@ -231,7 +231,7 @@ second line
self.assertEqual(cb_reads, [b'a', b'b'])
def test_add_watch_data_priority(self):
def test_deprecated_method_add_watch_data_priority(self):
(r, w) = os.pipe()
ch = GLib.IOChannel(filedes=r)
......@@ -279,7 +279,7 @@ second line
cb_reads.append(channel.read())
return True
id = GLib.io_add_watch(ch, GLib.IOCondition.IN, cb, priority=GLib.PRIORITY_HIGH)
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,
......@@ -307,7 +307,7 @@ second line
cb_reads.append(channel.read())
return True
id = GLib.io_add_watch(ch, GLib.IOCondition.IN, cb, 'hello', priority=GLib.PRIORITY_HIGH)
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,
......@@ -337,8 +337,70 @@ second line
cb_reads.append(channel.read())
return True
id = GLib.io_add_watch(ch, GLib.IOCondition.IN, cb,
'a', 'b', 'c', priority=GLib.PRIORITY_HIGH)
id = GLib.io_add_watch(ch, GLib.PRIORITY_HIGH, GLib.IOCondition.IN, cb,
'a', 'b', 'c')
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_deprecated_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
with warnings.catch_warnings(record=True) as warn:
warnings.simplefilter('always')
id = GLib.io_add_watch(ch, GLib.IOCondition.IN, cb, priority=GLib.PRIORITY_HIGH)
self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning))
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_deprecated_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
with warnings.catch_warnings(record=True) as warn:
warnings.simplefilter('always')
id = GLib.io_add_watch(ch, GLib.IOCondition.IN, cb, 'hello',
priority=GLib.PRIORITY_HIGH)
self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning))
ml = GLib.MainLoop()
self.assertEqual(ml.get_context().find_source_by_id(id).priority,
......
......@@ -218,6 +218,21 @@ class TestUserData(unittest.TestCase):
ml.run()
self.assertTrue(data['called'])
def test_idle_multidata(self):
ml = GLib.MainLoop()
def cb(data, data2):
data['called'] = True
data['data2'] = data2
ml.quit()
data = {}
id = GLib.idle_add(cb, data, 'hello')
self.assertEqual(ml.get_context().find_source_by_id(id).priority,
GLib.PRIORITY_DEFAULT_IDLE)
ml.run()
self.assertTrue(data['called'])
self.assertEqual(data['data2'], 'hello')
def test_timeout_data(self):
ml = GLib.MainLoop()
......@@ -231,6 +246,21 @@ class TestUserData(unittest.TestCase):
ml.run()
self.assertTrue(data['called'])
def test_timeout_multidata(self):
ml = GLib.MainLoop()
def cb(data, data2):
data['called'] = True
data['data2'] = data2
ml.quit()
data = {}
id = GLib.timeout_add(50, cb, data, 'hello')
self.assertEqual(ml.get_context().find_source_by_id(id).priority,
GLib.PRIORITY_DEFAULT)
ml.run()
self.assertTrue(data['called'])
self.assertEqual(data['data2'], 'hello')
def test_idle_no_data_priority(self):
ml = GLib.MainLoop()
......
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