-image: registry.gitlab.gnome.org/gnome/pygobject/main:v8
+image: registry.gitlab.gnome.org/gnome/pygobject/main:v9
stages:
- build_and_test
paths:
- coverage/
variables:
- PYENV_VERSION: "3.6.6"
+ PYENV_VERSION: "3.6.7"
script:
- bash -x ./.gitlab-ci/coverage-docker.sh
python3.6:
variables:
- PYENV_VERSION: "3.6.6"
+ PYENV_VERSION: "3.6.7"
<<: *defaults
python3.7:
variables:
- PYENV_VERSION: "3.7.0-debug"
+ PYENV_VERSION: "3.7.1-debug"
<<: *defaults
pypy2:
xenial-i386-py2:
stage: build_and_test
image: registry.gitlab.gnome.org/gnome/pygobject/old:v2
+ artifacts:
+ paths:
+ - coverage/
script:
- bash -x ./.gitlab-ci/test-docker-old.sh
gtk4:
stage: build_and_test
- image: registry.gitlab.gnome.org/gnome/pygobject/gtk4:v1
+ image: registry.gitlab.gnome.org/gnome/pygobject/gtk4:v2
+ artifacts:
+ paths:
+ - coverage/
script:
- bash -x ./.gitlab-ci/test-docker-gtk4.sh
-FROM ubuntu:bionic
+FROM ubuntu:cosmic
RUN apt-get update && apt-get install -y \
build-essential \
RUN pyenv install --debug 2.7.15
RUN pyenv install 3.5.6
-RUN pyenv install 3.6.6
-RUN pyenv install --debug 3.7.0
+RUN pyenv install 3.6.7
+RUN pyenv install --debug 3.7.1
RUN pyenv install pypy2.7-6.0.0
RUN pyenv install pypy3.5-6.0.0
-FROM registry.gitlab.gnome.org/gnome/pygobject/main:v8
+FROM registry.gitlab.gnome.org/gnome/pygobject/main:v9
USER root
wayland-protocols \
&& rm -rf /var/lib/apt/lists/*
-RUN git clone https://gitlab.freedesktop.org/wayland/wayland.git \
- && cd wayland \
- && git checkout 1.16.0 \
- && ./autogen.sh --disable-documentation \
- && make -j8 && make install \
- && cd .. \
- && rm -Rf wayland
-
RUN git clone https://gitlab.gnome.org/GNOME/gtk.git \
&& cd gtk \
&& git checkout 833442e1e29e5 \
&& rm -Rf gtk
USER user
-ENV PYENV_VERSION 3.7.0-debug
+ENV PYENV_VERSION 3.7.1-debug
set -e
-TAG="registry.gitlab.gnome.org/gnome/pygobject/gtk4:v1"
+TAG="registry.gitlab.gnome.org/gnome/pygobject/gtk4:v2"
sudo docker build --tag "${TAG}" --file "Dockerfile.gtk4" .
sudo docker run --rm --security-opt label=disable \
set -e
-TAG="registry.gitlab.gnome.org/gnome/pygobject/main:v8"
+TAG="registry.gitlab.gnome.org/gnome/pygobject/main:v9"
sudo docker build --build-arg HOST_USER_ID="$UID" --tag "${TAG}" \
--file "Dockerfile" .
-sudo docker run -e PYENV_VERSION='3.7.0-debug' --rm --security-opt label=disable \
+sudo docker run -e PYENV_VERSION='3.7.1-debug' --rm --security-opt label=disable \
--volume "$(pwd)/..:/home/user/app" --workdir "/home/user/app" \
--tty --interactive "${TAG}" bash
set -e
# ccache setup
-mkdir -p _ccache
export CCACHE_BASEDIR="$(pwd)"
export CCACHE_DIR="${CCACHE_BASEDIR}/_ccache"
+COV_DIR="$(pwd)/coverage"
+export COVERAGE_FILE="${COV_DIR}/.coverage.${CI_JOB_NAME}"
+mkdir -p "${COV_DIR}"
+mkdir -p "${CCACHE_DIR}"
# test
python -m pip install git+https://github.com/pygobject/pycairo.git
-python -m pip install pytest pytest-faulthandler
+python -m pip install pytest pytest-faulthandler coverage
g-ir-inspect Gtk --version=4.0 --print-typelibs
export TEST_GTK_VERSION=4.0
-xvfb-run -a python setup.py test
+python setup.py build_tests
+xvfb-run -a python -m coverage run tests/runtests.py
source _venv/bin/activate
# ccache setup
-mkdir -p _ccache
export CCACHE_BASEDIR="$(pwd)"
export CCACHE_DIR="${CCACHE_BASEDIR}/_ccache"
+COV_DIR="$(pwd)/coverage"
+export COVERAGE_FILE="${COV_DIR}/.coverage.${CI_JOB_NAME}"
+mkdir -p "${COV_DIR}"
+mkdir -p "${CCACHE_DIR}"
# test
python -m pip install git+https://github.com/pygobject/pycairo.git
-python -m pip install pytest pytest-faulthandler
-xvfb-run -a python setup.py test
+python -m pip install pytest pytest-faulthandler coverage
+python setup.py build_tests
+xvfb-run -a python -m coverage run tests/runtests.py
set -e
-python3 -m pip install --user pytest
-python3 setup.py test
+python3 -m pip install --user pytest pytest-faulthandler
+python3 setup.py test -s
+3.31.2 - 2018-12-15
+-------------------
+
+* Changes included in 3.30.4
+* GLib.Variant.keys: correctly raise TypeError for non-dict types
+* GLib.Variant: implement __bool__ for maybe types
+* cairo: Fix GValue converters in case of NULL
+* setup.py: Print an install command hint when pkg-config is missing
+* pygi-info: wrap g_union_info_get_alignment()
+ :mr:`105` (:user:`Tomasz Miąsko <tmiasko>`)
+
+
+3.30.4 - 2018-11-30
+-------------------
+
+* gtk overrides: Fix rows getting inserted on the wrong level with
+ TreeStore.insert_before/insert_after if parent=None.
+ :issue:`281` (3.30 regression, thanks to :user:`Cian Wilson <cianwilson>`
+ for the report)
+
+
+3.30.3 - 2018-11-27
+-------------------
+
+* GValue: fall back to the custom C marshaller to support fundamental types.
+ This makes GValue work with GstFraction. :issue:`280`
+* GValue: Work around wrong annotations for GVariant
+* Fix GObject attribute access during instance init which can lead to errors
+ with __getattr__ implementations of subclasses. This lead to criticals when
+ instantiating Gio.DBusProxy. :issue:`267`
+
+
3.31.1 - 2018-11-17
-------------------
Platform: POSIX, Windows
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)
+Classifier: License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+)
Classifier: Operating System :: POSIX
Classifier: Operating System :: Microsoft :: Windows
Classifier: Programming Language :: C
}
/* XXX: used for Gtk.Template */
- if (PyObject_HasAttrString (wrapper, "__dontuse_ginstance_init__")) {
+ if (PyObject_HasAttrString ((PyObject*) Py_TYPE (wrapper), "__dontuse_ginstance_init__")) {
result = PyObject_CallMethod (wrapper, "__dontuse_ginstance_init__", NULL);
if (result == NULL)
PyErr_Print ();
GIFieldInfo **field_info_ret)
{
GType ancestor_g_type = 0;
- int length, i;
GIBaseInfo *ancestor_info;
GIStructInfo *struct_info;
gpointer implementor_class = NULL;
gboolean is_interface = FALSE;
+ GIFieldInfo *field_info;
ancestor_info = g_base_info_get_container (vfunc_info);
is_interface = g_base_info_get_type (ancestor_info) == GI_INFO_TYPE_INTERFACE;
*implementor_class_ret = implementor_class;
- length = g_struct_info_get_n_fields (struct_info);
- for (i = 0; i < length; i++) {
- GIFieldInfo *field_info;
+ field_info = g_struct_info_find_field (struct_info,
+ g_base_info_get_name ( (GIBaseInfo*) vfunc_info));
+ if (field_info != NULL) {
GITypeInfo *type_info;
- field_info = g_struct_info_get_field (struct_info, i);
-
- if (strcmp (g_base_info_get_name ( (GIBaseInfo*) field_info),
- g_base_info_get_name ( (GIBaseInfo*) vfunc_info)) != 0) {
- g_base_info_unref (field_info);
- continue;
- }
-
type_info = g_field_info_get_type (field_info);
if (g_type_info_get_tag (type_info) == GI_TYPE_TAG_INTERFACE) {
- g_base_info_unref (type_info);
*field_info_ret = field_info;
- break;
+ } else {
+ g_base_info_unref (field_info);
}
-
g_base_info_unref (type_info);
- g_base_info_unref (field_info);
}
g_base_info_unref (struct_info);
# Array, dict, tuple
if self.get_type_string().startswith('a') or self.get_type_string().startswith('('):
return self.n_children() != 0
- if self.get_type_string() in ['v']:
- # unpack works recursively, hence bool also works recursively
- return bool(self.unpack())
- # Everything else is True
- return True
+ # unpack works recursively, hence bool also works recursively
+ return bool(self.unpack())
def keys(self):
if not self.get_type_string().startswith('a{'):
- return TypeError, 'GVariant type %s is not a dictionary' % self.get_type_string()
+ raise TypeError('GVariant type %s is not a dictionary' % self.get_type_string())
res = []
for i in range(self.n_children()):
if 'data' in kwargs:
if user_data:
raise TypeError('got multiple values for "data" argument')
- user_data = [kwargs['data']]
+ user_data = (kwargs['data'],)
return priority, pid, callback, user_data
__all__.append('filename_from_utf8')
-# backwards compatible API for renamed function
-if not hasattr(GLib, 'unix_signal_add_full'):
- def add_full_compat(*args):
- warnings.warn('GLib.unix_signal_add_full() was renamed to GLib.unix_signal_add()',
- PyGIDeprecationWarning)
- return GLib.unix_signal_add(*args)
-
- GLib.unix_signal_add_full = add_full_compat
+if hasattr(GLib, "unix_signal_add"):
+ unix_signal_add_full = GLib.unix_signal_add
+ __all__.append('unix_signal_add_full')
+ deprecated_attr("GLib", "unix_signal_add_full", "GLib.unix_signal_add")
# obsolete constants for backwards compatibility
__all__.append(name)
# PARAM_READWRITE should come from the gi module but cannot due to:
-# https://bugzilla.gnome.org/show_bug.cgi?id=687615
+# https://gitlab.gnome.org/GNOME/gobject-introspection/issues/75
PARAM_READWRITE = GObjectModule.ParamFlags.READABLE | \
GObjectModule.ParamFlags.WRITABLE
+deprecated_attr("GObject", "PARAM_READWRITE", "GObject.ParamFlags.READWRITE")
__all__.append("PARAM_READWRITE")
-# READWRITE is part of ParamFlags since glib 2.42. Only mark PARAM_READWRITE as
-# deprecated in case ParamFlags.READWRITE is available. Also include the glib
-# version in the warning so it's clear that this needs a newer glib, unlike
-# the other ParamFlags related deprecations.
-# https://bugzilla.gnome.org/show_bug.cgi?id=726037
-if hasattr(GObjectModule.ParamFlags, "READWRITE"):
- deprecated_attr("GObject", "PARAM_READWRITE",
- "GObject.ParamFlags.READWRITE (glib 2.42+)")
-
# Deprecated, use: GObject.SignalFlags.* directly
for name in ['SIGNAL_ACTION', 'SIGNAL_DETAILED', 'SIGNAL_NO_HOOKS',
if isinstance(py_value, text_type):
py_value = py_value.encode('UTF-8')
else:
- raise ValueError("Expected string or unicode but got %s%s" %
- (py_value, type(py_value)))
+ raise TypeError("Expected string or unicode but got %s%s" %
+ (py_value, type(py_value)))
else:
- raise ValueError("Expected string but got %s%s" %
- (py_value, type(py_value)))
+ raise TypeError("Expected string but got %s%s" %
+ (py_value, type(py_value)))
self.set_string(py_value)
elif gtype == TYPE_PARAM:
self.set_param(py_value)
+ elif gtype == TYPE_PYOBJECT:
+ self.set_boxed(py_value)
elif gtype.is_a(TYPE_ENUM):
self.set_enum(py_value)
elif gtype.is_a(TYPE_FLAGS):
self.set_pointer(py_value)
elif gtype.is_a(TYPE_OBJECT):
self.set_object(py_value)
- elif gtype == TYPE_UNICHAR:
- self.set_uint(int(py_value))
- # elif gtype == TYPE_OVERRIDE:
- # pass
elif gtype == TYPE_GTYPE:
self.set_gtype(py_value)
elif gtype == TYPE_VARIANT:
self.set_variant(py_value)
- elif gtype == TYPE_PYOBJECT:
- self.set_boxed(py_value)
else:
- raise TypeError("Unknown value type %s" % gtype)
+ # Fall back to _gvalue_set which handles some more cases
+ # like fundamentals for which a converter is registered
+ _gi._gvalue_set(self, py_value)
def get_value(self):
gtype = self.g_type
return self.get_double()
elif gtype == TYPE_STRING:
return self.get_string()
+ elif gtype == TYPE_PYOBJECT:
+ return self.get_boxed()
elif gtype == TYPE_PARAM:
return self.get_param()
elif gtype.is_a(TYPE_ENUM):
return self.get_pointer()
elif gtype.is_a(TYPE_OBJECT):
return self.get_object()
- elif gtype == TYPE_UNICHAR:
- return self.get_uint()
elif gtype == TYPE_GTYPE:
return self.get_gtype()
elif gtype == TYPE_VARIANT:
- return self.get_variant()
- elif gtype == TYPE_PYOBJECT:
- pass
- else:
+ # get_variant was missing annotations
+ # https://gitlab.gnome.org/GNOME/glib/merge_requests/492
+ return self.dup_variant()
+ elif gtype == _gi.TYPE_INVALID:
return None
+ else:
+ return _gi._gvalue_get(self)
def __repr__(self):
return '<Value (%s) %s>' % (self.g_type.name, self.get_value())
id_or_name = signal_lookup(id_or_name, type_)
res = GObjectModule.signal_query(id_or_name)
- if res is None:
- return None
+ assert res is not None
if res.signal_id == 0:
return None
from gi import PyGIDeprecationWarning, require_version
Gdk = get_introspection_module('Gdk')
+GDK2 = Gdk._version == '2.0'
+GDK3 = Gdk._version == '3.0'
__all__ = []
except (ValueError, ImportError):
pass
-if hasattr(Gdk, 'Color'):
+if GDK2 or GDK3:
# Gdk.Color was deprecated since 3.14 and dropped in Gtk+-4.0
class Color(Gdk.Color):
MAX_VALUE = 65535
Color = override(Color)
__all__.append('Color')
-if hasattr(Gdk, 'RGBA'):
+if GDK3:
# Introduced since Gtk+-3.0
class RGBA(Gdk.RGBA):
def __init__(self, red=1.0, green=1.0, blue=1.0, alpha=1.0):
RGBA = override(RGBA)
__all__.append('RGBA')
-if Gdk._version == '2.0':
+if GDK2:
class Rectangle(Gdk.Rectangle):
def __init__(self, x, y, width, height):
Rectangle = override(Rectangle)
__all__.append('Rectangle')
-else:
+elif GDK3:
# Newer GTK+/gobject-introspection (3.17.x) include GdkRectangle in the
# typelib. See https://bugzilla.gnome.org/show_bug.cgi?id=748832 and
# https://bugzilla.gnome.org/show_bug.cgi?id=748833
__all__.append('rectangle_intersect')
__all__.append('rectangle_union')
-if Gdk._version == '2.0':
+if GDK2:
class Drawable(Gdk.Drawable):
def cairo_create(self):
return Gdk.cairo_create(self)
Drawable = override(Drawable)
__all__.append('Drawable')
-elif Gdk._version == '3.0':
+elif GDK3:
class Window(Gdk.Window):
def __new__(cls, parent, attributes, attributes_mask):
# Gdk.Window had to be made abstract,
Window = override(Window)
__all__.append('Window')
-if Gdk._version in ("2.0", "3.0"):
+if GDK2 or GDK3:
Gdk.EventType._2BUTTON_PRESS = getattr(Gdk.EventType, "2BUTTON_PRESS")
Gdk.EventType._3BUTTON_PRESS = getattr(Gdk.EventType, "3BUTTON_PRESS")
Gdk.EventType.UNMAP: 'any',
}
- if Gdk._version == '2.0':
+ if GDK2:
_UNION_MEMBERS[Gdk.EventType.NO_EXPOSE] = 'no_expose'
if hasattr(Gdk.EventType, 'TOUCH_BEGIN'):
DragContext = override(DragContext)
__all__.append('DragContext')
+ class Cursor(Gdk.Cursor):
+
+ def __new__(cls, *args, **kwds):
+ arg_len = len(args)
+ kwd_len = len(kwds)
+ total_len = arg_len + kwd_len
+
+ if total_len == 1:
+ # Since g_object_newv (super.__new__) does not seem valid for
+ # direct use with GdkCursor, we must assume usage of at least
+ # one of the C constructors to be valid.
+ return cls.new(*args, **kwds)
+
+ elif total_len == 2:
+ warnings.warn('Calling "Gdk.Cursor(display, cursor_type)" has been deprecated. '
+ 'Please use Gdk.Cursor.new_for_display(display, cursor_type). '
+ 'See: https://wiki.gnome.org/PyGObject/InitializerDeprecations',
+ PyGIDeprecationWarning)
+ return cls.new_for_display(*args, **kwds)
+
+ elif total_len == 4:
+ warnings.warn('Calling "Gdk.Cursor(display, pixbuf, x, y)" has been deprecated. '
+ 'Please use Gdk.Cursor.new_from_pixbuf(display, pixbuf, x, y). '
+ 'See: https://wiki.gnome.org/PyGObject/InitializerDeprecations',
+ PyGIDeprecationWarning)
+ return cls.new_from_pixbuf(*args, **kwds)
+
+ elif total_len == 6:
+ if not GDK2:
+ # pixmaps don't exist in Gdk 3.0
+ raise ValueError("Wrong number of parameters")
+
+ warnings.warn('Calling "Gdk.Cursor(source, mask, fg, bg, x, y)" has been deprecated. '
+ 'Please use Gdk.Cursor.new_from_pixmap(source, mask, fg, bg, x, y). '
+ 'See: https://wiki.gnome.org/PyGObject/InitializerDeprecations',
+ PyGIDeprecationWarning)
+ return cls.new_from_pixmap(*args, **kwds)
-class Cursor(Gdk.Cursor):
-
- def __new__(cls, *args, **kwds):
- arg_len = len(args)
- kwd_len = len(kwds)
- total_len = arg_len + kwd_len
-
- if total_len == 1:
- if Gdk._version == "4.0":
- raise ValueError("Wrong number of parameters")
- # Since g_object_newv (super.__new__) does not seem valid for
- # direct use with GdkCursor, we must assume usage of at least
- # one of the C constructors to be valid.
- return cls.new(*args, **kwds)
-
- elif total_len == 2:
- warnings.warn('Calling "Gdk.Cursor(display, cursor_type)" has been deprecated. '
- 'Please use Gdk.Cursor.new_for_display(display, cursor_type). '
- 'See: https://wiki.gnome.org/PyGObject/InitializerDeprecations',
- PyGIDeprecationWarning)
- return cls.new_for_display(*args, **kwds)
-
- elif total_len == 4:
- warnings.warn('Calling "Gdk.Cursor(display, pixbuf, x, y)" has been deprecated. '
- 'Please use Gdk.Cursor.new_from_pixbuf(display, pixbuf, x, y). '
- 'See: https://wiki.gnome.org/PyGObject/InitializerDeprecations',
- PyGIDeprecationWarning)
- return cls.new_from_pixbuf(*args, **kwds)
-
- elif total_len == 6:
- if Gdk._version != '2.0':
- # pixmaps don't exist in Gdk 3.0
+ else:
raise ValueError("Wrong number of parameters")
- warnings.warn('Calling "Gdk.Cursor(source, mask, fg, bg, x, y)" has been deprecated. '
- 'Please use Gdk.Cursor.new_from_pixmap(source, mask, fg, bg, x, y). '
- 'See: https://wiki.gnome.org/PyGObject/InitializerDeprecations',
- PyGIDeprecationWarning)
- return cls.new_from_pixmap(*args, **kwds)
-
- else:
- raise ValueError("Wrong number of parameters")
-
+ Cursor = override(Cursor)
+ __all__.append('Cursor')
-Cursor = override(Cursor)
-__all__.append('Cursor')
-
-if hasattr(Gdk, 'color_parse'):
# Gdk.Color was deprecated since 3.14 and dropped in Gtk+-4.0
color_parse = strip_boolean_result(Gdk.color_parse)
__all__.append('color_parse')
+ # Note, we cannot override the entire class as Gdk.Atom has no gtype, so just
+ # hack some individual methods
+ def _gdk_atom_str(atom):
+ n = atom.name()
+ if n:
+ return n
+ # fall back to atom index
+ return 'Gdk.Atom<%i>' % hash(atom)
+
+ def _gdk_atom_repr(atom):
+ n = atom.name()
+ if n:
+ return 'Gdk.Atom.intern("%s", False)' % n
+ # fall back to atom index
+ return '<Gdk.Atom(%i)>' % hash(atom)
-# Note, we cannot override the entire class as Gdk.Atom has no gtype, so just
-# hack some individual methods
-def _gdk_atom_str(atom):
- n = atom.name()
- if n:
- return n
- # fall back to atom index
- return 'Gdk.Atom<%i>' % hash(atom)
-
-
-def _gdk_atom_repr(atom):
- n = atom.name()
- if n:
- return 'Gdk.Atom.intern("%s", False)' % n
- # fall back to atom index
- return '<Gdk.Atom(%i)>' % hash(atom)
-
-
-if Gdk._version in ("2.0", "3.0"):
Gdk.Atom.__str__ = _gdk_atom_str
Gdk.Atom.__repr__ = _gdk_atom_repr
# constants
-if Gdk._version == '3.0':
+if GDK3:
SELECTION_PRIMARY = Gdk.atom_intern('PRIMARY', True)
__all__.append('SELECTION_PRIMARY')
SELECTION_TYPE_STRING = Gdk.atom_intern('STRING', True)
__all__.append('SELECTION_TYPE_STRING')
-if Gdk._version in ('2.0', '3.0'):
+if GDK2 or GDK3:
import sys
initialized, argv = Gdk.init_check(sys.argv)
def _process_action(group_source, name, stock_id=None, label=None, accelerator=None, tooltip=None, entry_value=0):
action = RadioAction(name=name, label=label, tooltip=tooltip, stock_id=stock_id, value=entry_value)
- # FIXME: join_group is a patch to Gtk+ 3.0
- # otherwise we can't effectively add radio actions to a
- # group. Should we depend on 3.0 and error out here
- # or should we offer the functionality via a compat
- # C module?
- if hasattr(action, 'join_group'):
+ if Gtk._version == '3.0':
action.join_group(group_source)
if value == entry_value:
def _get_utf8_length(string):
- if not isinstance(string, string_types):
- raise TypeError('must be a string')
+ assert isinstance(string, string_types)
if not isinstance(string, bytes):
string = string.encode("utf-8")
return len(string)
'Please use the "add_buttons" method for adding buttons. '
'See: https://wiki.gnome.org/PyGObject/InitializerDeprecations',
PyGTKDeprecationWarning, stacklevel=stacklevel)
- if 'buttons' in new_kwargs:
- del new_kwargs['buttons']
+ new_kwargs.pop('buttons', None)
else:
add_buttons = None
"""
def _button(b):
while b:
- t, r = b[0:2]
+ try:
+ t, r = b[0:2]
+ except ValueError:
+ raise ValueError('Must pass an even number of arguments')
b = b[2:]
yield t, r
- try:
- for text, response in _button(args):
- self.add_button(text, response)
- except (IndexError):
- raise TypeError('Must pass an even number of arguments')
+ for text, response in _button(args):
+ self.add_button(text, response)
Dialog = override(Dialog)
class TextBuffer(Gtk.TextBuffer):
- def _get_or_create_tag_table(self):
- table = self.get_tag_table()
- if table is None:
- table = Gtk.TextTagTable()
- self.set_tag_table(table)
-
- return table
def create_tag(self, tag_name=None, **properties):
"""Creates a tag and adds it to the tag table of the TextBuffer.
"""
tag = Gtk.TextTag(name=tag_name, **properties)
- self._get_or_create_tag_table().add(tag)
+ self.get_tag_table().add(tag)
return tag
def create_mark(self, mark_name, where, left_gravity=False):
index = len(self) + key
if index < 0:
raise IndexError("row index is out of bounds: %d" % key)
- try:
- aiter = self.get_iter(index)
- except ValueError:
- raise IndexError("could not find tree path '%s'" % key)
- return aiter
+ return self.get_iter(index)
else:
try:
aiter = self.get_iter(key)
def set_row(self, treeiter, row):
converted_row, columns = self._convert_row(row)
for column in columns:
- value = row[column]
- if value is None:
- continue # None means skip this row
-
- self.set_value(treeiter, column, value)
+ self.set_value(treeiter, column, row[column])
def _convert_value(self, column, value):
'''Convert value to a GObject.Value of the expected type'''
elif isinstance(iter_or_path, Gtk.TreeIter):
self.iter = iter_or_path
else:
- raise TypeError("expected Gtk.TreeIter or Gtk.TreePath, \
- %s found" % type(iter_or_path).__name__)
+ raise TypeError("expected Gtk.TreeIter or Gtk.TreePath, "
+ "%s found" % type(iter_or_path).__name__)
@property
def path(self):
if sibling is None:
position = -1
else:
+ if parent is None:
+ parent = self.iter_parent(sibling)
position = self.get_path(sibling).get_indices()[-1]
return self._do_insert(parent, position, row)
if sibling is None:
position = 0
else:
+ if parent is None:
+ parent = self.iter_parent(sibling)
position = self.get_path(sibling).get_indices()[-1] + 1
return self._do_insert(parent, position, row)
GType temp = pyg_type_from_object (py_arg);
if (temp == 0) {
- PyErr_Format (PyExc_TypeError, "Must be gobject.GType, not %s",
+ if (!PyErr_Occurred ()) {
+ PyErr_SetString (PyExc_ValueError, "Invalid GType");
+ return FALSE;
+ }
+ PyErr_Format (PyExc_TypeError, "Must be GObject.GType, not %s",
Py_TYPE (py_arg)->tp_name);
return FALSE;
}
/* PycairoContext_FromContext steals a ref, so we dup it out of the GValue. */
cairo_t *cr = g_value_dup_boxed (value);
if (!cr) {
- return NULL;
+ Py_RETURN_NONE;
}
return PycairoContext_FromContext (cr, &PycairoContext_Type, NULL);
/* PycairoSurface_FromSurface steals a ref, so we dup it out of the GValue. */
cairo_surface_t *surface = g_value_dup_boxed (value);
if (!surface) {
- return NULL;
+ Py_RETURN_NONE;
}
return PycairoSurface_FromSurface (surface, NULL);
{
cairo_font_face_t *font_face = g_value_dup_boxed (value);
if (!font_face) {
- return NULL;
+ Py_RETURN_NONE;
}
return PycairoFontFace_FromFontFace (font_face);
/* PycairoScaledFont_FromScaledFont steals a ref, so we dup it out of the GValue. */
cairo_scaled_font_t *scaled_font = g_value_dup_boxed (value);
if (!scaled_font) {
- return NULL;
+ Py_RETURN_NONE;
}
return PycairoScaledFont_FromScaledFont (scaled_font);
/* PycairoPattern_FromPattern steals a ref, so we dup it out of the GValue. */
cairo_pattern_t *pattern = g_value_dup_boxed (value);
if (!pattern) {
- return NULL;
+ Py_RETURN_NONE;
}
return PycairoPattern_FromPattern (pattern, NULL);
return pygi_gboolean_to_py (g_struct_info_is_foreign (self->info));
}
+static PyObject *
+_wrap_g_struct_info_find_method (PyGIBaseInfo *self, PyObject *py_name)
+{
+ return _get_child_info_by_name (self, py_name, g_struct_info_find_method);
+}
+
+static PyObject *
+_wrap_g_struct_info_find_field (PyGIBaseInfo *self, PyObject *py_name)
+{
+ return _get_child_info_by_name (self, py_name, g_struct_info_find_field);
+}
+
static PyMethodDef _PyGIStructInfo_methods[] = {
{ "get_fields", (PyCFunction) _wrap_g_struct_info_get_fields, METH_NOARGS },
+ { "find_field", (PyCFunction) _wrap_g_struct_info_find_field, METH_O },
{ "get_methods", (PyCFunction) _wrap_g_struct_info_get_methods, METH_NOARGS },
+ { "find_method", (PyCFunction) _wrap_g_struct_info_find_method, METH_O },
{ "get_size", (PyCFunction) _wrap_g_struct_info_get_size, METH_NOARGS },
{ "get_alignment", (PyCFunction) _wrap_g_struct_info_get_alignment, METH_NOARGS },
{ "is_gtype_struct", (PyCFunction) _wrap_g_struct_info_is_gtype_struct, METH_NOARGS },
return pygi_gsize_to_py (g_union_info_get_size (self->info));
}
+static PyObject *
+_wrap_g_union_info_get_alignment (PyGIBaseInfo *self)
+{
+ return pygi_gsize_to_py (g_union_info_get_alignment (self->info));
+}
+
static PyMethodDef _PyGIUnionInfo_methods[] = {
{ "get_fields", (PyCFunction) _wrap_g_union_info_get_fields, METH_NOARGS },
{ "get_methods", (PyCFunction) _wrap_g_union_info_get_methods, METH_NOARGS },
{ "get_size", (PyCFunction) _wrap_g_union_info_get_size, METH_NOARGS },
+ { "get_alignment", (PyCFunction) _wrap_g_union_info_get_alignment, METH_NOARGS },
{ NULL, NULL, 0 }
};
project('pygobject', 'c',
- version : '3.31.1',
+ version : '3.31.2',
meson_version : '>= 0.46.0',
default_options : [ 'warning_level=1',
'buildtype=debugoptimized'])
python_dep = python.dependency()
-glib_version_req = '>= 2.38.0'
+glib_version_req = '>= 2.48.0'
gi_version_req = '>= 1.46.0'
pycairo_version_req = '>= 1.11.1'
libffi_version_req = '>= 3.0'
<mailing-list rdf:resource="http://mail.gnome.org/mailman/listinfo/python-hackers-list" />
<category rdf:resource="http://api.gnome.org/doap-extensions#core" />
<download-page rdf:resource="http://download.gnome.org/sources/pygobject/" />
- <bug-database rdf:resource="https://bugzilla.gnome.org/browse.cgi?product=pygobject" />
+ <bug-database rdf:resource="https://gitlab.gnome.org/GNOME/pygobject/issues/" />
<programming-language>C</programming-language>
<programming-language>Python</programming-language>
<maintainer>
from distutils.spawn import find_executable
-PYGOBJECT_VERISON = "3.31.1"
-GLIB_VERSION_REQUIRED = "2.38.0"
+PYGOBJECT_VERSION = "3.31.2"
+GLIB_VERSION_REQUIRED = "2.48.0"
GI_VERSION_REQUIRED = "1.46.0"
PYCAIRO_VERSION_REQUIRED = "1.11.1"
LIBFFI_VERSION_REQUIRED = "3.0"
def is_dev_version():
- version = tuple(map(int, PYGOBJECT_VERISON.split(".")))
+ version = tuple(map(int, PYGOBJECT_VERSION.split(".")))
return version[1] % 2 != 0
def get_versions():
- version = PYGOBJECT_VERISON.split(".")
+ version = PYGOBJECT_VERSION.split(".")
assert len(version) == 3
versions = {
return message
-def pkg_config_get_install_hint(pkg_name):
+def pkg_config_get_install_hint():
+ """Returns an installation hint for installing pkg-config or None"""
+
+ if not sys.platform.startswith("linux"):
+ return
+
+ if find_executable("apt"):
+ return "sudo apt install pkg-config"
+ elif find_executable("dnf"):
+ return "sudo dnf install pkg-config"
+
+
+def pkg_config_get_package_install_hint(pkg_name):
"""Returns an installation hint for a pkg-config name or None"""
if not sys.platform.startswith("linux"):
pass
+class PkgConfigMissingError(PkgConfigError):
+ pass
+
+
class PkgConfigMissingPackageError(PkgConfigError):
pass
result = subprocess.check_output(command)
except OSError as e:
if e.errno == errno.ENOENT:
- raise PkgConfigError(
+ raise PkgConfigMissingError(
"%r not found.\nArguments: %r" % (command[0], command))
raise PkgConfigError(e)
except subprocess.CalledProcessError as e:
def _run_pkg_config_or_exit(pkg_name, args):
try:
return _run_pkg_config(pkg_name, args)
+ except PkgConfigMissingError as e:
+ hint = pkg_config_get_install_hint()
+ if hint:
+ raise SystemExit(
+ "%s\n\nTry installing it with: %r" % (e, hint))
+ else:
+ raise SystemExit(e)
except PkgConfigMissingPackageError as e:
- hint = pkg_config_get_install_hint(pkg_name)
+ hint = pkg_config_get_package_install_hint(pkg_name)
if hint:
raise SystemExit(
"%s\n\nTry installing it with: %r" % (e, hint))
def run(self):
# Don't use PEP 440 pre-release versions for GNOME releases
- self.distribution.metadata.version = PYGOBJECT_VERISON
+ self.distribution.metadata.version = PYGOBJECT_VERSION
dist_dir = tempfile.mkdtemp()
try:
"includedir": "${prefix}/include",
"datarootdir": "${prefix}/share",
"datadir": "${datarootdir}",
- "VERSION": PYGOBJECT_VERISON,
+ "VERSION": PYGOBJECT_VERSION,
}
for key, value in config.items():
content = content.replace("@%s@" % key, value)
@unittest.skipUnless(has_cairo, 'built without cairo support')
class Test(unittest.TestCase):
+
+ def test_gvalue_converters(self):
+ surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
+ context = cairo.Context(surface)
+ objects = {
+ 'CairoContext': context,
+ 'CairoSurface': surface,
+ 'CairoFontFace': context.get_font_face(),
+ 'CairoScaledFont': context.get_scaled_font(),
+ 'CairoPattern': context.get_source(),
+ }
+ for type_name, cairo_obj in objects.items():
+ gtype = GObject.type_from_name(type_name)
+ v = GObject.Value()
+ assert v.init(gtype) is None
+ assert v.get_value() is None
+ v.set_value(None)
+ assert v.get_value() is None
+ v.set_value(cairo_obj)
+ assert v.get_value() == cairo_obj
+
def test_cairo_context(self):
context = Regress.test_cairo_context_full_return()
self.assertTrue(isinstance(context, cairo.Context))
self.assertTrue(isinstance(data['error'], Exception))
self.assertTrue('InvalidArgs' in str(data['error']), str(data['error']))
+
+ def test_instantiate_custom_proxy(self):
+ class SomeProxy(Gio.DBusProxy):
+ def __init__(self):
+ Gio.DBusProxy.__init__(self)
+
+ SomeProxy()
self.assertEqual(count, 0)
def test_get_column_type(self):
- with ExceptHook(NotImplementedError, TypeError):
+ with ExceptHook(NotImplementedError, ValueError):
col_type = self.model.get_column_type(0)
self.assertEqual(col_type, GObject.TYPE_INVALID)
from gi import _gi
import testhelper
+from .helper import capture_glib_deprecation_warnings
class TestGObjectAPI(unittest.TestCase):
self.assertEqual(self.source.int_prop, 1)
self.assertEqual(self.target.int_prop, 2)
+ def test_call_binding(self):
+ binding = self.source.bind_property('int_prop', self.target, 'int_prop',
+ GObject.BindingFlags.DEFAULT)
+ with capture_glib_deprecation_warnings() as warn:
+ result = binding()
+ assert len(warn)
+ assert result is binding
+
def test_bidirectional_binding(self):
binding = self.source.bind_property('int_prop', self.target, 'int_prop',
GObject.BindingFlags.BIDIRECTIONAL)
from __future__ import absolute_import
+import re
import os
import sys
import unittest
+import pytest
+import gi
import gi.overrides
from gi import PyGIDeprecationWarning
try:
from gi.repository import Gdk, GdkPixbuf, Gtk
- Gdk_version = Gdk._version
+ GDK4 = Gdk._version == "4.0"
except ImportError:
Gdk = None
- Gdk_version = None
+ GDK4 = False
+
+try:
+ gi.require_foreign('cairo')
+ has_cairo = True
+except ImportError:
+ has_cairo = False
from .helper import capture_glib_deprecation_warnings
class TestGdk(unittest.TestCase):
@unittest.skipIf(sys.platform == "darwin" or os.name == "nt", "crashes")
- @unittest.skipIf(Gdk_version == "4.0", "not in gdk4")
+ @unittest.skipIf(GDK4, "not in gdk4")
def test_constructor(self):
attribute = Gdk.WindowAttr()
attribute.window_type = Gdk.WindowType.CHILD
window = Gdk.Window(None, attribute, attributes_mask)
self.assertEqual(window.get_window_type(), Gdk.WindowType.CHILD)
- @unittest.skipIf(Gdk_version == "4.0", "not in gdk4")
+ @unittest.skipIf(GDK4, "not in gdk4")
def test_color(self):
color = Gdk.Color(100, 200, 300)
self.assertEqual(color.red, 100)
self.assertEqual(color, Gdk.Color(100, 200, 300))
self.assertNotEqual(color, Gdk.Color(1, 2, 3))
- @unittest.skipIf(Gdk_version == "4.0", "not in gdk4")
+ @unittest.skipIf(GDK4, "not in gdk4")
def test_color_floats(self):
self.assertEqual(Gdk.Color(13107, 21845, 65535),
Gdk.Color.from_floats(0.2, 1.0 / 3.0, 1.0))
self.assertEqual(Gdk.RGBA.from_color(Gdk.Color(13107, 21845, 65535)),
Gdk.RGBA(0.2, 1.0 / 3.0, 1.0, 1.0))
+ @unittest.skipIf(GDK4, "not in gdk4")
+ def test_color_to_floats_attrs(self):
+ color = Gdk.Color(13107, 21845, 65535)
+ assert color.red_float == 0.2
+ color.red_float = 0
+ assert color.red_float == 0
+ assert color.green_float == 1.0 / 3.0
+ color.green_float = 0
+ assert color.green_float == 0
+ assert color.blue_float == 1.0
+ color.blue_float = 0
+ assert color.blue_float == 0
+
+ @unittest.skipIf(GDK4, "not in gdk4")
def test_rgba(self):
self.assertEqual(Gdk.RGBA, gi.overrides.Gdk.RGBA)
rgba = Gdk.RGBA(0.1, 0.2, 0.3, 0.4)
self.assertEqual(tuple(Gdk.RGBA(0.1, 0.2, 0.3, 0.4)),
(0.1, 0.2, 0.3, 0.4))
- @unittest.skipIf(Gdk_version == "4.0", "not in gdk4")
+ @unittest.skipUnless(GDK4, "only in gdk4")
+ def test_rgba_gtk4(self):
+ c = Gdk.RGBA()
+ assert c.to_string() == "rgba(0,0,0,0)"
+
+ @unittest.skipIf(not has_cairo or GDK4, "not in gdk4")
+ def test_window(self):
+ w = Gtk.Window()
+ w.realize()
+ window = w.get_window()
+ with capture_glib_deprecation_warnings():
+ assert window.cairo_create() is not None
+
+ @unittest.skipIf(GDK4, "not in gdk4")
+ def test_drag_context(self):
+ context = Gdk.DragContext()
+ # using it this way crashes..
+ assert hasattr(context, "finish")
+
+ @unittest.skipIf(GDK4, "not in gdk4")
def test_event(self):
event = Gdk.Event.new(Gdk.EventType.CONFIGURE)
self.assertEqual(event.type, Gdk.EventType.CONFIGURE)
event.type = Gdk.EventType.SCROLL
self.assertRaises(AttributeError, lambda: getattr(event, 'foo_bar'))
- @unittest.skipIf(Gdk_version == "4.0", "not in gdk4")
+ @unittest.skipIf(GDK4, "not in gdk4")
def test_event_touch(self):
event = Gdk.Event.new(Gdk.EventType.TOUCH_BEGIN)
self.assertEqual(event.type, Gdk.EventType.TOUCH_BEGIN)
self.assertTrue(event.emulating_pointer)
self.assertTrue(event.touch.emulating_pointer)
- @unittest.skipIf(Gdk_version == "4.0", "not in gdk4")
+ @unittest.skipIf(GDK4, "not in gdk4")
def test_event_setattr(self):
event = Gdk.Event.new(Gdk.EventType.DRAG_MOTION)
event.x_root, event.y_root = 0, 5
self.assertFalse(hasattr(event, "foo_bar"))
event.foo_bar = 42
- @unittest.skipIf(Gdk_version == "4.0", "not in gdk4")
+ # unhandled type
+ event.type = Gdk.EventType.EVENT_LAST
+ with pytest.raises(AttributeError):
+ event.foo_bar
+ event.foo_bar = 42
+ assert event.foo_bar == 42
+
+ @unittest.skipIf(GDK4, "not in gdk4")
def test_event_repr(self):
event = Gdk.Event.new(Gdk.EventType.CONFIGURE)
self.assertTrue("CONFIGURE" in repr(event))
- @unittest.skipIf(Gdk_version == "4.0", "not in gdk4")
+ @unittest.skipIf(GDK4, "not in gdk4")
def test_event_structures(self):
def button_press_cb(button, event):
self.assertTrue(isinstance(event, Gdk.EventButton))
Gdk.ModifierType.CONTROL_MASK,
Gdk.EventType.BUTTON_PRESS)
- @unittest.skipIf(Gdk_version == "4.0", "not in gdk4")
+ @unittest.skipIf(GDK4, "not in gdk4")
def test_cursor(self):
self.assertEqual(Gdk.Cursor, gi.overrides.Gdk.Cursor)
with capture_glib_deprecation_warnings():
self.assertRaises(ValueError, Gdk.Cursor, 1, 2, 3)
+ with capture_glib_deprecation_warnings() as warn:
+ c = Gdk.Cursor(display, Gdk.CursorType.WATCH)
+ assert len(warn) == 1
+ # on macOS the type is switched to PIXMAP behind the scenes
+ assert c.props.cursor_type in (
+ Gdk.CursorType.WATCH, Gdk.CursorType.CURSOR_IS_PIXMAP)
+ assert c.props.display == display
+
+ @unittest.skipUnless(GDK4, "only gdk4")
+ def test_cursor_gdk4(self):
+ Gdk.Cursor()
+ Gdk.Cursor(name="foo")
+ Gdk.Cursor(fallback=Gdk.Cursor())
+
def test_flags(self):
self.assertEqual(Gdk.ModifierType.META_MASK | 0, 0x10000000)
self.assertEqual(hex(Gdk.ModifierType.META_MASK), '0x10000000')
self.assertEqual(str(Gdk.ModifierType.RELEASE_MASK | Gdk.ModifierType.META_MASK),
'<flags GDK_META_MASK | GDK_RELEASE_MASK of type Gdk.ModifierType>')
- @unittest.skipIf(Gdk_version == "4.0", "not in gdk4")
+ @unittest.skipIf(GDK4, "not in gdk4")
def test_color_parse(self):
with capture_glib_deprecation_warnings():
c = Gdk.color_parse('#00FF80')
self.assertEqual(c.blue, 32896)
self.assertEqual(Gdk.color_parse('bogus'), None)
- @unittest.skipIf(Gdk_version == "4.0", "not in gdk4")
+ @unittest.skipIf(GDK4, "not in gdk4")
def test_color_representations(self):
# __repr__ should generate a string which is parsable when possible
# http://docs.python.org/2/reference/datamodel.html#object.__repr__
rgba = Gdk.RGBA(red=1.0, green=0.8, blue=0.6, alpha=0.4)
self.assertEqual(eval(repr(rgba)), rgba)
+ @unittest.skipIf(GDK4, "not in gdk4")
def test_rectangle_functions(self):
# https://bugzilla.gnome.org/show_bug.cgi?id=756364
a = Gdk.Rectangle()
intersect, rect = Gdk.rectangle_intersect(a, b)
self.assertTrue(isinstance(rect, Gdk.Rectangle))
self.assertTrue(isinstance(intersect, bool))
+
+ @unittest.skipIf(GDK4, "not in gdk4")
+ def test_atom_repr_str(self):
+ atom = Gdk.atom_intern("", True)
+ assert re.match(r"<Gdk.Atom\(\d+\)>", repr(atom))
+ assert re.match(r"Gdk.Atom<\d+>", str(atom))
from __future__ import absolute_import
+import os
import gc
import unittest
+import tempfile
+import socket
+
+import pytest
import gi
from gi.repository import GLib
from gi._compat import long_, integer_types
+from .helper import capture_gi_deprecation_warnings
+
+
+def test_io_add_watch_get_args():
+ get_args = GLib._io_add_watch_get_args
+ func = lambda: None
+
+ # create a closed channel for testing
+ fd, fn = tempfile.mkstemp()
+ os.close(fd)
+ try:
+ chan = GLib.IOChannel(filename=fn)
+ chan.shutdown(True)
+ finally:
+ os.remove(fn)
+
+ # old way
+ with capture_gi_deprecation_warnings():
+ assert get_args(chan, GLib.IOCondition.IN, func) == (
+ chan, 0, GLib.IOCondition.IN, func, tuple())
+
+ with pytest.raises(TypeError):
+ get_args(chan, GLib.IOCondition.IN, object())
+
+ # new way
+ prio = GLib.PRIORITY_DEFAULT
+ with capture_gi_deprecation_warnings():
+ assert get_args(chan, prio, GLib.IOCondition.IN, func, 99) == \
+ (chan, prio, GLib.IOCondition.IN, func, (99,))
+
+ with pytest.raises(TypeError):
+ assert get_args(chan, prio, GLib.IOCondition.IN)
+
+ with pytest.raises(TypeError):
+ assert get_args(chan, prio, 99)
+
+
+@pytest.mark.skipif(os.name != "nt", reason="windows only")
+def test_io_add_watch_get_args_win32_socket():
+ get_args = GLib._io_add_watch_get_args
+
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ func = lambda: None
+ prio = GLib.PRIORITY_DEFAULT
+ chan = get_args(s, prio, GLib.IOCondition.IN, func)[0]
+ assert isinstance(chan, GLib.IOChannel)
+ chan.shutdown(False)
+
+
+def test_threads_init():
+ with capture_gi_deprecation_warnings() as w:
+ GLib.threads_init()
+ assert len(w)
+
+
+def test_gerror_matches():
+ e = GLib.Error(domain=42, code=24)
+ assert e.matches(42, 24)
+
+
+def test_timeout_add_seconds():
+ h = GLib.timeout_add_seconds(
+ 100, lambda *x: None, 1, 2, 3, priority=GLib.PRIORITY_HIGH_IDLE)
+ GLib.source_remove(h)
+
+
+def test_iochannel():
+ with pytest.raises(TypeError):
+ GLib.IOChannel()
+
+
+def test_iochannel_write():
+ fd, fn = tempfile.mkstemp()
+ os.close(fd)
+ chan = GLib.IOChannel(filename=fn, mode="r+")
+ try:
+ assert chan.write(b"foo", 2) == 2
+ chan.seek(0)
+ assert chan.read() == b"fo"
+ finally:
+ chan.shutdown(True)
+
+
+@pytest.mark.skipif(os.name == "nt", reason="unix only")
+def test_has_unix_signal_add():
+ with capture_gi_deprecation_warnings():
+ GLib.unix_signal_add == GLib.unix_signal_add_full
+
+
+@pytest.mark.skipif(os.name != "nt", reason="windows only")
+def test_iochannel_win32():
+ fd, fn = tempfile.mkstemp()
+ closed = False
+ try:
+ channel = GLib.IOChannel(hwnd=fd)
+ try:
+ assert channel.read() == b""
+ finally:
+ closed = True
+ channel.shutdown(True)
+ finally:
+ if not closed:
+ os.close(fd)
+ os.remove(fn)
+
class TestGVariant(unittest.TestCase):
def test_create_simple(self):
self.assertTrue(isinstance(variant, GLib.Variant))
self.assertEqual(variant.get_string(), 'hello')
+ def test_simple_invalid_ops(self):
+ variant = GLib.Variant('i', 42)
+ with pytest.raises(TypeError):
+ len(variant)
+
+ with pytest.raises(TypeError):
+ variant[0]
+
+ with pytest.raises(TypeError):
+ variant.keys()
+
def test_create_variant(self):
variant = GLib.Variant('v', GLib.Variant('i', 42))
self.assertTrue(isinstance(variant, GLib.Variant))
self.assertTrue(isinstance(variant, GLib.Variant))
self.assertEqual(variant.unpack(), d)
+ # init with an iterable
+ variant = GLib.Variant('a{si}', [("foo", 2)])
+ assert variant.unpack() == {'foo': 2}
+
+ with pytest.raises(TypeError):
+ GLib.Variant('a{si}', [("foo",)])
+ with pytest.raises(TypeError):
+ GLib.Variant('a{si}', [("foo", 1, 2)])
+
def test_create_array(self):
variant = GLib.Variant('ai', [])
self.assertEqual(variant.get_type_string(), 'ai')
assert_equal('v', GLib.Variant('i', 42))
assert_not_equal('v', GLib.Variant('i', 42), 'v', GLib.Variant('i', 43))
+ assert GLib.Variant('i', 42) != object()
+ assert not GLib.Variant('i', 42) == object()
+
def test_bool(self):
# Check if the GVariant bool matches the unpacked Pythonic bool
assert_equals_bool('v', GLib.Variant('i', 0))
assert_equals_bool('v', GLib.Variant('i', 1))
+ # maybe types
+ assert_equals_bool('mi', 42)
+ assert_equals_bool('mi', 0)
+ assert_equals_bool('mi', None)
+
def test_repr(self):
# with C constructor
v = GLib.Variant.new_uint32(42)
--- /dev/null
+# -*- coding: utf-8 -*-
+
+from __future__ import absolute_import
+
+import pytest
+
+from gi import PyGIDeprecationWarning
+from gi.repository import GObject, GLib
+
+from gi._compat import PY2
+from .helper import ignore_gi_deprecation_warnings
+
+
+def test_stop_emission_deprec():
+ class TestObject(GObject.GObject):
+ int_prop = GObject.Property(default=0, type=int)
+
+ obj = TestObject()
+
+ def notify_callback(obj, *args):
+ with pytest.warns(PyGIDeprecationWarning):
+ obj.stop_emission("notify::int-prop")
+
+ with pytest.warns(PyGIDeprecationWarning):
+ obj.emit_stop_by_name("notify::int-prop")
+
+ obj.stop_emission_by_name("notify::int-prop")
+
+ obj.connect("notify::int-prop", notify_callback)
+ obj.notify("int-prop")
+
+
+def test_signal_parse_name():
+ obj = GObject.GObject()
+ assert GObject.signal_parse_name("notify", obj, True) == (1, 0)
+
+ with pytest.raises(ValueError):
+ GObject.signal_parse_name("foobar", obj, True)
+
+
+def test_signal_query():
+ obj = GObject.GObject()
+ res = GObject.signal_query("notify", obj)
+ assert res.signal_name == "notify"
+ assert res.itype == obj.__gtype__
+
+ res = GObject.signal_query("foobar", obj)
+ assert res is None
+
+
+def test_value_repr():
+ v = GObject.Value()
+ assert repr(v) == "<Value (invalid) None>"
+
+ v = GObject.Value(int, 0)
+ assert repr(v) == "<Value (gint) 0>"
+
+
+def test_value_no_init():
+ v = GObject.Value()
+ with pytest.raises(TypeError):
+ v.set_value(0)
+ v.init(GObject.TYPE_LONG)
+ assert v.get_value() == 0
+ v.set_value(0)
+
+
+def test_value_invalid_type():
+ v = GObject.Value()
+ assert v.g_type == GObject.TYPE_INVALID
+ assert isinstance(GObject.TYPE_INVALID, GObject.GType)
+ with pytest.raises(ValueError, match="Invalid GType"):
+ v.init(GObject.TYPE_INVALID)
+
+
+def test_value_long():
+ v = GObject.Value(GObject.TYPE_LONG)
+ assert v.get_value() == 0
+ v.set_value(0)
+ assert v.get_value() == 0
+
+ v.set_value(GLib.MAXLONG)
+ assert v.get_value() == GLib.MAXLONG
+
+ v.set_value(GLib.MINLONG)
+ assert v.get_value() == GLib.MINLONG
+
+ with pytest.raises(OverflowError):
+ v.set_value(GLib.MAXLONG + 1)
+
+ with pytest.raises(OverflowError):
+ v.set_value(GLib.MINLONG - 1)
+
+
+def test_value_ulong():
+ v = GObject.Value(GObject.TYPE_ULONG)
+ assert v.get_value() == 0
+ v.set_value(0)
+ assert v.get_value() == 0
+
+ v.set_value(GLib.MAXULONG)
+ assert v.get_value() == GLib.MAXULONG
+
+ with pytest.raises(OverflowError):
+ v.set_value(GLib.MAXULONG + 1)
+
+ with pytest.raises(OverflowError):
+ v.set_value(-1)
+
+
+def test_value_uint64():
+ v = GObject.Value(GObject.TYPE_UINT64)
+ assert v.get_value() == 0
+ v.set_value(0)
+ assert v.get_value() == 0
+
+ v.set_value(GLib.MAXUINT64)
+ assert v.get_value() == GLib.MAXUINT64
+
+ with pytest.raises(OverflowError):
+ v.set_value(GLib.MAXUINT64 + 1)
+
+ with pytest.raises(OverflowError):
+ v.set_value(-1)
+
+
+def test_value_int64():
+ v = GObject.Value(GObject.TYPE_INT64)
+ assert v.get_value() == 0
+ v.set_value(0)
+ assert v.get_value() == 0
+
+ v.set_value(GLib.MAXINT64)
+ assert v.get_value() == GLib.MAXINT64
+ v.set_value(GLib.MININT64)
+ assert v.get_value() == GLib.MININT64
+
+ with pytest.raises(OverflowError):
+ v.set_value(GLib.MAXINT64 + 1)
+
+ with pytest.raises(OverflowError):
+ v.set_value(GLib.MININT64 - 1)
+
+
+def test_value_pointer():
+ v = GObject.Value(GObject.TYPE_POINTER)
+ assert v.get_value() == 0
+ v.set_value(42)
+ assert v.get_value() == 42
+ v.set_value(0)
+ assert v.get_value() == 0
+
+
+def test_value_unichar():
+ assert GObject.TYPE_UNICHAR == GObject.TYPE_UINT
+
+ v = GObject.Value(GObject.TYPE_UNICHAR)
+ assert v.get_value() == 0
+ v.set_value(42)
+ assert v.get_value() == 42
+
+ v.set_value(GLib.MAXUINT)
+ assert v.get_value() == GLib.MAXUINT
+
+
+def test_value_gtype():
+ class TestObject(GObject.GObject):
+ pass
+
+ v = GObject.Value(GObject.TYPE_GTYPE)
+ assert v.get_value() == GObject.TYPE_INVALID
+ v.set_value(TestObject.__gtype__)
+ assert v.get_value() == TestObject.__gtype__
+ v.set_value(TestObject)
+ assert v.get_value() == TestObject.__gtype__
+
+ with pytest.raises(TypeError):
+ v.set_value(None)
+
+
+def test_value_variant():
+ v = GObject.Value(GObject.TYPE_VARIANT)
+ assert v.get_value() is None
+ variant = GLib.Variant('i', 42)
+ v.set_value(variant)
+ assert v.get_value() == variant
+
+ v.set_value(None)
+ assert v.get_value() is None
+
+ with pytest.raises(TypeError):
+ v.set_value(object())
+
+
+def test_value_param():
+ # FIXME: set_value and get_value trigger a critical
+ # GObject.Value(GObject.TYPE_PARAM)
+ pass
+
+
+def test_value_string():
+ v = GObject.Value(GObject.TYPE_STRING)
+ assert v.get_value() is None
+
+ if PY2:
+ v.set_value(b"bar")
+ assert v.get_value() == b"bar"
+
+ v.set_value(u"öäü")
+ assert v.get_value().decode("utf-8") == u"öäü"
+ else:
+ with pytest.raises(TypeError):
+ v.set_value(b"bar")
+
+ v.set_value(u"quux")
+ assert v.get_value() == u"quux"
+ assert isinstance(v.get_value(), str)
+
+ with pytest.raises(TypeError):
+ v.set_value(None)
+
+
+def test_value_pyobject():
+ class Foo(object):
+ pass
+
+ v = GObject.Value(GObject.TYPE_PYOBJECT)
+ assert v.get_value() is None
+ for obj in [Foo(), None, 42, "foo"]:
+ v.set_value(obj)
+ assert v.get_value() == obj
+
+
+@ignore_gi_deprecation_warnings
+def test_value_char():
+ v = GObject.Value(GObject.TYPE_CHAR)
+ assert v.get_value() == 0
+ v.set_value(42)
+ assert v.get_value() == 42
+ v.set_value(-1)
+ assert v.get_value() == -1
+ v.set_value(b"a")
+ assert v.get_value() == 97
+ v.set_value(b"\x00")
+ assert v.get_value() == 0
+
+ with pytest.raises(TypeError):
+ v.set_value(u"a")
+
+ with pytest.raises(OverflowError):
+ v.set_value(128)
+
+
+def test_value_uchar():
+ v = GObject.Value(GObject.TYPE_UCHAR)
+ assert v.get_value() == 0
+ v.set_value(200)
+ assert v.get_value() == 200
+ v.set_value(b"a")
+ assert v.get_value() == 97
+ v.set_value(b"\x00")
+ assert v.get_value() == 0
+
+ with pytest.raises(TypeError):
+ v.set_value(u"a")
+
+ with pytest.raises(OverflowError):
+ v.set_value(256)
import gc
import warnings
+import pytest
+
from .helper import ignore_gi_deprecation_warnings, capture_glib_warnings
import gi.overrides
import gi.types
+from gi._compat import cmp
from gi.repository import GLib, GObject
try:
@unittest.skipUnless(Gtk, 'Gtk not available')
+@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
+def test_menu_popup():
+ m = Gtk.Menu()
+ with capture_glib_warnings():
+ m.popup(None, None, None, None, 0, 0)
+ m.popdown()
+
+
+@unittest.skipUnless(Gtk, 'Gtk not available')
+@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
+def test_button_stock():
+ with capture_glib_warnings():
+ button = Gtk.Button(stock=Gtk.STOCK_OK)
+ assert button.props.label == Gtk.STOCK_OK
+ assert button.props.use_stock
+
+
+@unittest.skipUnless(Gtk, 'Gtk not available')
def test_wrapper_toggle_refs():
class MyButton(Gtk.Button):
def __init__(self, height):
action.activate()
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
+ def test_action_group_error_handling(self):
+ action_group = Gtk.ActionGroup(name='TestActionGroup')
+ with pytest.raises(TypeError):
+ action_group.add_actions(42)
+
+ with pytest.raises(TypeError):
+ action_group.add_toggle_actions(42)
+
+ with pytest.raises(TypeError):
+ action_group.add_radio_actions(42)
+
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
+ def test_action_group_no_user_data(self):
+ action_group = Gtk.ActionGroup(name='TestActionGroup')
+
+ called = []
+
+ def test_action_callback_no_data(action):
+ called.append(action)
+
+ action_group.add_actions([
+ ('test-action1', None, 'Test Action 1',
+ None, None, test_action_callback_no_data)])
+ action_group.add_actions([('test2-action1',)])
+ action_group.get_action('test-action1').activate()
+
+ action_group.add_toggle_actions([
+ ('test-action2', None, 'Test Action 2',
+ None, None, test_action_callback_no_data)])
+ action_group.add_toggle_actions([('test2-action2',)])
+ action_group.get_action('test-action2').activate()
+
+ def test_action_callback_no_data_radio(action, current):
+ called.append(action)
+
+ action_group.add_radio_actions([
+ ('test-action3', None, 'Test Action 3', None, None, 0),
+ ('test-action4', None, 'Test Action 4', None, None, 1)],
+ 1, test_action_callback_no_data_radio)
+ action_group.add_radio_actions([('test2-action3',)])
+ action = action_group.get_action('test-action3')
+ assert action.get_current_value() == 1
+ action.activate()
+
+ assert len(called) == 3
+
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_uimanager(self):
self.assertEqual(Gtk.UIManager, gi.overrides.Gtk.UIManager)
ui = Gtk.UIManager()
ui.add_ui_from_string("""<ui>
<menubar name="menubar1"></menubar>
</ui>
-"""
-)
+""")
menubar = ui.get_widget("/menubar1")
self.assertEqual(type(menubar), Gtk.MenuBar)
self.assertEqual(ag, groups[-2])
self.assertEqual(ag2, groups[-1])
+ with pytest.raises(TypeError):
+ ui.add_ui_from_string(42)
+
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_uimanager_nonascii(self):
ui = Gtk.UIManager()
button = dialog.get_widget_for_response(Gtk.ResponseType.CLOSE)
self.assertEqual('gtk-close', button.get_label())
+ with pytest.raises(ValueError, match="even number"):
+ dialog.add_buttons('test-button2', 2, 'gtk-close')
+
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
+ def test_dialog_deprecated_attributes(self):
+ dialog = Gtk.Dialog()
+ assert dialog.action_area == dialog.get_action_area()
+ assert dialog.vbox == dialog.get_content_area()
+
def test_about_dialog(self):
dialog = Gtk.AboutDialog()
self.assertTrue(isinstance(dialog, Gtk.Dialog))
pixbuf = GdkPixbuf.Pixbuf()
Gtk.IconSet.new_from_pixbuf(pixbuf)
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.simplefilter('always')
+ Gtk.IconSet(pixbuf)
+ assert issubclass(warn[0].category, PyGTKDeprecationWarning)
+
def test_viewport(self):
vadjustment = Gtk.Adjustment()
hadjustment = Gtk.Adjustment()
[]),
}
+ class SignalTestObject(GObject.GObject):
+ __gtype_name__ = "GIOverrideSignalTestObject"
+
def test_add_from_string(self):
builder = Gtk.Builder()
+
+ with pytest.raises(TypeError):
+ builder.add_from_string(object())
+
builder.add_from_string(u"")
builder.add_from_string("")
builder.add_objects_from_string("", [''])
builder.add_objects_from_string(get_example(u"ä" * 1000), [''])
+ with pytest.raises(TypeError):
+ builder.add_objects_from_string(object(), [])
+
def test_extract_handler_and_args_object(self):
class Obj():
pass
Gtk._extract_handler_and_args,
obj, 'not_a_handler')
+ def test_extract_handler_and_args_type_mismatch(self):
+ with pytest.raises(TypeError):
+ Gtk._extract_handler_and_args({"foo": object()}, "foo")
+
+ with pytest.raises(TypeError):
+ Gtk._extract_handler_and_args({"foo": []}, "foo")
+
def test_builder_with_handler_and_args(self):
builder = Gtk.Builder()
builder.add_from_string("""
self.assertSequenceEqual(args_collector[0], (obj, 1, 2))
self.assertSequenceEqual(args_collector[1], (obj, ))
+ def test_builder_with_handler_object(self):
+ builder = Gtk.Builder()
+ builder.add_from_string("""
+ <interface>
+ <object class="GIOverrideSignalTestObject" id="foo"/>
+ <object class="GIOverrideSignalTest" id="object_sig_test">
+ <signal name="test-signal" handler="on_signal1" object="foo"/>
+ <signal name="test-signal" handler="on_signal2" after="yes" object="foo" />
+ </object>
+ </interface>
+ """)
+
+ args_collector = []
+
+ def on_signal(*args):
+ args_collector.append(args)
+
+ builder.connect_signals({'on_signal1': (on_signal, 1, 2),
+ 'on_signal2': on_signal})
+ obj, emitter = builder.get_objects()
+ emitter.emit("test-signal")
+ assert len(args_collector) == 2
+ assert args_collector[0] == (obj, 1, 2)
+ assert args_collector[1] == (obj, )
+
def test_builder(self):
self.assertEqual(Gtk.Builder, gi.overrides.Gtk.Builder)
self.assertEqual(signal_checker.after_sentinel, 2)
+@unittest.skipUnless(Gtk, 'Gtk not available')
+class TestTreeModelRow(unittest.TestCase):
+ def test_tree_model_row(self):
+ model = Gtk.TreeStore(int)
+ iter_ = model.append(None, [42])
+ path = model.get_path(iter_)
+ Gtk.TreeModelRow(model, iter_)
+ row = Gtk.TreeModelRow(model, path)
+
+ with pytest.raises(TypeError):
+ row["foo"]
+
+ with pytest.raises(TypeError):
+ Gtk.TreeModelRow(model, 42)
+
+ with pytest.raises(TypeError):
+ Gtk.TreeModelRow(42, path)
+
+ iter_ = model.append(None, [24])
+ row = Gtk.TreeModelRow(model, iter_)
+ assert row.previous[0] == 42
+ assert row.get_previous()[0] == 42
+ assert row.previous.previous is None
+
+
@ignore_gi_deprecation_warnings
@unittest.skipUnless(Gtk, 'Gtk not available')
class TestTreeModel(unittest.TestCase):
([0], [-1]), ([0, 0], [0]), ([0, 1], [None]), ([0, 2], [None]),
([0, 3], [4321]), ([0, 4], [1234])]
+ def test_tree_store_insert_before_none(self):
+ store = Gtk.TreeStore(object)
+ root = store.append(None)
+ sub = store.append(root)
+
+ iter_ = store.insert_before(None, None, [1])
+ assert store.get_path(iter_).get_indices() == [1]
+
+ iter_ = store.insert_before(root, None, [1])
+ assert store.get_path(iter_).get_indices() == [0, 1]
+
+ iter_ = store.insert_before(sub, None, [1])
+ assert store.get_path(iter_).get_indices() == [0, 0, 0]
+
+ iter_ = store.insert_before(None, root, [1])
+ assert store.get_path(iter_).get_indices() == [0]
+
+ iter_ = store.insert_before(None, sub, [1])
+ assert store.get_path(iter_).get_indices() == [1, 0]
+
def test_tree_store_insert_after(self):
store = Gtk.TreeStore(object)
signals = []
([0], [-1]), ([0, 0], [1234]), ([0, 1], [4321]),
([0, 2], [None]), ([0, 3], [None]), ([0, 4], [0])]
+ def test_tree_store_insert_after_none(self):
+ store = Gtk.TreeStore(object)
+ root = store.append(None)
+ sub = store.append(root)
+
+ iter_ = store.insert_after(None, None, [1])
+ assert store.get_path(iter_).get_indices() == [0]
+
+ iter_ = store.insert_after(root, None, [1])
+ assert store.get_path(iter_).get_indices() == [1, 0]
+
+ iter_ = store.insert_after(sub, None, [1])
+ assert store.get_path(iter_).get_indices() == [1, 1, 0]
+
+ iter_ = store.insert_after(None, root, [1])
+ assert store.get_path(iter_).get_indices() == [2]
+
+ iter_ = store.insert_after(None, sub, [1])
+ assert store.get_path(iter_).get_indices() == [1, 2]
+
def test_tree_path(self):
p1 = Gtk.TreePath()
p2 = Gtk.TreePath.new_first()
filtered[0][1] = 'ONE'
self.assertEqual(filtered[0][1], 'ONE')
+ def foo(store, iter_, data):
+ assert data is None
+ return False
+
+ filtered.set_visible_func(foo)
+ filtered.refilter()
+ assert len(filtered) == 0
+
def test_list_store_performance(self):
model = Gtk.ListStore(int, str)
filt = model.filter_new()
self.assertTrue(filt is not None)
+ def test_tree_store_set(self):
+ tree_store = Gtk.TreeStore(int, int)
+ iter_ = tree_store.append(None)
+ tree_store.set(iter_)
+ assert tree_store.get_value(iter_, 0) == 0
+ tree_store.set(iter_, 0, 42)
+ assert tree_store.get_value(iter_, 0) == 42
+ assert tree_store.get_value(iter_, 1) == 0
+ tree_store.set(iter_, 0, 42, 1, 24)
+ assert tree_store.get_value(iter_, 1) == 24
+ tree_store.set(iter_, 1, 124)
+ assert tree_store.get_value(iter_, 1) == 124
+
+ with pytest.raises(TypeError):
+ tree_store.set(iter_, 0, 42, "foo", 24)
+ with pytest.raises(TypeError):
+ tree_store.set(iter_, "foo")
+ with pytest.raises(TypeError):
+ tree_store.set(iter_, [1, 2, 3])
+ with pytest.raises(TypeError):
+ tree_store.set(iter_, 0, 42, 24)
+
+ def test_list_store_set(self):
+ list_store = Gtk.ListStore(int, int)
+ iter_ = list_store.append()
+ list_store.set(iter_)
+ assert list_store.get_value(iter_, 0) == 0
+ list_store.set(iter_, 0, 42)
+ assert list_store.get_value(iter_, 0) == 42
+ assert list_store.get_value(iter_, 1) == 0
+ list_store.set(iter_, 0, 42, 1, 24)
+ assert list_store.get_value(iter_, 1) == 24
+ list_store.set(iter_, 1, 124)
+ assert list_store.get_value(iter_, 1) == 124
+
+ with pytest.raises(TypeError):
+ list_store.set(iter_, 0, 42, "foo", 24)
+ with pytest.raises(TypeError):
+ list_store.set(iter_, "foo")
+ with pytest.raises(TypeError):
+ list_store.set(iter_, [1, 2, 3])
+ with pytest.raises(TypeError):
+ list_store.set(iter_, 0, 42, 24)
+
+ def test_set_default_sort_func(self):
+ list_store = Gtk.ListStore(int)
+ list_store.append([2])
+ list_store.append([1])
+
+ def sort_func(store, iter1, iter2, data):
+ assert data is None
+ return cmp(store[iter1][0], store[iter2][0])
+
+ list_store.set_default_sort_func(sort_func)
+ list_store.set_sort_column_id(
+ Gtk.TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, Gtk.SortType.ASCENDING)
+ assert [v[0] for v in list_store] == [1, 2]
+
+ def test_model_rows_reordered(self):
+ list_store = Gtk.ListStore(int)
+ list_store.append([2])
+ list_store.append([1])
+ list_store.rows_reordered(Gtk.TreePath.new_first(), None, [0, 1])
+ list_store.rows_reordered(0, None, [0, 1])
+
+ def test_model_set_row(self):
+ list_store = Gtk.ListStore(int, int)
+ list_store.append([1, 2])
+ iter_ = list_store.get_iter_first()
+ list_store.set_row(iter_, [3, 4])
+ assert list_store[0][:] == [3, 4]
+ list_store.set_row(iter_, [None, 7])
+ assert list_store[0][:] == [3, 7]
+ list_store.set_row(iter_, [None, GObject.Value(int, 9)])
+ assert list_store[0][:] == [3, 9]
+
+ def test_model_set_row_skip_on_none(self):
+ list_store = Gtk.ListStore(int, int, int, int)
+ list_store.append([1, 2, 3, 4])
+ iter_ = list_store.get_iter_first()
+ list_store.set_row(iter_, [None, 7, None, 9])
+ assert list_store[0][:] == [1, 7, 3, 9]
+
@unittest.skipIf(sys.platform == "darwin", "hangs")
@unittest.skipUnless(Gtk, 'Gtk not available')
self.assertEqual(m, store)
self.assertEqual(store.get_path(s), firstpath)
+ sel.unselect_all()
+ (m, s) = sel.get_selected()
+ assert s is None
+
+ sel.select_path(0)
+ m, r = sel.get_selected_rows()
+ assert m == store
+ assert len(r) == 1
+ assert r[0] == store[0].path
+
+ def test_scroll_to_cell(self):
+ store = Gtk.ListStore(int, str)
+ store.append((0, "foo"))
+ view = Gtk.TreeView()
+ view.set_model(store)
+ view.scroll_to_cell(store[0].path)
+ view.scroll_to_cell(0)
+
@unittest.skipUnless(Gtk, 'Gtk not available')
class TestTextBuffer(unittest.TestCase):
def test_text_buffer(self):
self.assertEqual(Gtk.TextBuffer, gi.overrides.Gtk.TextBuffer)
buffer = Gtk.TextBuffer()
+ assert buffer.get_tag_table() is not None
tag = buffer.create_tag('title', font='Sans 18')
self.assertEqual(tag.props.name, 'title')
self.assertRaises(ValueError, buffer.insert_with_tags_by_name,
buffer.get_start_iter(), 'HelloHello', 'unknowntag')
+ def test_insert(self):
+ buffer = Gtk.TextBuffer()
+ start = buffer.get_bounds()[0]
+ with pytest.raises(TypeError):
+ buffer.insert(start, 42)
+
+ with pytest.raises(TypeError):
+ buffer.insert_at_cursor(42)
+
def test_text_iter(self):
try:
starts_tag = Gtk.TextIter.starts_tag
@unittest.skipUnless(Gtk, 'Gtk not available')
+class TestPaned(unittest.TestCase):
+
+ def test_pack_defaults(self):
+ p = Gtk.Paned()
+ l1 = Gtk.Label()
+ l2 = Gtk.Label()
+ p.pack1(l1)
+ p.pack2(l2)
+ assert p.get_children() == [l1, l2]
+
+
+@unittest.skipUnless(Gtk, 'Gtk not available')
class TestContainer(unittest.TestCase):
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
from __future__ import absolute_import
import unittest
-import collections
+try:
+ from collections import abc
+except ImportError:
+ import collections as abc
import gi._gi as GIRepository
from gi.module import repository as repo
def test_object_info(self):
info = repo.find_by_name('GIMarshallingTests', 'Object')
self.assertEqual(info.get_parent(), repo.find_by_name('GObject', 'Object'))
- self.assertTrue(isinstance(info.get_methods(), collections.Iterable))
- self.assertTrue(isinstance(info.get_fields(), collections.Iterable))
- self.assertTrue(isinstance(info.get_interfaces(), collections.Iterable))
- self.assertTrue(isinstance(info.get_constants(), collections.Iterable))
- self.assertTrue(isinstance(info.get_vfuncs(), collections.Iterable))
- self.assertTrue(isinstance(info.get_properties(), collections.Iterable))
+ self.assertTrue(isinstance(info.get_methods(), abc.Iterable))
+ self.assertTrue(isinstance(info.get_fields(), abc.Iterable))
+ self.assertTrue(isinstance(info.get_interfaces(), abc.Iterable))
+ self.assertTrue(isinstance(info.get_constants(), abc.Iterable))
+ self.assertTrue(isinstance(info.get_vfuncs(), abc.Iterable))
+ self.assertTrue(isinstance(info.get_properties(), abc.Iterable))
self.assertFalse(info.get_abstract())
self.assertEqual(info.get_class_struct(), repo.find_by_name('GIMarshallingTests', 'ObjectClass'))
self.assertEqual(info.get_type_name(), 'GIMarshallingTestsObject')
def test_interface_info(self):
info = repo.find_by_name('GIMarshallingTests', 'Interface')
- self.assertTrue(isinstance(info.get_methods(), collections.Iterable))
- self.assertTrue(isinstance(info.get_vfuncs(), collections.Iterable))
- self.assertTrue(isinstance(info.get_constants(), collections.Iterable))
- self.assertTrue(isinstance(info.get_prerequisites(), collections.Iterable))
- self.assertTrue(isinstance(info.get_properties(), collections.Iterable))
- self.assertTrue(isinstance(info.get_signals(), collections.Iterable))
+ self.assertTrue(isinstance(info.get_methods(), abc.Iterable))
+ self.assertTrue(isinstance(info.get_vfuncs(), abc.Iterable))
+ self.assertTrue(isinstance(info.get_constants(), abc.Iterable))
+ self.assertTrue(isinstance(info.get_prerequisites(), abc.Iterable))
+ self.assertTrue(isinstance(info.get_properties(), abc.Iterable))
+ self.assertTrue(isinstance(info.get_signals(), abc.Iterable))
method = info.find_method('test_int8_in')
vfunc = info.find_vfunc('test_int8_in')
def test_struct_info(self):
info = repo.find_by_name('GIMarshallingTests', 'InterfaceIface')
self.assertTrue(isinstance(info, GIRepository.StructInfo))
- self.assertTrue(isinstance(info.get_fields(), collections.Iterable))
- self.assertTrue(isinstance(info.get_methods(), collections.Iterable))
+ self.assertTrue(isinstance(info.get_fields(), abc.Iterable))
+ self.assertTrue(isinstance(info.get_methods(), abc.Iterable))
self.assertTrue(isinstance(info.get_size(), int))
self.assertTrue(isinstance(info.get_alignment(), int))
self.assertTrue(info.is_gtype_struct())
self.assertFalse(info.is_foreign())
+ info = repo.find_by_name('GIMarshallingTests', 'SimpleStruct')
+ assert info.find_method("nope") is None
+ assert isinstance(info.find_method("method"), GIRepository.FunctionInfo)
+
+ assert info.find_field("nope") is None
+ assert isinstance(info.find_field("int8"), GIRepository.FieldInfo)
+
def test_enum_info(self):
info = repo.find_by_name('GIMarshallingTests', 'Enum')
self.assertTrue(isinstance(info, GIRepository.EnumInfo))
- self.assertTrue(isinstance(info.get_values(), collections.Iterable))
- self.assertTrue(isinstance(info.get_methods(), collections.Iterable))
+ self.assertTrue(isinstance(info.get_values(), abc.Iterable))
+ self.assertTrue(isinstance(info.get_methods(), abc.Iterable))
self.assertFalse(info.is_flags())
self.assertTrue(info.get_storage_type() > 0) # might be platform dependent
def test_union_info(self):
info = repo.find_by_name('GIMarshallingTests', 'Union')
self.assertTrue(isinstance(info, GIRepository.UnionInfo))
- self.assertTrue(isinstance(info.get_fields(), collections.Iterable))
- self.assertTrue(isinstance(info.get_methods(), collections.Iterable))
+ self.assertTrue(isinstance(info.get_fields(), abc.Iterable))
+ self.assertTrue(isinstance(info.get_methods(), abc.Iterable))
self.assertTrue(isinstance(info.get_size(), int))
+ self.assertTrue(isinstance(info.get_alignment(), int))
def test_type_info(self):
func_info = repo.find_by_name('GIMarshallingTests', 'array_fixed_out_struct')
def test_callable_info(self):
func_info = repo.find_by_name('GIMarshallingTests', 'array_fixed_out_struct')
self.assertTrue(hasattr(func_info, 'invoke'))
- self.assertTrue(isinstance(func_info.get_arguments(), collections.Iterable))
+ self.assertTrue(isinstance(func_info.get_arguments(), abc.Iterable))
self.assertEqual(func_info.get_caller_owns(), GIRepository.Transfer.NOTHING)
self.assertFalse(func_info.may_return_null())
self.assertEqual(func_info.get_return_type().get_tag(), GIRepository.TypeTag.VOID)
import unittest
import warnings
+import pytest
+
from gi.repository import GLib
from gi import PyGIDeprecationWarning
+from .helper import capture_gi_deprecation_warnings
+
+
+def test_child_watch_add_get_args_various():
+ cb = lambda pid, status: None
+ get_args = GLib._child_watch_add_get_args
+ pid = 42
+ with capture_gi_deprecation_warnings():
+ assert get_args(pid, cb, 2) == (0, pid, cb, (2,))
+
+ with pytest.raises(TypeError):
+ get_args(pid, cb, 2, 3, 4)
+
+ assert get_args(0, pid, 2, 3, function=cb) == (0, pid, cb, (2, 3))
+ assert get_args(0, pid, cb, 2, 3) == (0, pid, cb, (2, 3))
+ assert get_args(0, pid, cb, data=99) == (0, pid, cb, (99,))
+
+ with pytest.raises(TypeError):
+ get_args(0, pid, 24)
+
+ with pytest.raises(TypeError):
+ get_args(0, pid, cb, 2, 3, data=99)
+
@unittest.skipIf(os.name == "nt", "not on Windows")
class TestProcess(unittest.TestCase):