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
27 from ..module import get_introspection_module
28 from .._gi import (variant_type_from_string, source_new,
29 source_set_callback, io_channel_read)
30 from ..overrides import override, deprecated, deprecated_attr
31 from gi import PyGIDeprecationWarning, version_info
33 GLib = get_introspection_module('GLib')
37 from gi import _option as option
39 __all__.append('option')
42 # Types and functions still needed from static bindings
44 from gi._error import GError
47 OptionContext = _gi.OptionContext
48 OptionGroup = _gi.OptionGroup
50 spawn_async = _gi.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.__gtype__ = GLib.Error.__gtype__
78 Error.matches = gerror_matches
79 Error.new_literal = staticmethod(gerror_new_literal)
82 __all__ += ['GError', 'Error', 'OptionContext', 'OptionGroup', 'Pid',
83 'spawn_async', 'threads_init']
86 class _VariantCreator(object):
88 _LEAF_CONSTRUCTORS = {
89 'b': GLib.Variant.new_boolean,
90 'y': GLib.Variant.new_byte,
91 'n': GLib.Variant.new_int16,
92 'q': GLib.Variant.new_uint16,
93 'i': GLib.Variant.new_int32,
94 'u': GLib.Variant.new_uint32,
95 'x': GLib.Variant.new_int64,
96 't': GLib.Variant.new_uint64,
97 'h': GLib.Variant.new_handle,
98 'd': GLib.Variant.new_double,
99 's': GLib.Variant.new_string,
100 'o': GLib.Variant.new_object_path,
101 'g': GLib.Variant.new_signature,
102 'v': GLib.Variant.new_variant,
105 def _create(self, format, args):
106 """Create a GVariant object from given format and argument list.
108 This method recursively calls itself for complex structures (arrays,
109 dictionaries, boxed).
111 Return a tuple (variant, rest_format, rest_args) with the generated
112 GVariant, the remainder of the format string, and the remainder of the
115 If args is None, then this won't actually consume any arguments, and
116 just parse the format string and generate empty GVariant structures.
117 This is required for creating empty dictionaries or arrays.
119 # leaves (simple types)
120 constructor = self._LEAF_CONSTRUCTORS.get(format[0])
124 raise TypeError('not enough arguments for GVariant format string')
125 v = constructor(args[0])
126 return (v, format[1:], args[1:])
128 return (None, format[1:], None)
131 return self._create_tuple(format, args)
133 if format.startswith('a{'):
134 return self._create_dict(format, args)
137 return self._create_array(format, args)
139 raise NotImplementedError('cannot handle GVariant type ' + format)
141 def _create_tuple(self, format, args):
142 """Handle the case where the outermost type of format is a tuple."""
144 format = format[1:] # eat the '('
146 # empty value: we need to call _create() to parse the subtype
149 if rest_format.startswith(')'):
151 rest_format = self._create(rest_format, None)[1]
153 raise TypeError('tuple type string not closed with )')
155 rest_format = rest_format[1:] # eat the )
156 return (None, rest_format, None)
158 if not args or not isinstance(args[0], tuple):
159 raise TypeError('expected tuple argument')
161 builder = GLib.VariantBuilder.new(variant_type_from_string('r'))
162 for i in range(len(args[0])):
163 if format.startswith(')'):
164 raise TypeError('too many arguments for tuple signature')
166 (v, format, _) = self._create(format, args[0][i:])
169 if not format.startswith(')'):
170 raise TypeError('tuple type string not closed with )')
172 rest_format = format[1:] # eat the )
173 return (builder.end(), rest_format, args)
175 def _create_dict(self, format, args):
176 """Handle the case where the outermost type of format is a dict."""
179 if args is None or not args[0]:
180 # empty value: we need to call _create() to parse the subtype,
181 # and specify the element type precisely
182 rest_format = self._create(format[2:], None)[1]
183 rest_format = self._create(rest_format, None)[1]
184 if not rest_format.startswith('}'):
185 raise TypeError('dictionary type string not closed with }')
186 rest_format = rest_format[1:] # eat the }
187 element_type = format[:len(format) - len(rest_format)]
188 builder = GLib.VariantBuilder.new(variant_type_from_string(element_type))
190 builder = GLib.VariantBuilder.new(variant_type_from_string('a{?*}'))
191 for k, v in args[0].items():
192 (key_v, rest_format, _) = self._create(format[2:], [k])
193 (val_v, rest_format, _) = self._create(rest_format, [v])
195 if not rest_format.startswith('}'):
196 raise TypeError('dictionary type string not closed with }')
197 rest_format = rest_format[1:] # eat the }
199 entry = GLib.VariantBuilder.new(variant_type_from_string('{?*}'))
200 entry.add_value(key_v)
201 entry.add_value(val_v)
202 builder.add_value(entry.end())
206 return (builder.end(), rest_format, args)
208 def _create_array(self, format, args):
209 """Handle the case where the outermost type of format is an array."""
212 if args is None or not args[0]:
213 # empty value: we need to call _create() to parse the subtype,
214 # and specify the element type precisely
215 rest_format = self._create(format[1:], None)[1]
216 element_type = format[:len(format) - len(rest_format)]
217 builder = GLib.VariantBuilder.new(variant_type_from_string(element_type))
219 builder = GLib.VariantBuilder.new(variant_type_from_string('a*'))
220 for i in range(len(args[0])):
221 (v, rest_format, _) = self._create(format[1:], args[0][i:])
225 return (builder.end(), rest_format, args)
228 class Variant(GLib.Variant):
229 def __new__(cls, format_string, value):
230 """Create a GVariant from a native Python object.
232 format_string is a standard GVariant type signature, value is a Python
233 object whose structure has to match the signature.
237 GLib.Variant('(is)', (1, 'hello'))
238 GLib.Variant('(asa{sv})', ([], {'foo': GLib.Variant('b', True),
239 'bar': GLib.Variant('i', 2)}))
241 creator = _VariantCreator()
242 (v, rest_format, _) = creator._create(format_string, [value])
244 raise TypeError('invalid remaining format string: "%s"' % rest_format)
245 v.format_string = format_string
249 def new_tuple(*elements):
250 return GLib.Variant.new_tuple(elements)
256 # Calling unref will cause gi and gi.repository.GLib to be
257 # imported. However, if the program is exiting, then these
258 # modules have likely been removed from sys.modules and will
259 # raise an exception. Assume that's the case for ImportError
260 # and ignore the exception since everything will be cleaned
265 return self.print_(True)
268 if hasattr(self, 'format_string'):
269 f = self.format_string
271 f = self.get_type_string()
272 return "GLib.Variant('%s', %s)" % (f, self.print_(False))
274 def __eq__(self, other):
276 return self.equal(other)
280 def __ne__(self, other):
282 return not self.equal(other)
287 # We're not using just hash(self.unpack()) because otherwise we'll have
288 # hash collisions between the same content in different variant types,
289 # which will cause a performance issue in set/dict/etc.
290 return hash((self.get_type_string(), self.unpack()))
293 """Decompose a GVariant into a native Python object."""
296 'b': self.get_boolean,
299 'q': self.get_uint16,
301 'u': self.get_uint32,
303 't': self.get_uint64,
304 'h': self.get_handle,
305 'd': self.get_double,
306 's': self.get_string,
307 'o': self.get_string, # object path
308 'g': self.get_string, # signature
312 la = LEAF_ACCESSORS.get(self.get_type_string())
317 if self.get_type_string().startswith('('):
318 res = [self.get_child_value(i).unpack()
319 for i in range(self.n_children())]
323 if self.get_type_string().startswith('a{'):
325 for i in range(self.n_children()):
326 v = self.get_child_value(i)
327 res[v.get_child_value(0).unpack()] = v.get_child_value(1).unpack()
331 if self.get_type_string().startswith('a'):
332 return [self.get_child_value(i).unpack()
333 for i in range(self.n_children())]
335 # variant (just unbox transparently)
336 if self.get_type_string().startswith('v'):
337 return self.get_variant().unpack()
340 if self.get_type_string().startswith('m'):
342 return m.unpack() if m else None
344 raise NotImplementedError('unsupported GVariant type ' + self.get_type_string())
347 def split_signature(klass, signature):
348 """Return a list of the element signatures of the topmost signature tuple.
350 If the signature is not a tuple, it returns one element with the entire
351 signature. If the signature is an empty tuple, the result is [].
353 This is useful for e. g. iterating over method parameters which are
354 passed as a single Variant.
356 if signature == '()':
359 if not signature.startswith('('):
364 tail = signature[1:-1] # eat the surrounding ()
371 # prefixes, keep collecting
374 # consume until corresponding )/}
390 # otherwise we have a simple type
401 if self.get_type_string() in ['s', 'o', 'g']:
402 return len(self.get_string())
404 if self.get_type_string().startswith('a') or self.get_type_string().startswith('('):
405 return self.n_children()
406 raise TypeError('GVariant type %s does not have a length' % self.get_type_string())
408 def __getitem__(self, key):
410 if self.get_type_string().startswith('a{'):
412 val = self.lookup_value(key, variant_type_from_string('*'))
417 # lookup_value() only works for string keys, which is certainly
418 # the common case; we have to do painful iteration for other
420 for i in range(self.n_children()):
421 v = self.get_child_value(i)
422 if v.get_child_value(0).unpack() == key:
423 return v.get_child_value(1).unpack()
427 if self.get_type_string().startswith('a') or self.get_type_string().startswith('('):
430 key = self.n_children() + key
431 if key < 0 or key >= self.n_children():
432 raise IndexError('list index out of range')
433 return self.get_child_value(key).unpack()
436 if self.get_type_string() in ['s', 'o', 'g']:
437 return self.get_string().__getitem__(key)
439 raise TypeError('GVariant type %s is not a container' % self.get_type_string())
442 # Pythonic bool operations
445 def __nonzero__(self):
446 return self.__bool__()
449 if self.get_type_string() in ['y', 'n', 'q', 'i', 'u', 'x', 't', 'h', 'd']:
450 return self.unpack() != 0
451 if self.get_type_string() in ['b']:
452 return self.get_boolean()
453 if self.get_type_string() in ['s', 'o', 'g']:
454 return len(self.get_string()) != 0
456 if self.get_type_string().startswith('a') or self.get_type_string().startswith('('):
457 return self.n_children() != 0
458 if self.get_type_string() in ['v']:
459 # unpack works recursively, hence bool also works recursively
460 return bool(self.unpack())
461 # Everything else is True
465 if not self.get_type_string().startswith('a{'):
466 return TypeError, 'GVariant type %s is not a dictionary' % self.get_type_string()
469 for i in range(self.n_children()):
470 v = self.get_child_value(i)
471 res.append(v.get_child_value(0).unpack())
475 def get_string(self):
476 value, length = GLib.Variant.get_string(self)
480 setattr(Variant, 'get_string', get_string)
482 __all__.append('Variant')
485 def markup_escape_text(text, length=-1):
486 if isinstance(text, bytes):
487 return GLib.markup_escape_text(text.decode('UTF-8'), length)
489 return GLib.markup_escape_text(text, length)
492 __all__.append('markup_escape_text')
495 # backwards compatible names from old static bindings
496 for n in ['DESKTOP', 'DOCUMENTS', 'DOWNLOAD', 'MUSIC', 'PICTURES',
497 'PUBLIC_SHARE', 'TEMPLATES', 'VIDEOS']:
498 attr = 'USER_DIRECTORY_' + n
499 deprecated_attr("GLib", attr, "GLib.UserDirectory.DIRECTORY_" + n)
500 globals()[attr] = getattr(GLib.UserDirectory, 'DIRECTORY_' + n)
503 for n in ['ERR', 'HUP', 'IN', 'NVAL', 'OUT', 'PRI']:
504 globals()['IO_' + n] = getattr(GLib.IOCondition, n)
505 __all__.append('IO_' + n)
507 for n in ['APPEND', 'GET_MASK', 'IS_READABLE', 'IS_SEEKABLE',
508 'MASK', 'NONBLOCK', 'SET_MASK']:
509 attr = 'IO_FLAG_' + n
510 deprecated_attr("GLib", attr, "GLib.IOFlags." + n)
511 globals()[attr] = getattr(GLib.IOFlags, n)
514 # spelling for the win
515 IO_FLAG_IS_WRITEABLE = GLib.IOFlags.IS_WRITABLE
516 deprecated_attr("GLib", "IO_FLAG_IS_WRITEABLE", "GLib.IOFlags.IS_WRITABLE")
517 __all__.append('IO_FLAG_IS_WRITEABLE')
519 for n in ['AGAIN', 'EOF', 'ERROR', 'NORMAL']:
520 attr = 'IO_STATUS_' + n
521 globals()[attr] = getattr(GLib.IOStatus, n)
522 deprecated_attr("GLib", attr, "GLib.IOStatus." + n)
525 for n in ['CHILD_INHERITS_STDIN', 'DO_NOT_REAP_CHILD', 'FILE_AND_ARGV_ZERO',
526 'LEAVE_DESCRIPTORS_OPEN', 'SEARCH_PATH', 'STDERR_TO_DEV_NULL',
527 'STDOUT_TO_DEV_NULL']:
529 globals()[attr] = getattr(GLib.SpawnFlags, n)
530 deprecated_attr("GLib", attr, "GLib.SpawnFlags." + n)
533 for n in ['HIDDEN', 'IN_MAIN', 'REVERSE', 'NO_ARG', 'FILENAME', 'OPTIONAL_ARG',
535 attr = 'OPTION_FLAG_' + n
536 globals()[attr] = getattr(GLib.OptionFlags, n)
537 deprecated_attr("GLib", attr, "GLib.OptionFlags." + n)
540 for n in ['UNKNOWN_OPTION', 'BAD_VALUE', 'FAILED']:
541 attr = 'OPTION_ERROR_' + n
542 deprecated_attr("GLib", attr, "GLib.OptionError." + n)
543 globals()[attr] = getattr(GLib.OptionError, n)
547 # these are not currently exported in GLib gir, presumably because they are
548 # platform dependent; so get them from our static bindings
549 for name in ['G_MINFLOAT', 'G_MAXFLOAT', 'G_MINDOUBLE', 'G_MAXDOUBLE',
550 'G_MINSHORT', 'G_MAXSHORT', 'G_MAXUSHORT', 'G_MININT', 'G_MAXINT',
551 'G_MAXUINT', 'G_MINLONG', 'G_MAXLONG', 'G_MAXULONG', 'G_MAXSIZE',
552 'G_MINSSIZE', 'G_MAXSSIZE', 'G_MINOFFSET', 'G_MAXOFFSET']:
553 attr = name.split("_", 1)[-1]
554 globals()[attr] = getattr(_gi, name)
558 class MainLoop(GLib.MainLoop):
559 # Backwards compatible constructor API
560 def __new__(cls, context=None):
561 return GLib.MainLoop.new(context, False)
563 # Retain classic pygobject behaviour of quitting main loops on SIGINT
564 def __init__(self, context=None):
567 loop._quit_by_sigint = True
568 # We handle signal deletion in __del__, return True so GLib
569 # doesn't do the deletion for us.
572 if sys.platform != 'win32':
573 # compatibility shim, keep around until we depend on glib 2.36
574 if hasattr(GLib, 'unix_signal_add'):
575 fn = GLib.unix_signal_add
577 fn = GLib.unix_signal_add_full
578 self._signal_source = fn(GLib.PRIORITY_DEFAULT, signal.SIGINT, _handler, self)
581 if hasattr(self, '_signal_source'):
582 GLib.source_remove(self._signal_source)
585 super(MainLoop, self).run()
586 if hasattr(self, '_quit_by_sigint'):
587 # caught by _main_loop_sigint_handler()
588 raise KeyboardInterrupt
591 MainLoop = override(MainLoop)
592 __all__.append('MainLoop')
595 class MainContext(GLib.MainContext):
596 # Backwards compatible API with default value
597 def iteration(self, may_block=True):
598 return super(MainContext, self).iteration(may_block)
601 MainContext = override(MainContext)
602 __all__.append('MainContext')
605 class Source(GLib.Source):
606 def __new__(cls, *args, **kwargs):
607 # use our custom pyg_source_new() here as g_source_new() is not
609 source = source_new()
610 source.__class__ = cls
611 setattr(source, '__pygi_custom_source', True)
614 def __init__(self, *args, **kwargs):
615 return super(Source, self).__init__()
617 def set_callback(self, fn, user_data=None):
618 if hasattr(self, '__pygi_custom_source'):
619 # use our custom pyg_source_set_callback() if for a GSource object
620 # with custom functions
621 source_set_callback(self, fn, user_data)
623 # otherwise, for Idle and Timeout, use the standard method
624 super(Source, self).set_callback(fn, user_data)
626 def get_current_time(self):
627 return GLib.get_real_time() * 0.000001
629 get_current_time = deprecated(get_current_time,
630 'GLib.Source.get_time() or GLib.get_real_time()')
632 # as get/set_priority are introspected, we can't use the static
633 # property(get_priority, ..) here
634 def __get_priority(self):
635 return self.get_priority()
637 def __set_priority(self, value):
638 self.set_priority(value)
640 priority = property(__get_priority, __set_priority)
642 def __get_can_recurse(self):
643 return self.get_can_recurse()
645 def __set_can_recurse(self, value):
646 self.set_can_recurse(value)
648 can_recurse = property(__get_can_recurse, __set_can_recurse)
651 Source = override(Source)
652 __all__.append('Source')
656 def __new__(cls, priority=GLib.PRIORITY_DEFAULT):
657 source = GLib.idle_source_new()
658 source.__class__ = cls
661 def __init__(self, priority=GLib.PRIORITY_DEFAULT):
662 super(Source, self).__init__()
663 if priority != GLib.PRIORITY_DEFAULT:
664 self.set_priority(priority)
667 __all__.append('Idle')
670 class Timeout(Source):
671 def __new__(cls, interval=0, priority=GLib.PRIORITY_DEFAULT):
672 source = GLib.timeout_source_new(interval)
673 source.__class__ = cls
676 def __init__(self, interval=0, priority=GLib.PRIORITY_DEFAULT):
677 if priority != GLib.PRIORITY_DEFAULT:
678 self.set_priority(priority)
681 __all__.append('Timeout')
684 # backwards compatible API
685 def idle_add(function, *user_data, **kwargs):
686 priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT_IDLE)
687 return GLib.idle_add(priority, function, *user_data)
690 __all__.append('idle_add')
693 def timeout_add(interval, function, *user_data, **kwargs):
694 priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT)
695 return GLib.timeout_add(priority, interval, function, *user_data)
698 __all__.append('timeout_add')
701 def timeout_add_seconds(interval, function, *user_data, **kwargs):
702 priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT)
703 return GLib.timeout_add_seconds(priority, interval, function, *user_data)
706 __all__.append('timeout_add_seconds')
709 # The GI GLib API uses g_io_add_watch_full renamed to g_io_add_watch with
710 # a signature of (channel, priority, condition, func, user_data).
711 # Prior to PyGObject 3.8, this function was statically bound with an API closer to the
712 # non-full version with a signature of: (fd, condition, func, *user_data)
713 # We need to support this until we are okay with breaking API in a way which is
714 # not backwards compatible.
716 # This needs to take into account several historical APIs:
717 # - calling with an fd as first argument
718 # - calling with a Python file object as first argument (we keep this one as
719 # it's really convenient and does not change the number of arguments)
720 # - calling without a priority as second argument
721 def _io_add_watch_get_args(channel, priority_, condition, *cb_and_user_data, **kwargs):
722 if not isinstance(priority_, int) or isinstance(priority_, GLib.IOCondition):
723 warnings.warn('Calling io_add_watch without priority as second argument is deprecated',
724 PyGIDeprecationWarning)
725 # shift the arguments around
726 user_data = cb_and_user_data
728 condition = priority_
729 if not callable(callback):
730 raise TypeError('third argument must be callable')
732 # backwards compatibility: Call with priority kwarg
733 if 'priority' in kwargs:
734 warnings.warn('Calling io_add_watch with priority keyword argument is deprecated, put it as second positional argument',
735 PyGIDeprecationWarning)
736 priority_ = kwargs['priority']
738 priority_ = GLib.PRIORITY_DEFAULT
740 if len(cb_and_user_data) < 1 or not callable(cb_and_user_data[0]):
741 raise TypeError('expecting callback as fourth argument')
742 callback = cb_and_user_data[0]
743 user_data = cb_and_user_data[1:]
745 # backwards compatibility: Allow calling with fd
746 if isinstance(channel, int):
747 func_fdtransform = lambda _, cond, *data: callback(channel, cond, *data)
748 real_channel = GLib.IOChannel.unix_new(channel)
749 elif isinstance(channel, socket.socket) and sys.platform == 'win32':
750 func_fdtransform = lambda _, cond, *data: callback(channel, cond, *data)
751 real_channel = GLib.IOChannel.win32_new_socket(channel.fileno())
752 elif hasattr(channel, 'fileno'):
753 # backwards compatibility: Allow calling with Python file
754 func_fdtransform = lambda _, cond, *data: callback(channel, cond, *data)
755 real_channel = GLib.IOChannel.unix_new(channel.fileno())
757 assert isinstance(channel, GLib.IOChannel)
758 func_fdtransform = callback
759 real_channel = channel
761 return real_channel, priority_, condition, func_fdtransform, user_data
764 __all__.append('_io_add_watch_get_args')
767 def io_add_watch(*args, **kwargs):
768 """io_add_watch(channel, priority, condition, func, *user_data) -> event_source_id"""
769 channel, priority, condition, func, user_data = _io_add_watch_get_args(*args, **kwargs)
770 return GLib.io_add_watch(channel, priority, condition, func, *user_data)
773 __all__.append('io_add_watch')
776 # backwards compatible API
777 class IOChannel(GLib.IOChannel):
778 def __new__(cls, filedes=None, filename=None, mode=None, hwnd=None):
779 if filedes is not None:
780 return GLib.IOChannel.unix_new(filedes)
781 if filename is not None:
782 return GLib.IOChannel.new_file(filename, mode or 'r')
784 return GLib.IOChannel.win32_new_fd(hwnd)
785 raise TypeError('either a valid file descriptor, file name, or window handle must be supplied')
787 def __init__(self, *args, **kwargs):
788 return super(IOChannel, self).__init__()
790 def read(self, max_count=-1):
791 return io_channel_read(self, max_count)
793 def readline(self, size_hint=-1):
794 # note, size_hint is just to maintain backwards compatible API; the
795 # old static binding did not actually use it
796 (status, buf, length, terminator_pos) = self.read_line()
801 def readlines(self, size_hint=-1):
802 # note, size_hint is just to maintain backwards compatible API;
803 # the old static binding did not actually use it
805 status = GLib.IOStatus.NORMAL
806 while status == GLib.IOStatus.NORMAL:
807 (status, buf, length, terminator_pos) = self.read_line()
808 # note, this appends an empty line after EOF; this is
809 # bug-compatible with the old static bindings
815 def write(self, buf, buflen=-1):
816 if not isinstance(buf, bytes):
817 buf = buf.encode('UTF-8')
820 (status, written) = self.write_chars(buf, buflen)
823 def writelines(self, lines):
827 _whence_map = {0: GLib.SeekType.SET, 1: GLib.SeekType.CUR, 2: GLib.SeekType.END}
829 def seek(self, offset, whence=0):
831 w = self._whence_map[whence]
833 raise ValueError("invalid 'whence' value")
834 return self.seek_position(offset, w)
836 def add_watch(self, condition, callback, *user_data, **kwargs):
837 priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT)
838 return io_add_watch(self, priority, condition, callback, *user_data)
840 add_watch = deprecated(add_watch, 'GLib.io_add_watch()')
846 (status, buf, length, terminator_pos) = self.read_line()
847 if status == GLib.IOStatus.NORMAL:
851 # Python 2.x compatibility
855 IOChannel = override(IOChannel)
856 __all__.append('IOChannel')
859 class PollFD(GLib.PollFD):
860 def __new__(cls, fd, events):
861 pollfd = GLib.PollFD()
862 pollfd.__class__ = cls
865 def __init__(self, fd, events):
870 PollFD = override(PollFD)
871 __all__.append('PollFD')
874 # The GI GLib API uses g_child_watch_add_full renamed to g_child_watch_add with
875 # a signature of (priority, pid, callback, data).
876 # Prior to PyGObject 3.8, this function was statically bound with an API closer to the
877 # non-full version with a signature of: (pid, callback, data=None, priority=GLib.PRIORITY_DEFAULT)
878 # We need to support this until we are okay with breaking API in a way which is
879 # not backwards compatible.
880 def _child_watch_add_get_args(priority_or_pid, pid_or_callback, *args, **kwargs):
883 if callable(pid_or_callback):
884 warnings.warn('Calling child_watch_add without priority as first argument is deprecated',
885 PyGIDeprecationWarning)
886 pid = priority_or_pid
887 callback = pid_or_callback
889 priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT)
892 priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT)
894 user_data = [args[0]]
897 raise TypeError('expected at most 4 positional arguments')
899 priority = priority_or_pid
900 pid = pid_or_callback
901 if 'function' in kwargs:
902 callback = kwargs['function']
904 elif len(args) > 0 and callable(args[0]):
908 raise TypeError('expected callback as third argument')
912 raise TypeError('got multiple values for "data" argument')
913 user_data = [kwargs['data']]
915 return priority, pid, callback, user_data
918 # we need this to be accessible for unit testing
919 __all__.append('_child_watch_add_get_args')
922 def child_watch_add(*args, **kwargs):
923 """child_watch_add(priority, pid, function, *data)"""
924 priority, pid, function, data = _child_watch_add_get_args(*args, **kwargs)
925 return GLib.child_watch_add(priority, pid, function, *data)
928 __all__.append('child_watch_add')
931 def get_current_time():
932 return GLib.get_real_time() * 0.000001
935 get_current_time = deprecated(get_current_time, 'GLib.get_real_time()')
937 __all__.append('get_current_time')
940 # backwards compatible API with default argument, and ignoring bytes_read
942 def filename_from_utf8(utf8string, len=-1):
943 return GLib.filename_from_utf8(utf8string, len)[0]
946 __all__.append('filename_from_utf8')
949 # backwards compatible API for renamed function
950 if not hasattr(GLib, 'unix_signal_add_full'):
951 def add_full_compat(*args):
952 warnings.warn('GLib.unix_signal_add_full() was renamed to GLib.unix_signal_add()',
953 PyGIDeprecationWarning)
954 return GLib.unix_signal_add(*args)
956 GLib.unix_signal_add_full = add_full_compat
959 # obsolete constants for backwards compatibility
960 glib_version = (GLib.MAJOR_VERSION, GLib.MINOR_VERSION, GLib.MICRO_VERSION)
961 __all__.append('glib_version')
962 deprecated_attr("GLib", "glib_version",
963 "(GLib.MAJOR_VERSION, GLib.MINOR_VERSION, GLib.MICRO_VERSION)")
965 pyglib_version = version_info
966 __all__.append('pyglib_version')
967 deprecated_attr("GLib", "pyglib_version", "gi.version_info")