1 # -*- Mode: Python; py-indent-offset: 4 -*-
2 # vim: tabstop=4 shiftwidth=4 expandtab
4 # Copyright (C) 2010 Tomeu Vizoso <tomeu.vizoso@collabora.co.uk>
5 # Copyright (C) 2011, 2012 Canonical Ltd.
7 # This library is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU Lesser General Public
9 # License as published by the Free Software Foundation; either
10 # version 2.1 of the License, or (at your option) any later version.
12 # This library is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 # Lesser General Public License for more details.
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with this library; if not, write to the Free Software
19 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
26 from ..module import get_introspection_module
27 from .._gi import (variant_type_from_string, source_new,
28 source_set_callback, io_channel_read)
29 from ..overrides import override, deprecated, deprecated_attr
30 from gi import PyGIDeprecationWarning, version_info
32 GLib = get_introspection_module('GLib')
36 from gi import _option as option
38 __all__.append('option')
41 # Types and functions still needed from static bindings
42 from gi._gi import _glib
43 from gi._gi import _gobject
44 from gi._error import GError
47 OptionContext = _glib.OptionContext
48 OptionGroup = _glib.OptionGroup
50 spawn_async = _glib.spawn_async
54 warnings.warn('Since version 3.11, calling threads_init is no longer needed. '
55 'See: https://wiki.gnome.org/PyGObject/Threading',
56 PyGIDeprecationWarning, stacklevel=2)
59 def gerror_matches(self, domain, code):
60 # Handle cases where self.domain was set to an integer for compatibility
61 # with the introspected GLib.Error.
62 if isinstance(self.domain, str):
63 self_domain_quark = GLib.quark_from_string(self.domain)
65 self_domain_quark = self.domain
66 return (self_domain_quark, self.code) == (domain, code)
69 def gerror_new_literal(domain, message, code):
70 domain_quark = GLib.quark_to_string(domain)
71 return GError(message, domain_quark, code)
74 # Monkey patch methods that rely on GLib introspection to be loaded at runtime.
75 Error.__name__ = 'Error'
76 Error.__module__ = 'GLib'
77 Error.matches = gerror_matches
78 Error.new_literal = staticmethod(gerror_new_literal)
81 __all__ += ['GError', 'Error', 'OptionContext', 'OptionGroup', 'Pid',
82 'spawn_async', 'threads_init']
85 class _VariantCreator(object):
87 _LEAF_CONSTRUCTORS = {
88 'b': GLib.Variant.new_boolean,
89 'y': GLib.Variant.new_byte,
90 'n': GLib.Variant.new_int16,
91 'q': GLib.Variant.new_uint16,
92 'i': GLib.Variant.new_int32,
93 'u': GLib.Variant.new_uint32,
94 'x': GLib.Variant.new_int64,
95 't': GLib.Variant.new_uint64,
96 'h': GLib.Variant.new_handle,
97 'd': GLib.Variant.new_double,
98 's': GLib.Variant.new_string,
99 'o': GLib.Variant.new_object_path,
100 'g': GLib.Variant.new_signature,
101 'v': GLib.Variant.new_variant,
104 def _create(self, format, args):
105 """Create a GVariant object from given format and argument list.
107 This method recursively calls itself for complex structures (arrays,
108 dictionaries, boxed).
110 Return a tuple (variant, rest_format, rest_args) with the generated
111 GVariant, the remainder of the format string, and the remainder of the
114 If args is None, then this won't actually consume any arguments, and
115 just parse the format string and generate empty GVariant structures.
116 This is required for creating empty dictionaries or arrays.
118 # leaves (simple types)
119 constructor = self._LEAF_CONSTRUCTORS.get(format[0])
123 raise TypeError('not enough arguments for GVariant format string')
124 v = constructor(args[0])
125 return (v, format[1:], args[1:])
127 return (None, format[1:], None)
130 return self._create_tuple(format, args)
132 if format.startswith('a{'):
133 return self._create_dict(format, args)
136 return self._create_array(format, args)
138 raise NotImplementedError('cannot handle GVariant type ' + format)
140 def _create_tuple(self, format, args):
141 """Handle the case where the outermost type of format is a tuple."""
143 format = format[1:] # eat the '('
145 # empty value: we need to call _create() to parse the subtype
148 if rest_format.startswith(')'):
150 rest_format = self._create(rest_format, None)[1]
152 raise TypeError('tuple type string not closed with )')
154 rest_format = rest_format[1:] # eat the )
155 return (None, rest_format, None)
157 if not args or not isinstance(args[0], tuple):
158 raise TypeError('expected tuple argument')
160 builder = GLib.VariantBuilder.new(variant_type_from_string('r'))
161 for i in range(len(args[0])):
162 if format.startswith(')'):
163 raise TypeError('too many arguments for tuple signature')
165 (v, format, _) = self._create(format, args[0][i:])
168 if not format.startswith(')'):
169 raise TypeError('tuple type string not closed with )')
171 rest_format = format[1:] # eat the )
172 return (builder.end(), rest_format, args)
174 def _create_dict(self, format, args):
175 """Handle the case where the outermost type of format is a dict."""
178 if args is None or not args[0]:
179 # empty value: we need to call _create() to parse the subtype,
180 # and specify the element type precisely
181 rest_format = self._create(format[2:], None)[1]
182 rest_format = self._create(rest_format, None)[1]
183 if not rest_format.startswith('}'):
184 raise TypeError('dictionary type string not closed with }')
185 rest_format = rest_format[1:] # eat the }
186 element_type = format[:len(format) - len(rest_format)]
187 builder = GLib.VariantBuilder.new(variant_type_from_string(element_type))
189 builder = GLib.VariantBuilder.new(variant_type_from_string('a{?*}'))
190 for k, v in args[0].items():
191 (key_v, rest_format, _) = self._create(format[2:], [k])
192 (val_v, rest_format, _) = self._create(rest_format, [v])
194 if not rest_format.startswith('}'):
195 raise TypeError('dictionary type string not closed with }')
196 rest_format = rest_format[1:] # eat the }
198 entry = GLib.VariantBuilder.new(variant_type_from_string('{?*}'))
199 entry.add_value(key_v)
200 entry.add_value(val_v)
201 builder.add_value(entry.end())
205 return (builder.end(), rest_format, args)
207 def _create_array(self, format, args):
208 """Handle the case where the outermost type of format is an array."""
211 if args is None or not args[0]:
212 # empty value: we need to call _create() to parse the subtype,
213 # and specify the element type precisely
214 rest_format = self._create(format[1:], None)[1]
215 element_type = format[:len(format) - len(rest_format)]
216 builder = GLib.VariantBuilder.new(variant_type_from_string(element_type))
218 builder = GLib.VariantBuilder.new(variant_type_from_string('a*'))
219 for i in range(len(args[0])):
220 (v, rest_format, _) = self._create(format[1:], args[0][i:])
224 return (builder.end(), rest_format, args)
227 class Variant(GLib.Variant):
228 def __new__(cls, format_string, value):
229 """Create a GVariant from a native Python object.
231 format_string is a standard GVariant type signature, value is a Python
232 object whose structure has to match the signature.
236 GLib.Variant('(is)', (1, 'hello'))
237 GLib.Variant('(asa{sv})', ([], {'foo': GLib.Variant('b', True),
238 'bar': GLib.Variant('i', 2)}))
240 creator = _VariantCreator()
241 (v, rest_format, _) = creator._create(format_string, [value])
243 raise TypeError('invalid remaining format string: "%s"' % rest_format)
244 v.format_string = format_string
248 def new_tuple(*elements):
249 return GLib.Variant.new_tuple(elements)
255 return self.print_(True)
258 if hasattr(self, 'format_string'):
259 f = self.format_string
261 f = self.get_type_string()
262 return "GLib.Variant('%s', %s)" % (f, self.print_(False))
264 def __eq__(self, other):
266 return self.equal(other)
270 def __ne__(self, other):
272 return not self.equal(other)
277 # We're not using just hash(self.unpack()) because otherwise we'll have
278 # hash collisions between the same content in different variant types,
279 # which will cause a performance issue in set/dict/etc.
280 return hash((self.get_type_string(), self.unpack()))
283 """Decompose a GVariant into a native Python object."""
286 'b': self.get_boolean,
289 'q': self.get_uint16,
291 'u': self.get_uint32,
293 't': self.get_uint64,
294 'h': self.get_handle,
295 'd': self.get_double,
296 's': self.get_string,
297 'o': self.get_string, # object path
298 'g': self.get_string, # signature
302 la = LEAF_ACCESSORS.get(self.get_type_string())
307 if self.get_type_string().startswith('('):
308 res = [self.get_child_value(i).unpack()
309 for i in range(self.n_children())]
313 if self.get_type_string().startswith('a{'):
315 for i in range(self.n_children()):
316 v = self.get_child_value(i)
317 res[v.get_child_value(0).unpack()] = v.get_child_value(1).unpack()
321 if self.get_type_string().startswith('a'):
322 return [self.get_child_value(i).unpack()
323 for i in range(self.n_children())]
325 # variant (just unbox transparently)
326 if self.get_type_string().startswith('v'):
327 return self.get_variant().unpack()
330 if self.get_type_string().startswith('m'):
332 return m.unpack() if m else None
334 raise NotImplementedError('unsupported GVariant type ' + self.get_type_string())
337 def split_signature(klass, signature):
338 """Return a list of the element signatures of the topmost signature tuple.
340 If the signature is not a tuple, it returns one element with the entire
341 signature. If the signature is an empty tuple, the result is [].
343 This is useful for e. g. iterating over method parameters which are
344 passed as a single Variant.
346 if signature == '()':
349 if not signature.startswith('('):
354 tail = signature[1:-1] # eat the surrounding ()
361 # prefixes, keep collecting
364 # consume until corresponding )/}
380 # otherwise we have a simple type
391 if self.get_type_string() in ['s', 'o', 'g']:
392 return len(self.get_string())
394 if self.get_type_string().startswith('a') or self.get_type_string().startswith('('):
395 return self.n_children()
396 raise TypeError('GVariant type %s does not have a length' % self.get_type_string())
398 def __getitem__(self, key):
400 if self.get_type_string().startswith('a{'):
402 val = self.lookup_value(key, variant_type_from_string('*'))
407 # lookup_value() only works for string keys, which is certainly
408 # the common case; we have to do painful iteration for other
410 for i in range(self.n_children()):
411 v = self.get_child_value(i)
412 if v.get_child_value(0).unpack() == key:
413 return v.get_child_value(1).unpack()
417 if self.get_type_string().startswith('a') or self.get_type_string().startswith('('):
420 key = self.n_children() + key
421 if key < 0 or key >= self.n_children():
422 raise IndexError('list index out of range')
423 return self.get_child_value(key).unpack()
426 if self.get_type_string() in ['s', 'o', 'g']:
427 return self.get_string().__getitem__(key)
429 raise TypeError('GVariant type %s is not a container' % self.get_type_string())
432 # Pythonic bool operations
435 def __nonzero__(self):
436 return self.__bool__()
439 if self.get_type_string() in ['y', 'n', 'q', 'i', 'u', 'x', 't', 'h', 'd']:
440 return self.unpack() != 0
441 if self.get_type_string() in ['b']:
442 return self.get_boolean()
443 if self.get_type_string() in ['s', 'o', 'g']:
444 return len(self.get_string()) != 0
446 if self.get_type_string().startswith('a') or self.get_type_string().startswith('('):
447 return self.n_children() != 0
448 if self.get_type_string() in ['v']:
449 # unpack works recursively, hence bool also works recursively
450 return bool(self.unpack())
451 # Everything else is True
455 if not self.get_type_string().startswith('a{'):
456 return TypeError, 'GVariant type %s is not a dictionary' % self.get_type_string()
459 for i in range(self.n_children()):
460 v = self.get_child_value(i)
461 res.append(v.get_child_value(0).unpack())
465 def get_string(self):
466 value, length = GLib.Variant.get_string(self)
469 setattr(Variant, 'get_string', get_string)
471 __all__.append('Variant')
474 def markup_escape_text(text, length=-1):
475 if isinstance(text, bytes):
476 return GLib.markup_escape_text(text.decode('UTF-8'), length)
478 return GLib.markup_escape_text(text, length)
479 __all__.append('markup_escape_text')
482 # backwards compatible names from old static bindings
483 for n in ['DESKTOP', 'DOCUMENTS', 'DOWNLOAD', 'MUSIC', 'PICTURES',
484 'PUBLIC_SHARE', 'TEMPLATES', 'VIDEOS']:
485 attr = 'USER_DIRECTORY_' + n
486 deprecated_attr("GLib", attr, "GLib.UserDirectory.DIRECTORY_" + n)
487 globals()[attr] = getattr(GLib.UserDirectory, 'DIRECTORY_' + n)
490 for n in ['ERR', 'HUP', 'IN', 'NVAL', 'OUT', 'PRI']:
491 globals()['IO_' + n] = getattr(GLib.IOCondition, n)
492 __all__.append('IO_' + n)
494 for n in ['APPEND', 'GET_MASK', 'IS_READABLE', 'IS_SEEKABLE',
495 'MASK', 'NONBLOCK', 'SET_MASK']:
496 attr = 'IO_FLAG_' + n
497 deprecated_attr("GLib", attr, "GLib.IOFlags." + n)
498 globals()[attr] = getattr(GLib.IOFlags, n)
501 # spelling for the win
502 IO_FLAG_IS_WRITEABLE = GLib.IOFlags.IS_WRITABLE
503 deprecated_attr("GLib", "IO_FLAG_IS_WRITEABLE", "GLib.IOFlags.IS_WRITABLE")
504 __all__.append('IO_FLAG_IS_WRITEABLE')
506 for n in ['AGAIN', 'EOF', 'ERROR', 'NORMAL']:
507 attr = 'IO_STATUS_' + n
508 globals()[attr] = getattr(GLib.IOStatus, n)
509 deprecated_attr("GLib", attr, "GLib.IOStatus." + n)
512 for n in ['CHILD_INHERITS_STDIN', 'DO_NOT_REAP_CHILD', 'FILE_AND_ARGV_ZERO',
513 'LEAVE_DESCRIPTORS_OPEN', 'SEARCH_PATH', 'STDERR_TO_DEV_NULL',
514 'STDOUT_TO_DEV_NULL']:
516 globals()[attr] = getattr(GLib.SpawnFlags, n)
517 deprecated_attr("GLib", attr, "GLib.SpawnFlags." + n)
520 for n in ['HIDDEN', 'IN_MAIN', 'REVERSE', 'NO_ARG', 'FILENAME', 'OPTIONAL_ARG',
522 attr = 'OPTION_FLAG_' + n
523 globals()[attr] = getattr(GLib.OptionFlags, n)
524 deprecated_attr("GLib", attr, "GLib.OptionFlags." + n)
527 for n in ['UNKNOWN_OPTION', 'BAD_VALUE', 'FAILED']:
528 attr = 'OPTION_ERROR_' + n
529 deprecated_attr("GLib", attr, "GLib.OptionError." + n)
530 globals()[attr] = getattr(GLib.OptionError, n)
534 # these are not currently exported in GLib gir, presumably because they are
535 # platform dependent; so get them from our static bindings
536 for name in ['G_MINFLOAT', 'G_MAXFLOAT', 'G_MINDOUBLE', 'G_MAXDOUBLE',
537 'G_MINSHORT', 'G_MAXSHORT', 'G_MAXUSHORT', 'G_MININT', 'G_MAXINT',
538 'G_MAXUINT', 'G_MINLONG', 'G_MAXLONG', 'G_MAXULONG', 'G_MAXSIZE',
539 'G_MINSSIZE', 'G_MAXSSIZE', 'G_MINOFFSET', 'G_MAXOFFSET']:
540 attr = name.split("_", 1)[-1]
541 globals()[attr] = getattr(_gobject, name)
545 class MainLoop(GLib.MainLoop):
546 # Backwards compatible constructor API
547 def __new__(cls, context=None):
548 return GLib.MainLoop.new(context, False)
550 # Retain classic pygobject behaviour of quitting main loops on SIGINT
551 def __init__(self, context=None):
554 loop._quit_by_sigint = True
555 # We handle signal deletion in __del__, return True so GLib
556 # doesn't do the deletion for us.
559 if sys.platform != 'win32':
560 # compatibility shim, keep around until we depend on glib 2.36
561 if hasattr(GLib, 'unix_signal_add'):
562 fn = GLib.unix_signal_add
564 fn = GLib.unix_signal_add_full
565 self._signal_source = fn(GLib.PRIORITY_DEFAULT, signal.SIGINT, _handler, self)
568 if hasattr(self, '_signal_source'):
569 GLib.source_remove(self._signal_source)
572 super(MainLoop, self).run()
573 if hasattr(self, '_quit_by_sigint'):
574 # caught by _main_loop_sigint_handler()
575 raise KeyboardInterrupt
577 MainLoop = override(MainLoop)
578 __all__.append('MainLoop')
581 class MainContext(GLib.MainContext):
582 # Backwards compatible API with default value
583 def iteration(self, may_block=True):
584 return super(MainContext, self).iteration(may_block)
586 MainContext = override(MainContext)
587 __all__.append('MainContext')
590 class Source(GLib.Source):
591 def __new__(cls, *args, **kwargs):
592 # use our custom pyg_source_new() here as g_source_new() is not
594 source = source_new()
595 source.__class__ = cls
596 setattr(source, '__pygi_custom_source', True)
599 def __init__(self, *args, **kwargs):
600 return super(Source, self).__init__()
602 def set_callback(self, fn, user_data=None):
603 if hasattr(self, '__pygi_custom_source'):
604 # use our custom pyg_source_set_callback() if for a GSource object
605 # with custom functions
606 source_set_callback(self, fn, user_data)
608 # otherwise, for Idle and Timeout, use the standard method
609 super(Source, self).set_callback(fn, user_data)
611 def get_current_time(self):
612 return GLib.get_real_time() * 0.000001
614 get_current_time = deprecated(get_current_time,
615 'GLib.Source.get_time() or GLib.get_real_time()')
617 # as get/set_priority are introspected, we can't use the static
618 # property(get_priority, ..) here
619 def __get_priority(self):
620 return self.get_priority()
622 def __set_priority(self, value):
623 self.set_priority(value)
625 priority = property(__get_priority, __set_priority)
627 def __get_can_recurse(self):
628 return self.get_can_recurse()
630 def __set_can_recurse(self, value):
631 self.set_can_recurse(value)
633 can_recurse = property(__get_can_recurse, __set_can_recurse)
635 Source = override(Source)
636 __all__.append('Source')
640 def __new__(cls, priority=GLib.PRIORITY_DEFAULT):
641 source = GLib.idle_source_new()
642 source.__class__ = cls
645 def __init__(self, priority=GLib.PRIORITY_DEFAULT):
646 super(Source, self).__init__()
647 if priority != GLib.PRIORITY_DEFAULT:
648 self.set_priority(priority)
650 __all__.append('Idle')
653 class Timeout(Source):
654 def __new__(cls, interval=0, priority=GLib.PRIORITY_DEFAULT):
655 source = GLib.timeout_source_new(interval)
656 source.__class__ = cls
659 def __init__(self, interval=0, priority=GLib.PRIORITY_DEFAULT):
660 if priority != GLib.PRIORITY_DEFAULT:
661 self.set_priority(priority)
663 __all__.append('Timeout')
666 # backwards compatible API
667 def idle_add(function, *user_data, **kwargs):
668 priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT_IDLE)
669 return GLib.idle_add(priority, function, *user_data)
671 __all__.append('idle_add')
674 def timeout_add(interval, function, *user_data, **kwargs):
675 priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT)
676 return GLib.timeout_add(priority, interval, function, *user_data)
678 __all__.append('timeout_add')
681 def timeout_add_seconds(interval, function, *user_data, **kwargs):
682 priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT)
683 return GLib.timeout_add_seconds(priority, interval, function, *user_data)
685 __all__.append('timeout_add_seconds')
688 # The GI GLib API uses g_io_add_watch_full renamed to g_io_add_watch with
689 # a signature of (channel, priority, condition, func, user_data).
690 # Prior to PyGObject 3.8, this function was statically bound with an API closer to the
691 # non-full version with a signature of: (fd, condition, func, *user_data)
692 # We need to support this until we are okay with breaking API in a way which is
693 # not backwards compatible.
695 # This needs to take into account several historical APIs:
696 # - calling with an fd as first argument
697 # - calling with a Python file object as first argument (we keep this one as
698 # it's really convenient and does not change the number of arguments)
699 # - calling without a priority as second argument
700 def _io_add_watch_get_args(channel, priority_, condition, *cb_and_user_data, **kwargs):
701 if not isinstance(priority_, int) or isinstance(priority_, GLib.IOCondition):
702 warnings.warn('Calling io_add_watch without priority as second argument is deprecated',
703 PyGIDeprecationWarning)
704 # shift the arguments around
705 user_data = cb_and_user_data
707 condition = priority_
708 if not callable(callback):
709 raise TypeError('third argument must be callable')
711 # backwards compatibility: Call with priority kwarg
712 if 'priority' in kwargs:
713 warnings.warn('Calling io_add_watch with priority keyword argument is deprecated, put it as second positional argument',
714 PyGIDeprecationWarning)
715 priority_ = kwargs['priority']
717 priority_ = GLib.PRIORITY_DEFAULT
719 if len(cb_and_user_data) < 1 or not callable(cb_and_user_data[0]):
720 raise TypeError('expecting callback as fourth argument')
721 callback = cb_and_user_data[0]
722 user_data = cb_and_user_data[1:]
724 # backwards compatibility: Allow calling with fd
725 if isinstance(channel, int):
726 func_fdtransform = lambda _, cond, *data: callback(channel, cond, *data)
727 real_channel = GLib.IOChannel.unix_new(channel)
728 elif hasattr(channel, 'fileno'):
729 # backwards compatibility: Allow calling with Python file
730 func_fdtransform = lambda _, cond, *data: callback(channel, cond, *data)
731 real_channel = GLib.IOChannel.unix_new(channel.fileno())
733 assert isinstance(channel, GLib.IOChannel)
734 func_fdtransform = callback
735 real_channel = channel
737 return real_channel, priority_, condition, func_fdtransform, user_data
739 __all__.append('_io_add_watch_get_args')
742 def io_add_watch(*args, **kwargs):
743 """io_add_watch(channel, priority, condition, func, *user_data) -> event_source_id"""
744 channel, priority, condition, func, user_data = _io_add_watch_get_args(*args, **kwargs)
745 return GLib.io_add_watch(channel, priority, condition, func, *user_data)
747 __all__.append('io_add_watch')
750 # backwards compatible API
751 class IOChannel(GLib.IOChannel):
752 def __new__(cls, filedes=None, filename=None, mode=None, hwnd=None):
753 if filedes is not None:
754 return GLib.IOChannel.unix_new(filedes)
755 if filename is not None:
756 return GLib.IOChannel.new_file(filename, mode or 'r')
758 return GLib.IOChannel.win32_new_fd(hwnd)
759 raise TypeError('either a valid file descriptor, file name, or window handle must be supplied')
761 def __init__(self, *args, **kwargs):
762 return super(IOChannel, self).__init__()
764 def read(self, max_count=-1):
765 return io_channel_read(self, max_count)
767 def readline(self, size_hint=-1):
768 # note, size_hint is just to maintain backwards compatible API; the
769 # old static binding did not actually use it
770 (status, buf, length, terminator_pos) = self.read_line()
775 def readlines(self, size_hint=-1):
776 # note, size_hint is just to maintain backwards compatible API;
777 # the old static binding did not actually use it
779 status = GLib.IOStatus.NORMAL
780 while status == GLib.IOStatus.NORMAL:
781 (status, buf, length, terminator_pos) = self.read_line()
782 # note, this appends an empty line after EOF; this is
783 # bug-compatible with the old static bindings
789 def write(self, buf, buflen=-1):
790 if not isinstance(buf, bytes):
791 buf = buf.encode('UTF-8')
794 (status, written) = self.write_chars(buf, buflen)
797 def writelines(self, lines):
801 _whence_map = {0: GLib.SeekType.SET, 1: GLib.SeekType.CUR, 2: GLib.SeekType.END}
803 def seek(self, offset, whence=0):
805 w = self._whence_map[whence]
807 raise ValueError("invalid 'whence' value")
808 return self.seek_position(offset, w)
810 def add_watch(self, condition, callback, *user_data, **kwargs):
811 priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT)
812 return io_add_watch(self, priority, condition, callback, *user_data)
814 add_watch = deprecated(add_watch, 'GLib.io_add_watch()')
820 (status, buf, length, terminator_pos) = self.read_line()
821 if status == GLib.IOStatus.NORMAL:
825 # Python 2.x compatibility
828 IOChannel = override(IOChannel)
829 __all__.append('IOChannel')
832 class PollFD(GLib.PollFD):
833 def __new__(cls, fd, events):
834 pollfd = GLib.PollFD()
835 pollfd.__class__ = cls
838 def __init__(self, fd, events):
842 PollFD = override(PollFD)
843 __all__.append('PollFD')
846 # The GI GLib API uses g_child_watch_add_full renamed to g_child_watch_add with
847 # a signature of (priority, pid, callback, data).
848 # Prior to PyGObject 3.8, this function was statically bound with an API closer to the
849 # non-full version with a signature of: (pid, callback, data=None, priority=GLib.PRIORITY_DEFAULT)
850 # We need to support this until we are okay with breaking API in a way which is
851 # not backwards compatible.
852 def _child_watch_add_get_args(priority_or_pid, pid_or_callback, *args, **kwargs):
855 if callable(pid_or_callback):
856 warnings.warn('Calling child_watch_add without priority as first argument is deprecated',
857 PyGIDeprecationWarning)
858 pid = priority_or_pid
859 callback = pid_or_callback
861 priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT)
864 priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT)
866 user_data = [args[0]]
869 raise TypeError('expected at most 4 positional arguments')
871 priority = priority_or_pid
872 pid = pid_or_callback
873 if 'function' in kwargs:
874 callback = kwargs['function']
876 elif len(args) > 0 and callable(args[0]):
880 raise TypeError('expected callback as third argument')
884 raise TypeError('got multiple values for "data" argument')
885 user_data = [kwargs['data']]
887 return priority, pid, callback, user_data
889 # we need this to be accessible for unit testing
890 __all__.append('_child_watch_add_get_args')
893 def child_watch_add(*args, **kwargs):
894 """child_watch_add(priority, pid, function, *data)"""
895 priority, pid, function, data = _child_watch_add_get_args(*args, **kwargs)
896 return GLib.child_watch_add(priority, pid, function, *data)
898 __all__.append('child_watch_add')
901 def get_current_time():
902 return GLib.get_real_time() * 0.000001
904 get_current_time = deprecated(get_current_time, 'GLib.get_real_time()')
906 __all__.append('get_current_time')
909 # backwards compatible API with default argument, and ignoring bytes_read
911 def filename_from_utf8(utf8string, len=-1):
912 return GLib.filename_from_utf8(utf8string, len)[0]
914 __all__.append('filename_from_utf8')
917 # backwards compatible API for renamed function
918 if not hasattr(GLib, 'unix_signal_add_full'):
919 def add_full_compat(*args):
920 warnings.warn('GLib.unix_signal_add_full() was renamed to GLib.unix_signal_add()',
921 PyGIDeprecationWarning)
922 return GLib.unix_signal_add(*args)
924 GLib.unix_signal_add_full = add_full_compat
927 # obsolete constants for backwards compatibility
928 glib_version = (GLib.MAJOR_VERSION, GLib.MINOR_VERSION, GLib.MICRO_VERSION)
929 __all__.append('glib_version')
930 deprecated_attr("GLib", "glib_version",
931 "(GLib.MAJOR_VERSION, GLib.MINOR_VERSION, GLib.MICRO_VERSION)")
933 pyglib_version = version_info
934 __all__.append('pyglib_version')
935 deprecated_attr("GLib", "pyglib_version", "gi.version_info")