[pygobject] Restore actual GLib API after previous fix



commit d7f095b01e7208273703c880f4f0dfcc1a152a9a
Author: Martin Pitt <martinpitt gnome org>
Date:   Sat Nov 3 09:33:08 2012 +0100

    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

 gi/overrides/GLib.py    |  117 ++++++++++++++++++++++++-----------------------
 tests/test_iochannel.py |   74 +++++++++++++++++++++++++++--
 tests/test_source.py    |   30 ++++++++++++
 3 files changed, 158 insertions(+), 63 deletions(-)
---
diff --git a/gi/overrides/GLib.py b/gi/overrides/GLib.py
index 3919f5f..a53c5e6 100644
--- a/gi/overrides/GLib.py
+++ b/gi/overrides/GLib.py
@@ -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()')
 
diff --git a/tests/test_iochannel.py b/tests/test_iochannel.py
index bc15229..f0fe273 100644
--- a/tests/test_iochannel.py
+++ b/tests/test_iochannel.py
@@ -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,
diff --git a/tests/test_source.py b/tests/test_source.py
index ba9ea37..dda492a 100644
--- a/tests/test_source.py
+++ b/tests/test_source.py
@@ -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()
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]