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.__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 return self.print_(True)
259 if hasattr(self, 'format_string'):
260 f = self.format_string
262 f = self.get_type_string()
263 return "GLib.Variant('%s', %s)" % (f, self.print_(False))
265 def __eq__(self, other):
267 return self.equal(other)
271 def __ne__(self, other):
273 return not self.equal(other)
278 # We're not using just hash(self.unpack()) because otherwise we'll have
279 # hash collisions between the same content in different variant types,
280 # which will cause a performance issue in set/dict/etc.
281 return hash((self.get_type_string(), self.unpack()))
284 """Decompose a GVariant into a native Python object."""
287 'b': self.get_boolean,
290 'q': self.get_uint16,
292 'u': self.get_uint32,
294 't': self.get_uint64,
295 'h': self.get_handle,
296 'd': self.get_double,
297 's': self.get_string,
298 'o': self.get_string, # object path
299 'g': self.get_string, # signature
303 la = LEAF_ACCESSORS.get(self.get_type_string())
308 if self.get_type_string().startswith('('):
309 res = [self.get_child_value(i).unpack()
310 for i in range(self.n_children())]
314 if self.get_type_string().startswith('a{'):
316 for i in range(self.n_children()):
317 v = self.get_child_value(i)
318 res[v.get_child_value(0).unpack()] = v.get_child_value(1).unpack()
322 if self.get_type_string().startswith('a'):
323 return [self.get_child_value(i).unpack()
324 for i in range(self.n_children())]
326 # variant (just unbox transparently)
327 if self.get_type_string().startswith('v'):
328 return self.get_variant().unpack()
331 if self.get_type_string().startswith('m'):
333 return m.unpack() if m else None
335 raise NotImplementedError('unsupported GVariant type ' + self.get_type_string())
338 def split_signature(klass, signature):
339 """Return a list of the element signatures of the topmost signature tuple.
341 If the signature is not a tuple, it returns one element with the entire
342 signature. If the signature is an empty tuple, the result is [].
344 This is useful for e. g. iterating over method parameters which are
345 passed as a single Variant.
347 if signature == '()':
350 if not signature.startswith('('):
355 tail = signature[1:-1] # eat the surrounding ()
362 # prefixes, keep collecting
365 # consume until corresponding )/}
381 # otherwise we have a simple type
392 if self.get_type_string() in ['s', 'o', 'g']:
393 return len(self.get_string())
395 if self.get_type_string().startswith('a') or self.get_type_string().startswith('('):
396 return self.n_children()
397 raise TypeError('GVariant type %s does not have a length' % self.get_type_string())
399 def __getitem__(self, key):
401 if self.get_type_string().startswith('a{'):
403 val = self.lookup_value(key, variant_type_from_string('*'))
408 # lookup_value() only works for string keys, which is certainly
409 # the common case; we have to do painful iteration for other
411 for i in range(self.n_children()):
412 v = self.get_child_value(i)
413 if v.get_child_value(0).unpack() == key:
414 return v.get_child_value(1).unpack()
418 if self.get_type_string().startswith('a') or self.get_type_string().startswith('('):
421 key = self.n_children() + key
422 if key < 0 or key >= self.n_children():
423 raise IndexError('list index out of range')
424 return self.get_child_value(key).unpack()
427 if self.get_type_string() in ['s', 'o', 'g']:
428 return self.get_string().__getitem__(key)
430 raise TypeError('GVariant type %s is not a container' % self.get_type_string())
433 # Pythonic bool operations
436 def __nonzero__(self):
437 return self.__bool__()
440 if self.get_type_string() in ['y', 'n', 'q', 'i', 'u', 'x', 't', 'h', 'd']:
441 return self.unpack() != 0
442 if self.get_type_string() in ['b']:
443 return self.get_boolean()
444 if self.get_type_string() in ['s', 'o', 'g']:
445 return len(self.get_string()) != 0
447 if self.get_type_string().startswith('a') or self.get_type_string().startswith('('):
448 return self.n_children() != 0
449 if self.get_type_string() in ['v']:
450 # unpack works recursively, hence bool also works recursively
451 return bool(self.unpack())
452 # Everything else is True
456 if not self.get_type_string().startswith('a{'):
457 return TypeError, 'GVariant type %s is not a dictionary' % self.get_type_string()
460 for i in range(self.n_children()):
461 v = self.get_child_value(i)
462 res.append(v.get_child_value(0).unpack())
466 def get_string(self):
467 value, length = GLib.Variant.get_string(self)
470 setattr(Variant, 'get_string', get_string)
472 __all__.append('Variant')
475 def markup_escape_text(text, length=-1):
476 if isinstance(text, bytes):
477 return GLib.markup_escape_text(text.decode('UTF-8'), length)
479 return GLib.markup_escape_text(text, length)
480 __all__.append('markup_escape_text')
483 # backwards compatible names from old static bindings
484 for n in ['DESKTOP', 'DOCUMENTS', 'DOWNLOAD', 'MUSIC', 'PICTURES',
485 'PUBLIC_SHARE', 'TEMPLATES', 'VIDEOS']:
486 attr = 'USER_DIRECTORY_' + n
487 deprecated_attr("GLib", attr, "GLib.UserDirectory.DIRECTORY_" + n)
488 globals()[attr] = getattr(GLib.UserDirectory, 'DIRECTORY_' + n)
491 for n in ['ERR', 'HUP', 'IN', 'NVAL', 'OUT', 'PRI']:
492 globals()['IO_' + n] = getattr(GLib.IOCondition, n)
493 __all__.append('IO_' + n)
495 for n in ['APPEND', 'GET_MASK', 'IS_READABLE', 'IS_SEEKABLE',
496 'MASK', 'NONBLOCK', 'SET_MASK']:
497 attr = 'IO_FLAG_' + n
498 deprecated_attr("GLib", attr, "GLib.IOFlags." + n)
499 globals()[attr] = getattr(GLib.IOFlags, n)
502 # spelling for the win
503 IO_FLAG_IS_WRITEABLE = GLib.IOFlags.IS_WRITABLE
504 deprecated_attr("GLib", "IO_FLAG_IS_WRITEABLE", "GLib.IOFlags.IS_WRITABLE")
505 __all__.append('IO_FLAG_IS_WRITEABLE')
507 for n in ['AGAIN', 'EOF', 'ERROR', 'NORMAL']:
508 attr = 'IO_STATUS_' + n
509 globals()[attr] = getattr(GLib.IOStatus, n)
510 deprecated_attr("GLib", attr, "GLib.IOStatus." + n)
513 for n in ['CHILD_INHERITS_STDIN', 'DO_NOT_REAP_CHILD', 'FILE_AND_ARGV_ZERO',
514 'LEAVE_DESCRIPTORS_OPEN', 'SEARCH_PATH', 'STDERR_TO_DEV_NULL',
515 'STDOUT_TO_DEV_NULL']:
517 globals()[attr] = getattr(GLib.SpawnFlags, n)
518 deprecated_attr("GLib", attr, "GLib.SpawnFlags." + n)
521 for n in ['HIDDEN', 'IN_MAIN', 'REVERSE', 'NO_ARG', 'FILENAME', 'OPTIONAL_ARG',
523 attr = 'OPTION_FLAG_' + n
524 globals()[attr] = getattr(GLib.OptionFlags, n)
525 deprecated_attr("GLib", attr, "GLib.OptionFlags." + n)
528 for n in ['UNKNOWN_OPTION', 'BAD_VALUE', 'FAILED']:
529 attr = 'OPTION_ERROR_' + n
530 deprecated_attr("GLib", attr, "GLib.OptionError." + n)
531 globals()[attr] = getattr(GLib.OptionError, n)
535 # these are not currently exported in GLib gir, presumably because they are
536 # platform dependent; so get them from our static bindings
537 for name in ['G_MINFLOAT', 'G_MAXFLOAT', 'G_MINDOUBLE', 'G_MAXDOUBLE',
538 'G_MINSHORT', 'G_MAXSHORT', 'G_MAXUSHORT', 'G_MININT', 'G_MAXINT',
539 'G_MAXUINT', 'G_MINLONG', 'G_MAXLONG', 'G_MAXULONG', 'G_MAXSIZE',
540 'G_MINSSIZE', 'G_MAXSSIZE', 'G_MINOFFSET', 'G_MAXOFFSET']:
541 attr = name.split("_", 1)[-1]
542 globals()[attr] = getattr(_gobject, name)
546 class MainLoop(GLib.MainLoop):
547 # Backwards compatible constructor API
548 def __new__(cls, context=None):
549 return GLib.MainLoop.new(context, False)
551 # Retain classic pygobject behaviour of quitting main loops on SIGINT
552 def __init__(self, context=None):
555 loop._quit_by_sigint = True
556 # We handle signal deletion in __del__, return True so GLib
557 # doesn't do the deletion for us.
560 if sys.platform != 'win32':
561 # compatibility shim, keep around until we depend on glib 2.36
562 if hasattr(GLib, 'unix_signal_add'):
563 fn = GLib.unix_signal_add
565 fn = GLib.unix_signal_add_full
566 self._signal_source = fn(GLib.PRIORITY_DEFAULT, signal.SIGINT, _handler, self)
569 if hasattr(self, '_signal_source'):
570 GLib.source_remove(self._signal_source)
573 super(MainLoop, self).run()
574 if hasattr(self, '_quit_by_sigint'):
575 # caught by _main_loop_sigint_handler()
576 raise KeyboardInterrupt
578 MainLoop = override(MainLoop)
579 __all__.append('MainLoop')
582 class MainContext(GLib.MainContext):
583 # Backwards compatible API with default value
584 def iteration(self, may_block=True):
585 return super(MainContext, self).iteration(may_block)
587 MainContext = override(MainContext)
588 __all__.append('MainContext')
591 class Source(GLib.Source):
592 def __new__(cls, *args, **kwargs):
593 # use our custom pyg_source_new() here as g_source_new() is not
595 source = source_new()
596 source.__class__ = cls
597 setattr(source, '__pygi_custom_source', True)
600 def __init__(self, *args, **kwargs):
601 return super(Source, self).__init__()
603 def set_callback(self, fn, user_data=None):
604 if hasattr(self, '__pygi_custom_source'):
605 # use our custom pyg_source_set_callback() if for a GSource object
606 # with custom functions
607 source_set_callback(self, fn, user_data)
609 # otherwise, for Idle and Timeout, use the standard method
610 super(Source, self).set_callback(fn, user_data)
612 def get_current_time(self):
613 return GLib.get_real_time() * 0.000001
615 get_current_time = deprecated(get_current_time,
616 'GLib.Source.get_time() or GLib.get_real_time()')
618 # as get/set_priority are introspected, we can't use the static
619 # property(get_priority, ..) here
620 def __get_priority(self):
621 return self.get_priority()
623 def __set_priority(self, value):
624 self.set_priority(value)
626 priority = property(__get_priority, __set_priority)
628 def __get_can_recurse(self):
629 return self.get_can_recurse()
631 def __set_can_recurse(self, value):
632 self.set_can_recurse(value)
634 can_recurse = property(__get_can_recurse, __set_can_recurse)
636 Source = override(Source)
637 __all__.append('Source')
641 def __new__(cls, priority=GLib.PRIORITY_DEFAULT):
642 source = GLib.idle_source_new()
643 source.__class__ = cls
646 def __init__(self, priority=GLib.PRIORITY_DEFAULT):
647 super(Source, self).__init__()
648 if priority != GLib.PRIORITY_DEFAULT:
649 self.set_priority(priority)
651 __all__.append('Idle')
654 class Timeout(Source):
655 def __new__(cls, interval=0, priority=GLib.PRIORITY_DEFAULT):
656 source = GLib.timeout_source_new(interval)
657 source.__class__ = cls
660 def __init__(self, interval=0, priority=GLib.PRIORITY_DEFAULT):
661 if priority != GLib.PRIORITY_DEFAULT:
662 self.set_priority(priority)
664 __all__.append('Timeout')
667 # backwards compatible API
668 def idle_add(function, *user_data, **kwargs):
669 priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT_IDLE)
670 return GLib.idle_add(priority, function, *user_data)
672 __all__.append('idle_add')
675 def timeout_add(interval, function, *user_data, **kwargs):
676 priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT)
677 return GLib.timeout_add(priority, interval, function, *user_data)
679 __all__.append('timeout_add')
682 def timeout_add_seconds(interval, function, *user_data, **kwargs):
683 priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT)
684 return GLib.timeout_add_seconds(priority, interval, function, *user_data)
686 __all__.append('timeout_add_seconds')
689 # The GI GLib API uses g_io_add_watch_full renamed to g_io_add_watch with
690 # a signature of (channel, priority, condition, func, user_data).
691 # Prior to PyGObject 3.8, this function was statically bound with an API closer to the
692 # non-full version with a signature of: (fd, condition, func, *user_data)
693 # We need to support this until we are okay with breaking API in a way which is
694 # not backwards compatible.
696 # This needs to take into account several historical APIs:
697 # - calling with an fd as first argument
698 # - calling with a Python file object as first argument (we keep this one as
699 # it's really convenient and does not change the number of arguments)
700 # - calling without a priority as second argument
701 def _io_add_watch_get_args(channel, priority_, condition, *cb_and_user_data, **kwargs):
702 if not isinstance(priority_, int) or isinstance(priority_, GLib.IOCondition):
703 warnings.warn('Calling io_add_watch without priority as second argument is deprecated',
704 PyGIDeprecationWarning)
705 # shift the arguments around
706 user_data = cb_and_user_data
708 condition = priority_
709 if not callable(callback):
710 raise TypeError('third argument must be callable')
712 # backwards compatibility: Call with priority kwarg
713 if 'priority' in kwargs:
714 warnings.warn('Calling io_add_watch with priority keyword argument is deprecated, put it as second positional argument',
715 PyGIDeprecationWarning)
716 priority_ = kwargs['priority']
718 priority_ = GLib.PRIORITY_DEFAULT
720 if len(cb_and_user_data) < 1 or not callable(cb_and_user_data[0]):
721 raise TypeError('expecting callback as fourth argument')
722 callback = cb_and_user_data[0]
723 user_data = cb_and_user_data[1:]
725 # backwards compatibility: Allow calling with fd
726 if isinstance(channel, int):
727 func_fdtransform = lambda _, cond, *data: callback(channel, cond, *data)
728 real_channel = GLib.IOChannel.unix_new(channel)
729 elif hasattr(channel, 'fileno'):
730 # backwards compatibility: Allow calling with Python file
731 func_fdtransform = lambda _, cond, *data: callback(channel, cond, *data)
732 real_channel = GLib.IOChannel.unix_new(channel.fileno())
734 assert isinstance(channel, GLib.IOChannel)
735 func_fdtransform = callback
736 real_channel = channel
738 return real_channel, priority_, condition, func_fdtransform, user_data
740 __all__.append('_io_add_watch_get_args')
743 def io_add_watch(*args, **kwargs):
744 """io_add_watch(channel, priority, condition, func, *user_data) -> event_source_id"""
745 channel, priority, condition, func, user_data = _io_add_watch_get_args(*args, **kwargs)
746 return GLib.io_add_watch(channel, priority, condition, func, *user_data)
748 __all__.append('io_add_watch')
751 # backwards compatible API
752 class IOChannel(GLib.IOChannel):
753 def __new__(cls, filedes=None, filename=None, mode=None, hwnd=None):
754 if filedes is not None:
755 return GLib.IOChannel.unix_new(filedes)
756 if filename is not None:
757 return GLib.IOChannel.new_file(filename, mode or 'r')
759 return GLib.IOChannel.win32_new_fd(hwnd)
760 raise TypeError('either a valid file descriptor, file name, or window handle must be supplied')
762 def __init__(self, *args, **kwargs):
763 return super(IOChannel, self).__init__()
765 def read(self, max_count=-1):
766 return io_channel_read(self, max_count)
768 def readline(self, size_hint=-1):
769 # note, size_hint is just to maintain backwards compatible API; the
770 # old static binding did not actually use it
771 (status, buf, length, terminator_pos) = self.read_line()
776 def readlines(self, size_hint=-1):
777 # note, size_hint is just to maintain backwards compatible API;
778 # the old static binding did not actually use it
780 status = GLib.IOStatus.NORMAL
781 while status == GLib.IOStatus.NORMAL:
782 (status, buf, length, terminator_pos) = self.read_line()
783 # note, this appends an empty line after EOF; this is
784 # bug-compatible with the old static bindings
790 def write(self, buf, buflen=-1):
791 if not isinstance(buf, bytes):
792 buf = buf.encode('UTF-8')
795 (status, written) = self.write_chars(buf, buflen)
798 def writelines(self, lines):
802 _whence_map = {0: GLib.SeekType.SET, 1: GLib.SeekType.CUR, 2: GLib.SeekType.END}
804 def seek(self, offset, whence=0):
806 w = self._whence_map[whence]
808 raise ValueError("invalid 'whence' value")
809 return self.seek_position(offset, w)
811 def add_watch(self, condition, callback, *user_data, **kwargs):
812 priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT)
813 return io_add_watch(self, priority, condition, callback, *user_data)
815 add_watch = deprecated(add_watch, 'GLib.io_add_watch()')
821 (status, buf, length, terminator_pos) = self.read_line()
822 if status == GLib.IOStatus.NORMAL:
826 # Python 2.x compatibility
829 IOChannel = override(IOChannel)
830 __all__.append('IOChannel')
833 class PollFD(GLib.PollFD):
834 def __new__(cls, fd, events):
835 pollfd = GLib.PollFD()
836 pollfd.__class__ = cls
839 def __init__(self, fd, events):
843 PollFD = override(PollFD)
844 __all__.append('PollFD')
847 # The GI GLib API uses g_child_watch_add_full renamed to g_child_watch_add with
848 # a signature of (priority, pid, callback, data).
849 # Prior to PyGObject 3.8, this function was statically bound with an API closer to the
850 # non-full version with a signature of: (pid, callback, data=None, priority=GLib.PRIORITY_DEFAULT)
851 # We need to support this until we are okay with breaking API in a way which is
852 # not backwards compatible.
853 def _child_watch_add_get_args(priority_or_pid, pid_or_callback, *args, **kwargs):
856 if callable(pid_or_callback):
857 warnings.warn('Calling child_watch_add without priority as first argument is deprecated',
858 PyGIDeprecationWarning)
859 pid = priority_or_pid
860 callback = pid_or_callback
862 priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT)
865 priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT)
867 user_data = [args[0]]
870 raise TypeError('expected at most 4 positional arguments')
872 priority = priority_or_pid
873 pid = pid_or_callback
874 if 'function' in kwargs:
875 callback = kwargs['function']
877 elif len(args) > 0 and callable(args[0]):
881 raise TypeError('expected callback as third argument')
885 raise TypeError('got multiple values for "data" argument')
886 user_data = [kwargs['data']]
888 return priority, pid, callback, user_data
890 # we need this to be accessible for unit testing
891 __all__.append('_child_watch_add_get_args')
894 def child_watch_add(*args, **kwargs):
895 """child_watch_add(priority, pid, function, *data)"""
896 priority, pid, function, data = _child_watch_add_get_args(*args, **kwargs)
897 return GLib.child_watch_add(priority, pid, function, *data)
899 __all__.append('child_watch_add')
902 def get_current_time():
903 return GLib.get_real_time() * 0.000001
905 get_current_time = deprecated(get_current_time, 'GLib.get_real_time()')
907 __all__.append('get_current_time')
910 # backwards compatible API with default argument, and ignoring bytes_read
912 def filename_from_utf8(utf8string, len=-1):
913 return GLib.filename_from_utf8(utf8string, len)[0]
915 __all__.append('filename_from_utf8')
918 # backwards compatible API for renamed function
919 if not hasattr(GLib, 'unix_signal_add_full'):
920 def add_full_compat(*args):
921 warnings.warn('GLib.unix_signal_add_full() was renamed to GLib.unix_signal_add()',
922 PyGIDeprecationWarning)
923 return GLib.unix_signal_add(*args)
925 GLib.unix_signal_add_full = add_full_compat
928 # obsolete constants for backwards compatibility
929 glib_version = (GLib.MAJOR_VERSION, GLib.MINOR_VERSION, GLib.MICRO_VERSION)
930 __all__.append('glib_version')
931 deprecated_attr("GLib", "glib_version",
932 "(GLib.MAJOR_VERSION, GLib.MINOR_VERSION, GLib.MICRO_VERSION)")
934 pyglib_version = version_info
935 __all__.append('pyglib_version')
936 deprecated_attr("GLib", "pyglib_version", "gi.version_info")