From 75167a7461b05c8237d1e5acc5ab794e12e41d0e Mon Sep 17 00:00:00 2001 From: DongHun Kwak Date: Tue, 30 Oct 2018 10:30:32 +0900 Subject: [PATCH] Imported Upstream version 3.29.3 --- .gitlab-ci.yml | 23 +++++++++-------- .gitlab-ci/Dockerfile | 8 +++--- .gitlab-ci/run-docker.sh | 4 +-- .gitlab-ci/test-docker.sh | 3 +++ .gitlab-ci/test-flatpak.sh | 6 +++++ .gitlab-ci/test-msys2.sh | 9 ++++--- NEWS | 36 ++++++++++++++++++++++++++ PKG-INFO | 2 +- PyGObject.egg-info/PKG-INFO | 2 +- PyGObject.egg-info/SOURCES.txt | 4 +++ docs/getting_started.rst | 15 +++++------ gi/_gtktemplate.py | 17 ++++++++++--- gi/overrides/GObject.py | 4 +++ gi/overrides/GdkPixbuf.py | 53 +++++++++++++++++++++++++++++++++++++++ gi/overrides/Gio.py | 35 ++++++++++++++++++-------- gi/overrides/Gtk.py | 10 +++++--- gi/overrides/meson.build | 1 + gi/pygi-argument.c | 2 ++ gi/pygi-basictype.c | 12 +++++++++ gi/pygi-info.c | 8 ++++++ gi/pygobject-object.c | 2 +- meson.build | 34 +++++++++++++++++++------ setup.cfg | 1 + setup.py | 3 +-- subprojects/glib.wrap | 4 +-- subprojects/pycairo.wrap | 4 +++ tests/__init__.py | 10 +++++--- tests/conftest.py | 2 +- tests/meson.build | 7 +++++- tests/test_cairo.py | 3 ++- tests/test_everything.py | 18 ++++++------- tests/test_gi.py | 1 + tests/test_gobject.py | 29 ++++++++++++++------- tests/test_gtk_template.py | 37 +++++++++++++++++++++++++++ tests/test_overrides_gdkpixbuf.py | 49 ++++++++++++++++++++++++++++++++++++ tests/test_source.py | 3 +-- tools/pygi-convert.sh | 16 ++++++------ 37 files changed, 386 insertions(+), 91 deletions(-) create mode 100755 .gitlab-ci/test-flatpak.sh create mode 100644 gi/overrides/GdkPixbuf.py create mode 100644 subprojects/pycairo.wrap create mode 100644 tests/test_overrides_gdkpixbuf.py diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f53bddf..3a25c6a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,4 @@ -image: registry.gitlab.gnome.org/gnome/pygobject/main:v6 +image: registry.gitlab.gnome.org/gnome/pygobject/main:v8 stages: - build_and_test @@ -34,7 +34,7 @@ coverage: paths: - coverage/ variables: - PYENV_VERSION: "3.6.5" + PYENV_VERSION: "3.6.6" script: - bash -x ./.gitlab-ci/coverage-docker.sh @@ -59,7 +59,6 @@ python2-mingw32: <<: *mingw-defaults python2-mingw64: - when: manual variables: PYTHON: "python2" MSYSTEM: "MINGW64" @@ -67,7 +66,6 @@ python2-mingw64: <<: *mingw-defaults python3-mingw32: - when: manual variables: PYTHON: "python3" MSYSTEM: "MINGW32" @@ -83,23 +81,22 @@ python3-mingw64: python2.7: variables: - PYENV_VERSION: "2.7.15" + PYENV_VERSION: "2.7.15-debug" <<: *defaults python3.5: - when: manual variables: - PYENV_VERSION: "3.5.5" + PYENV_VERSION: "3.5.6" <<: *defaults python3.6: variables: - PYENV_VERSION: "3.6.5" + PYENV_VERSION: "3.6.6" <<: *defaults python3.7: variables: - PYENV_VERSION: "3.7.0b3" + PYENV_VERSION: "3.7.0-debug" <<: *defaults pypy2: @@ -109,7 +106,6 @@ pypy2: <<: *defaults pypy3: - when: manual allow_failure: true variables: PYENV_VERSION: "pypy3.5-6.0.0" @@ -120,3 +116,10 @@ xenial-i386-py2: image: registry.gitlab.gnome.org/gnome/pygobject/old:v2 script: - bash -x ./.gitlab-ci/test-docker-old.sh + +gnome-master: + allow_failure: true + stage: build_and_test + image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:master + script: + - xvfb-run -a flatpak run --filesystem=host --share=network --socket=x11 --command=bash org.gnome.Sdk//master -x .gitlab-ci/test-flatpak.sh diff --git a/.gitlab-ci/Dockerfile b/.gitlab-ci/Dockerfile index cd1aa1b..a72c718 100644 --- a/.gitlab-ci/Dockerfile +++ b/.gitlab-ci/Dockerfile @@ -39,10 +39,10 @@ ENV PYTHON_CONFIGURE_OPTS="--enable-shared" RUN curl -L https://raw.githubusercontent.com/pyenv/pyenv-installer/master/bin/pyenv-installer | bash -RUN pyenv install 2.7.15 -RUN pyenv install 3.5.5 -RUN pyenv install 3.6.5 -RUN pyenv install 3.7.0b3 +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 pypy2.7-6.0.0 RUN pyenv install pypy3.5-6.0.0 diff --git a/.gitlab-ci/run-docker.sh b/.gitlab-ci/run-docker.sh index aed8831..bcfd707 100755 --- a/.gitlab-ci/run-docker.sh +++ b/.gitlab-ci/run-docker.sh @@ -2,10 +2,10 @@ set -e -TAG="registry.gitlab.gnome.org/gnome/pygobject/main:v6" +TAG="registry.gitlab.gnome.org/gnome/pygobject/main:v8" sudo docker build --build-arg HOST_USER_ID="$UID" --tag "${TAG}" \ --file "Dockerfile" . -sudo docker run -e PYENV_VERSION='3.6.5' --rm --security-opt label=disable \ +sudo docker run -e PYENV_VERSION='3.7.0-debug' --rm --security-opt label=disable \ --volume "$(pwd)/..:/home/user/app" --workdir "/home/user/app" \ --tty --interactive "${TAG}" bash diff --git a/.gitlab-ci/test-docker.sh b/.gitlab-ci/test-docker.sh index 46a195e..1a6dddb 100755 --- a/.gitlab-ci/test-docker.sh +++ b/.gitlab-ci/test-docker.sh @@ -15,6 +15,9 @@ export COVERAGE_FILE="${COV_DIR}/.coverage.${CI_JOB_NAME}" export CCACHE_BASEDIR="$(pwd)" export CCACHE_DIR="${CCACHE_BASEDIR}/_ccache" +# https://docs.python.org/3/using/cmdline.html#envvar-PYTHONDEVMODE +export PYTHONDEVMODE=1 + mkdir -p "${CCACHE_DIR}" mkdir -p "${COV_DIR}" diff --git a/.gitlab-ci/test-flatpak.sh b/.gitlab-ci/test-flatpak.sh new file mode 100755 index 0000000..3e3a992 --- /dev/null +++ b/.gitlab-ci/test-flatpak.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +set -e + +python3 -m pip install --user pytest +python3 setup.py test diff --git a/.gitlab-ci/test-msys2.sh b/.gitlab-ci/test-msys2.sh index f81064e..2b11aea 100755 --- a/.gitlab-ci/test-msys2.sh +++ b/.gitlab-ci/test-msys2.sh @@ -45,13 +45,16 @@ COV_KEY="${MSYSTEM}.${PYVER}" mkdir -p "${COV_DIR}" export COVERAGE_FILE="${COV_DIR}/.coverage.${COV_KEY}" +# https://docs.python.org/3/using/cmdline.html#envvar-PYTHONDEVMODE +export PYTHONDEVMODE=1 + $PYTHON setup.py build_tests MSYSTEM= $PYTHON -m coverage run tests/runtests.py -curl -O -J -L "https://github.com/linux-test-project/lcov/releases/download/v1.13/lcov-1.13.tar.gz" -tar -xvzf lcov-1.13.tar.gz +curl -O -J -L "https://github.com/linux-test-project/lcov/archive/master.tar.gz" +tar -xvzf lcov-master.tar.gz -./lcov-1.13/bin/lcov \ +./lcov-master/bin/lcov \ --rc lcov_branch_coverage=1 --no-external \ --directory . --capture --output-file \ "${COV_DIR}/${COV_KEY}.lcov" diff --git a/NEWS b/NEWS index fc87917..e8d7b5a 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,39 @@ +3.29.3 - 2018-08-16 +------------------- + +* meson: Support building pycairo as a subproject. :mr:`76` +* meson: Declare_dependency for use by potential superprojects + (:user:`Mathieu Duponchelle `) +* meson: Update glib wrap file. :mr:`80` (:user:`Carlos Soriano `) +* meson: Fix the Python 2 build not not use the system pycairo extension when + running tests. :issue:`242` +* pygi-convert.sh: Various fixes and updates. :mr:`77` :mr:`78` + (:user:`Sander Sweers `) +* Gtk.Template: Fix instantiation error when using the new code with older + PyGObject. :mr:`79` (:user:`Kai Willadsen `) +* Gtk.Template: Don't error out when loading a resource that is only available + in an overlay. :issue:`230` +* Fix various crashes when running against a debug Python 3.7 build. :mr:`82` + (:user:`Simon McVittie `) +* overrides: Allow calling GObject.Binding.unbind() multiple times with + GLib 2.58+. :issue:`240` +* overrides: Gio.ListStore overrides use splice() when adding/removing many + items with GLib 2.58+. :issue:`115` :mr:`83` +* Work around pylint reporting bogus warnings regarding a missing self + argument for normal functions. :issue:`217` +* Add override for GdkPixbuf.Pixbuf.new_from_data() to wrap new_from_bytes() + to work around a use after free. :issue:`225` :mr:`74` + + +3.28.3 - 2018-05-31 +------------------- + +* Fix Gio.Application leak in case no signal handler is set before. + :issue:`219` +* Squash critical warning when using array as hash value + (:user:`Philip Withnall `) + + 3.29.2 - 2018-05-16 ------------------- diff --git a/PKG-INFO b/PKG-INFO index 08b8816..c15d2b1 100644 --- a/PKG-INFO +++ b/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 1.2 Name: PyGObject -Version: 3.29.2 +Version: 3.29.3 Summary: Python bindings for GObject Introspection Home-page: https://pygobject.readthedocs.io Author: James Henstridge diff --git a/PyGObject.egg-info/PKG-INFO b/PyGObject.egg-info/PKG-INFO index 08b8816..c15d2b1 100644 --- a/PyGObject.egg-info/PKG-INFO +++ b/PyGObject.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 1.2 Name: PyGObject -Version: 3.29.2 +Version: 3.29.3 Summary: Python bindings for GObject Introspection Home-page: https://pygobject.readthedocs.io Author: James Henstridge diff --git a/PyGObject.egg-info/SOURCES.txt b/PyGObject.egg-info/SOURCES.txt index bc687c6..ae9b52d 100644 --- a/PyGObject.egg-info/SOURCES.txt +++ b/PyGObject.egg-info/SOURCES.txt @@ -19,6 +19,7 @@ setup.py .gitlab-ci/run-docker.sh .gitlab-ci/test-docker-old.sh .gitlab-ci/test-docker.sh +.gitlab-ci/test-flatpak.sh .gitlab-ci/test-msys2.sh PyGObject.egg-info/PKG-INFO PyGObject.egg-info/SOURCES.txt @@ -237,6 +238,7 @@ gi/overrides/GIMarshallingTests.py gi/overrides/GLib.py gi/overrides/GObject.py gi/overrides/Gdk.py +gi/overrides/GdkPixbuf.py gi/overrides/Gio.py gi/overrides/Gtk.py gi/overrides/Pango.py @@ -252,6 +254,7 @@ pygtkcompat/pygtkcompat.py subprojects/glib.wrap subprojects/gobject-introspection.wrap subprojects/libffi.wrap +subprojects/pycairo.wrap tests/__init__.py tests/conftest.py tests/gimarshallingtestsextra.c @@ -291,6 +294,7 @@ tests/test_object_marshaling.py tests/test_option.py tests/test_ossig.py tests/test_overrides_gdk.py +tests/test_overrides_gdkpixbuf.py tests/test_overrides_gio.py tests/test_overrides_glib.py tests/test_overrides_gtk.py diff --git a/docs/getting_started.rst b/docs/getting_started.rst index 4cee81a..eabde65 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -36,13 +36,14 @@ and their dependencies. Follow the instructions for your platform below. |windows-logo| Windows ---------------------- -1) Go to http://www.msys2.org/ and download the x86_64 installer -2) Follow the instructions on the page for setting up the basic environment -3) Run ``C:\msys64\mingw32.exe`` - a terminal window should pop up -4) Execute ``pacman -S mingw-w64-i686-gtk3 mingw-w64-i686-python2-gobject mingw-w64-i686-python3-gobject`` -5) To test that GTK+3 is working you can run ``gtk3-demo`` -6) Copy the ``hello.py`` script you created to ``C:\msys64\home\`` -7) In the mingw32 terminal execute ``python3 hello.py`` - a window should appear. +#) Go to http://www.msys2.org/ and download the x86_64 installer +#) Follow the instructions on the page for setting up the basic environment +#) Run ``C:\msys64\mingw32.exe`` - a terminal window should pop up +#) Execute ``pacman -Suy`` +#) Execute ``pacman -S mingw-w64-i686-gtk3 mingw-w64-i686-python2-gobject mingw-w64-i686-python3-gobject`` +#) To test that GTK+3 is working you can run ``gtk3-demo`` +#) Copy the ``hello.py`` script you created to ``C:\msys64\home\`` +#) In the mingw32 terminal execute ``python3 hello.py`` - a window should appear. .. figure:: images/start_windows.png :scale: 60% diff --git a/gi/_gtktemplate.py b/gi/_gtktemplate.py index df9afdb..efaca33 100644 --- a/gi/_gtktemplate.py +++ b/gi/_gtktemplate.py @@ -99,7 +99,7 @@ def register_template(cls): def init_template(self, cls, base_init_template): - cls.init_template = lambda s: None + self.init_template = lambda s: None if self.__class__ is not cls: raise TypeError( @@ -145,6 +145,18 @@ class Callback(object): return CallThing(self._name, func) +def validate_resource_path(path): + """Raises GLib.Error in case the resource doesn't exist""" + + try: + Gio.resources_get_info(path, Gio.ResourceLookupFlags.NONE) + except GLib.Error: + # resources_get_info() doesn't handle overlays but we keep using it + # as a fast path. + # https://gitlab.gnome.org/GNOME/pygobject/issues/230 + Gio.resources_lookup_data(path, Gio.ResourceLookupFlags.NONE) + + class Template(object): def __init__(self, **kwargs): @@ -204,8 +216,7 @@ class Template(object): register_template(cls) return cls elif self.resource_path is not None: - Gio.resources_get_info( - self.resource_path, Gio.ResourceLookupFlags.NONE) + validate_resource_path(self.resource_path) cls.set_template_from_resource(self.resource_path) register_template(cls) return cls diff --git a/gi/overrides/GObject.py b/gi/overrides/GObject.py index 312119d..089b2a4 100644 --- a/gi/overrides/GObject.py +++ b/gi/overrides/GObject.py @@ -706,6 +706,10 @@ class Binding(GObjectModule.Binding): return self def unbind(self): + # Fixed in newer glib + if (GLib.MAJOR_VERSION, GLib.MINOR_VERSION, GLib.MICRO_VERSION) >= (2, 57, 2): + return super(Binding, self).unbind() + if hasattr(self, '_unbound'): raise ValueError('binding has already been cleared out') else: diff --git a/gi/overrides/GdkPixbuf.py b/gi/overrides/GdkPixbuf.py new file mode 100644 index 0000000..0f6cd75 --- /dev/null +++ b/gi/overrides/GdkPixbuf.py @@ -0,0 +1,53 @@ +# Copyright 2018 Christoph Reiter +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +# USA + +import warnings + +from gi import PyGIDeprecationWarning +from gi.repository import GLib + +from ..overrides import override +from ..module import get_introspection_module + + +GdkPixbuf = get_introspection_module('GdkPixbuf') +__all__ = [] + + +@override +class Pixbuf(GdkPixbuf.Pixbuf): + + @classmethod + def new_from_data( + cls, data, colorspace, has_alpha, bits_per_sample, + width, height, rowstride, + destroy_fn=None, *destroy_fn_data): + + if destroy_fn is not None: + w = PyGIDeprecationWarning("destroy_fn argument deprecated") + warnings.warn(w) + if destroy_fn_data: + w = PyGIDeprecationWarning("destroy_fn_data argument deprecated") + warnings.warn(w) + + data = GLib.Bytes.new(data) + return cls.new_from_bytes( + data, colorspace, has_alpha, bits_per_sample, + width, height, rowstride) + + +__all__.append('Pixbuf') diff --git a/gi/overrides/Gio.py b/gi/overrides/Gio.py index b282c2a..5c19ef2 100644 --- a/gi/overrides/Gio.py +++ b/gi/overrides/Gio.py @@ -413,6 +413,19 @@ def _wrap_list_store_sort_func(func): return wrap +if (GLib.MAJOR_VERSION, GLib.MINOR_VERSION, GLib.MICRO_VERSION) < (2, 57, 1): + # The "additions" functionality in splice() was broken in older glib + # https://bugzilla.gnome.org/show_bug.cgi?id=795307 + # This is a slower fallback which emits a signal per added item + def _list_store_splice(self, position, n_removals, additions): + self.splice(position, n_removals, []) + for v in reversed(additions): + self.insert(position, v) +else: + def _list_store_splice(self, position, n_removals, additions): + self.splice(position, n_removals, additions) + + class ListStore(Gio.ListStore): def sort(self, compare_func, *user_data): @@ -428,9 +441,9 @@ class ListStore(Gio.ListStore): if isinstance(key, slice): start, stop, step = key.indices(len(self)) if step == 1: - self.splice(start, max(stop - start, 0), []) + _list_store_splice(self, start, max(stop - start, 0), []) elif step == -1: - self.splice(stop + 1, max(start - stop, 0), []) + _list_store_splice(self, stop + 1, max(start - stop, 0), []) else: for i in sorted(xrange(start, stop, step), reverse=True): self.remove(i) @@ -456,16 +469,19 @@ class ListStore(Gio.ListStore): start, stop, step = key.indices(len(self)) if step == 1: - self.__delitem__(key) - for v in reversed(valuelist): - self.insert(start, v) + _list_store_splice( + self, start, max(stop - start, 0), valuelist) else: indices = list(xrange(start, stop, step)) if len(indices) != len(valuelist): raise ValueError - for i, v in zip(indices, valuelist): - self.remove(i) - self.insert(i, v) + + if step == -1: + _list_store_splice( + self, stop + 1, max(start - stop, 0), valuelist[::-1]) + else: + for i, v in zip(indices, valuelist): + _list_store_splice(self, i, 1, [v]) elif isinstance(key, int): if key < 0: key += len(self) @@ -478,8 +494,7 @@ class ListStore(Gio.ListStore): "Expected type %s.%s" % ( pytype.__module__, pytype.__name__)) - self.remove(key) - self.insert(key, value) + _list_store_splice(self, key, 1, [value]) else: raise TypeError diff --git a/gi/overrides/Gtk.py b/gi/overrides/Gtk.py index 612c07d..05da18a 100644 --- a/gi/overrides/Gtk.py +++ b/gi/overrides/Gtk.py @@ -19,10 +19,14 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 # USA -import collections import sys import warnings +if sys.version_info[0] == 2: + import collections as abc +else: + from collections import abc + from gi.repository import GObject from .._ossighelper import wakeup_on_signal, register_sigint_fallback from .._gtktemplate import Template @@ -77,7 +81,7 @@ __all__.append('_construct_target_list') def _extract_handler_and_args(obj_or_map, handler_name): handler = None - if isinstance(obj_or_map, collections.Mapping): + if isinstance(obj_or_map, abc.Mapping): handler = obj_or_map.get(handler_name, None) else: handler = getattr(obj_or_map, handler_name, None) @@ -86,7 +90,7 @@ def _extract_handler_and_args(obj_or_map, handler_name): raise AttributeError('Handler %s not found' % handler_name) args = () - if isinstance(handler, collections.Sequence): + if isinstance(handler, abc.Sequence): if len(handler) == 0: raise TypeError("Handler %s tuple can not be empty" % handler) args = handler[1:] diff --git a/gi/overrides/meson.build b/gi/overrides/meson.build index b8ecae9..6ff073f 100644 --- a/gi/overrides/meson.build +++ b/gi/overrides/meson.build @@ -2,6 +2,7 @@ python_sources = [ 'GLib.py', 'Gtk.py', 'Gdk.py', + 'GdkPixbuf.py', 'GObject.py', 'Gio.py', 'GIMarshallingTests.py', diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c index cbec0dd..76ce8b4 100644 --- a/gi/pygi-argument.c +++ b/gi/pygi-argument.c @@ -144,6 +144,7 @@ _pygi_hash_pointer_to_arg (GIArgument *arg, case GI_TYPE_TAG_UTF8: case GI_TYPE_TAG_FILENAME: case GI_TYPE_TAG_INTERFACE: + case GI_TYPE_TAG_ARRAY: break; default: g_critical ("Unsupported type %s", g_type_tag_to_string(type_tag)); @@ -174,6 +175,7 @@ _pygi_arg_to_hash_pointer (const GIArgument *arg, case GI_TYPE_TAG_UTF8: case GI_TYPE_TAG_FILENAME: case GI_TYPE_TAG_INTERFACE: + case GI_TYPE_TAG_ARRAY: return arg->v_pointer; default: g_critical ("Unsupported type %s", g_type_tag_to_string(type_tag)); diff --git a/gi/pygi-basictype.c b/gi/pygi-basictype.c index 3ffd711..82b43c5 100644 --- a/gi/pygi-basictype.c +++ b/gi/pygi-basictype.c @@ -579,6 +579,7 @@ pygi_gint_from_py (PyObject *object, gint *result) return TRUE; overflow: + PyErr_Clear (); pygi_pyerr_format ( PyExc_OverflowError, "%S not in range %d to %d", number, (int)G_MININT, (int)G_MAXINT); @@ -617,6 +618,7 @@ pygi_guint_from_py (PyObject *object, guint *result) return TRUE; overflow: + PyErr_Clear (); pygi_pyerr_format ( PyExc_OverflowError, "%S not in range %ld to %lu", number, (long)0, (unsigned long)G_MAXUINT); @@ -659,6 +661,7 @@ pygi_glong_from_py (PyObject *object, glong *result) return TRUE; overflow: + PyErr_Clear (); pygi_pyerr_format ( PyExc_OverflowError, "%S not in range %ld to %ld", number, (long)G_MINLONG, (long)G_MAXLONG); @@ -695,6 +698,7 @@ pygi_gulong_from_py (PyObject *object, gulong *result) return TRUE; overflow: + PyErr_Clear (); pygi_pyerr_format ( PyExc_OverflowError, "%S not in range %ld to %lu", number, (long)0, (unsigned long)G_MAXULONG); @@ -746,6 +750,7 @@ pygi_gint8_from_py (PyObject *object, gint8 *result) return TRUE; overflow: + PyErr_Clear (); pygi_pyerr_format ( PyExc_OverflowError, "%S not in range %ld to %ld", number, (long)G_MININT8, (long)G_MAXINT8); @@ -794,6 +799,7 @@ pygi_guint8_from_py (PyObject *object, guint8 *result) return TRUE; overflow: + PyErr_Clear (); pygi_pyerr_format ( PyExc_OverflowError, "%S not in range %ld to %ld", number, (long)0, (long)G_MAXUINT8); @@ -832,6 +838,7 @@ pygi_gint16_from_py (PyObject *object, gint16 *result) return TRUE; overflow: + PyErr_Clear (); pygi_pyerr_format ( PyExc_OverflowError, "%S not in range %ld to %ld", number, (long)G_MININT16, (long)G_MAXINT16); @@ -870,6 +877,7 @@ pygi_guint16_from_py (PyObject *object, guint16 *result) return TRUE; overflow: + PyErr_Clear (); pygi_pyerr_format ( PyExc_OverflowError, "%S not in range %ld to %ld", number, (long)0, (long)G_MAXUINT16); @@ -908,6 +916,7 @@ pygi_gint32_from_py (PyObject *object, gint32 *result) return TRUE; overflow: + PyErr_Clear (); pygi_pyerr_format ( PyExc_OverflowError, "%S not in range %ld to %ld", number, (long)G_MININT32, (long)G_MAXINT32); @@ -946,6 +955,7 @@ pygi_guint32_from_py (PyObject *object, guint32 *result) return TRUE; overflow: + PyErr_Clear (); pygi_pyerr_format ( PyExc_OverflowError, "%S not in range %ld to %lu", number, (long)0, (unsigned long)G_MAXUINT32); @@ -991,6 +1001,7 @@ pygi_gint64_from_py (PyObject *object, gint64 *result) return TRUE; overflow: + PyErr_Clear (); min = pygi_gint64_to_py (G_MININT64); max = pygi_gint64_to_py (G_MAXINT64); pygi_pyerr_format ( @@ -1036,6 +1047,7 @@ pygi_guint64_from_py (PyObject *object, guint64 *result) return TRUE; overflow: + PyErr_Clear (); max = pygi_guint64_to_py (G_MAXUINT64); pygi_pyerr_format ( PyExc_OverflowError, "%S not in range %ld to %S", diff --git a/gi/pygi-info.c b/gi/pygi-info.c index 7010158..4fca825 100644 --- a/gi/pygi-info.c +++ b/gi/pygi-info.c @@ -2308,10 +2308,18 @@ pygi_info_register_types (PyObject *m) _PyGI_REGISTER_TYPE (m, PyGICallableInfo_Type, CallableInfo, PyGIBaseInfo_Type); + // FIXME: this is to work around a pylint issue + // https://gitlab.gnome.org/GNOME/pygobject/issues/217 +#ifndef PYPY_VERSION + _PyGI_REGISTER_TYPE (m, PyGIFunctionInfo_Type, FunctionInfo, + PyGICallableInfo_Type); +#endif PyGIFunctionInfo_Type.tp_call = (ternaryfunc) _function_info_call; PyGIFunctionInfo_Type.tp_descr_get = (descrgetfunc) _function_info_descr_get; +#ifdef PYPY_VERSION _PyGI_REGISTER_TYPE (m, PyGIFunctionInfo_Type, FunctionInfo, PyGICallableInfo_Type); +#endif PyGIVFuncInfo_Type.tp_descr_get = (descrgetfunc) _vfunc_info_descr_get; _PyGI_REGISTER_TYPE (m, PyGIVFuncInfo_Type, VFuncInfo, diff --git a/gi/pygobject-object.c b/gi/pygobject-object.c index 02f2478..dbf46e1 100644 --- a/gi/pygobject-object.c +++ b/gi/pygobject-object.c @@ -106,7 +106,7 @@ pygobject_data_free(PyGObjectData *data) /* This function may be called after the python interpreter has already * been shut down. If this happens, we cannot do any python calls, so just * free the memory. */ - PyGILState_STATE state; + PyGILState_STATE state = 0; PyThreadState *_save = NULL; gboolean state_saved; GSList *closures, *tmp; diff --git a/meson.build b/meson.build index d3cb9b0..4e1faff 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('pygobject', 'c', - version : '3.29.2', + version : '3.29.3', meson_version : '>= 0.46.0', default_options : [ 'warning_level=1', 'buildtype=debugoptimized']) @@ -42,10 +42,17 @@ if with_pycairo cairo_gobject_dep = dependency('cairo-gobject') if python.language_version().version_compare('>= 3.0') - pycairo_dep = dependency('py3cairo', version : pycairo_version_req) + pycairo_name = 'py3cairo' else - pycairo_dep = dependency('pycairo', version : pycairo_version_req) + pycairo_name = 'pycairo' endif + + pycairo_dep = dependency( + pycairo_name, + version: pycairo_version_req, + fallback: ['pycairo', 'pycairo_dep'], + default_options: ['python=' + get_option('python')], + ) endif cc = meson.get_compiler('c') @@ -62,7 +69,6 @@ main_c_args = [ '-Wformat-security', '-Wimplicit-function-declaration', '-Winit-self', - '-Winline', '-Wjump-misses-init', '-Wlogical-op', '-Wmissing-declarations', @@ -135,10 +141,24 @@ configure_file(input : 'pygobject-@0@.pc.in'.format(platform_version), configuration : pkgconf, install_dir : pkg_install_dir) +pygobject_dep = declare_dependency( + include_directories: include_directories('gi'), + dependencies: [gobject_dep, ffi_dep], + version: meson.project_version(), +) + +if pygobject_version_minor.is_odd() + py_version = '@0@.dev0'.format(pygobject_version) +else + py_version = pygobject_version +endif + +pkginfo_conf = configuration_data() +pkginfo_conf.set('VERSION', py_version) configure_file(input : 'PKG-INFO.in', - output : 'pygobject-@0@-py@1@.egg-info'.format(pygobject_version, python.language_version()), - configuration : pkgconf, - install_dir : python.get_install_dir(subdir : 'gi')) + output : 'PyGObject-@0@.egg-info'.format(py_version), + configuration : pkginfo_conf, + install_dir : python.get_install_dir()) subdir('gi') subdir('pygtkcompat') diff --git a/setup.cfg b/setup.cfg index 1563cd3..2f80f59 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,6 @@ [flake8] ignore = E501,E123,E124,E402,E731,E722 +exclude = subprojects [coverage:run] branch = True diff --git a/setup.py b/setup.py index b38a43e..38bc2e4 100755 --- a/setup.py +++ b/setup.py @@ -39,7 +39,7 @@ from distutils import dir_util, log from distutils.spawn import find_executable -PYGOBJECT_VERISON = "3.29.2" +PYGOBJECT_VERISON = "3.29.3" GLIB_VERSION_REQUIRED = "2.38.0" GI_VERSION_REQUIRED = "1.46.0" PYCAIRO_VERSION_REQUIRED = "1.11.1" @@ -893,7 +893,6 @@ def add_ext_compiler_flags(ext, compiler, _cache={}): "-Wformat-security", "-Wimplicit-function-declaration", "-Winit-self", - "-Winline", "-Wjump-misses-init", "-Wlogical-op", "-Wmissing-declarations", diff --git a/subprojects/glib.wrap b/subprojects/glib.wrap index c86fea7..87021ae 100644 --- a/subprojects/glib.wrap +++ b/subprojects/glib.wrap @@ -1,5 +1,5 @@ [wrap-git] directory=glib -url=git://git.gnome.org/glib -push-url=ssh://git.gnome.org/git/glib +url=https://gitlab.gnome.org/GNOME/glib.git +push-url=git@gitlab.gnome.org:GNOME/glib.git revision=master diff --git a/subprojects/pycairo.wrap b/subprojects/pycairo.wrap new file mode 100644 index 0000000..87eac57 --- /dev/null +++ b/subprojects/pycairo.wrap @@ -0,0 +1,4 @@ +[wrap-git] +directory=pycairo +url=https://github.com/pygobject/pycairo.git +revision=master diff --git a/tests/__init__.py b/tests/__init__.py index eaa541d..1611db3 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -12,15 +12,19 @@ import imp class GIImport: def find_module(self, fullname, path=None): - if fullname == 'gi._gi': + if fullname in ('gi._gi', 'gi._gi_cairo'): return self return None def load_module(self, name): if name in sys.modules: return sys.modules[name] - module_info = imp.find_module('_gi') - module = imp.load_module(name, *module_info) + fp, pathname, description = imp.find_module(name.split('.')[-1]) + try: + module = imp.load_module(name, fp, pathname, description) + finally: + if fp: + fp.close() sys.modules[name] = module return module diff --git a/tests/conftest.py b/tests/conftest.py index c08a563..4d0cc6b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -9,7 +9,7 @@ import pytest from gi._compat import reraise -@pytest.hookimpl(hookwrapper=True) +@pytest.hookimpl(hookwrapper=True, tryfirst=True) def pytest_runtest_call(item): """A pytest hook which takes over sys.excepthook and raises any uncaught exception (with PyGObject this happesn often when we get called from C, diff --git a/tests/meson.build b/tests/meson.build index 5933ddb..f72ead0 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -118,7 +118,12 @@ endif if host_machine.system() == 'windows' envdata.prepend('PATH', join_paths(get_option('prefix'), get_option('bindir'))) endif -envdata.append('PYTHONPATH', join_paths(meson.current_build_dir(), '..')) + +python_paths = [join_paths(meson.current_build_dir(), '..')] +if with_pycairo and pycairo_dep.type_name() == 'internal' + python_paths += [join_paths(meson.build_root(), 'subprojects', 'pycairo')] +endif +envdata.append('PYTHONPATH', python_paths) envdata.append('TESTS_BUILDDIR', meson.current_build_dir()) test('pygobject-test-suite', python, diff --git a/tests/test_cairo.py b/tests/test_cairo.py index a34798f..18e5d62 100644 --- a/tests/test_cairo.py +++ b/tests/test_cairo.py @@ -52,7 +52,8 @@ class Test(unittest.TestCase): def test_cairo_path_full_return(self): path = Regress.test_cairo_path_full_return() - assert isinstance(path, cairo.Path) + if hasattr(cairo, "Path"): # pycairo 1.15.1+ + assert isinstance(path, cairo.Path) def test_cairo_path_none_in(self): surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) diff --git a/tests/test_everything.py b/tests/test_everything.py index bccc94b..68e8765 100644 --- a/tests/test_everything.py +++ b/tests/test_everything.py @@ -13,6 +13,7 @@ import os import re import platform import gc +import timeit import pytest @@ -1406,44 +1407,43 @@ class TestBoxed(unittest.TestCase): class TestTortureProfile(unittest.TestCase): def test_torture_profile(self): - import time total_time = 0 print("") object_ = Everything.TestObj() sys.stdout.write("\ttorture test 1 (10000 iterations): ") - start_time = time.clock() + start_time = timeit.default_timer() for i in range(10000): (y, z, q) = object_.torture_signature_0(5000, "Torture Test 1", 12345) - end_time = time.clock() + end_time = timeit.default_timer() delta_time = end_time - start_time total_time += delta_time print("%f secs" % delta_time) sys.stdout.write("\ttorture test 2 (10000 iterations): ") - start_time = time.clock() + start_time = timeit.default_timer() for i in range(10000): (y, z, q) = Everything.TestObj().torture_signature_0( 5000, "Torture Test 2", 12345) - end_time = time.clock() + end_time = timeit.default_timer() delta_time = end_time - start_time total_time += delta_time print("%f secs" % delta_time) sys.stdout.write("\ttorture test 3 (10000 iterations): ") - start_time = time.clock() + start_time = timeit.default_timer() for i in range(10000): try: (y, z, q) = object_.torture_signature_1( 5000, "Torture Test 3", 12345) except: pass - end_time = time.clock() + end_time = timeit.default_timer() delta_time = end_time - start_time total_time += delta_time print("%f secs" % delta_time) @@ -1454,11 +1454,11 @@ class TestTortureProfile(unittest.TestCase): return 0 userdata = [1, 2, 3, 4] - start_time = time.clock() + start_time = timeit.default_timer() for i in range(10000): (y, z, q) = Everything.test_torture_signature_2( 5000, callback, userdata, "Torture Test 4", 12345) - end_time = time.clock() + end_time = timeit.default_timer() delta_time = end_time - start_time total_time += delta_time print("%f secs" % delta_time) diff --git a/tests/test_gi.py b/tests/test_gi.py index 3d87662..2b6f3c0 100644 --- a/tests/test_gi.py +++ b/tests/test_gi.py @@ -1646,6 +1646,7 @@ class TestGValue(unittest.TestCase): gc.collect() assert obj.__grefcount__ == grefcount + @unittest.skipIf(platform.python_implementation() == "PyPy" and PY3, "fixme") def test_gvalue_gobject_ref_counts(self): # Tests a GObject held by a GValue obj = GObject.Object() diff --git a/tests/test_gobject.py b/tests/test_gobject.py index 51256f8..17106da 100644 --- a/tests/test_gobject.py +++ b/tests/test_gobject.py @@ -589,8 +589,16 @@ class TestPropertyBindings(unittest.TestCase): self.assertEqual(self.source.int_prop, 10) self.assertEqual(self.target.int_prop, 1) - # An already unbound BindingWeakRef will raise if unbind is attempted a second time. - self.assertRaises(ValueError, binding.unbind) + glib_version = (GLib.MAJOR_VERSION, GLib.MINOR_VERSION, GLib.MICRO_VERSION) + + # calling unbind() on an already unbound binding + if glib_version >= (2, 57, 2): + # Fixed in newer glib: + # https://gitlab.gnome.org/GNOME/glib/merge_requests/244 + for i in range(10): + binding.unbind() + else: + self.assertRaises(ValueError, binding.unbind) def test_reference_counts(self): self.assertEqual(self.source.__grefcount__, 1) @@ -714,13 +722,16 @@ class TestGValue(unittest.TestCase): self.assertEqual(testhelper.value_array_get_nth_type(value, 1), GObject.TYPE_STRING) def test_value_array_append_gvalue(self): - arr = GObject.ValueArray.new(0) - arr.append(GObject.Value(GObject.TYPE_UINT, 0xffffffff)) - arr.append(GObject.Value(GObject.TYPE_STRING, 'foo_bar')) - self.assertEqual(arr.get_nth(0), 0xffffffff) - self.assertEqual(arr.get_nth(1), 'foo_bar') - self.assertEqual(testhelper.value_array_get_nth_type(arr, 0), GObject.TYPE_UINT) - self.assertEqual(testhelper.value_array_get_nth_type(arr, 1), GObject.TYPE_STRING) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + + arr = GObject.ValueArray.new(0) + arr.append(GObject.Value(GObject.TYPE_UINT, 0xffffffff)) + arr.append(GObject.Value(GObject.TYPE_STRING, 'foo_bar')) + self.assertEqual(arr.get_nth(0), 0xffffffff) + self.assertEqual(arr.get_nth(1), 'foo_bar') + self.assertEqual(testhelper.value_array_get_nth_type(arr, 0), GObject.TYPE_UINT) + self.assertEqual(testhelper.value_array_get_nth_type(arr, 1), GObject.TYPE_STRING) def test_gerror_boxing(self): error = GLib.Error('test message', domain='mydomain', code=42) diff --git a/tests/test_gtk_template.py b/tests/test_gtk_template.py index 6f112dd..f0cc963 100644 --- a/tests/test_gtk_template.py +++ b/tests/test_gtk_template.py @@ -79,9 +79,46 @@ def test_allow_init_template_call(): super(Foo, self).__init__() self.init_template() + # Stop current pygobject from handling the initialisation + del Foo.__dontuse_ginstance_init__ + Foo() +def test_init_template_second_instance(): + type_name = new_gtype_name() + + xml = """\ + + + +""".format(type_name) + + @Gtk.Template.from_string(xml) + class Foo(Gtk.Box): + __gtype_name__ = type_name + + label = Gtk.Template.Child("label") + + def __init__(self): + super(Foo, self).__init__() + self.init_template() + + # Stop current pygobject from handling the initialisation + del Foo.__dontuse_ginstance_init__ + + foo = Foo() + assert isinstance(foo.label, Gtk.Label) + + foo2 = Foo() + assert isinstance(foo2.label, Gtk.Label) + + def test_main_example(): type_name = new_gtype_name() diff --git a/tests/test_overrides_gdkpixbuf.py b/tests/test_overrides_gdkpixbuf.py new file mode 100644 index 0000000..5b2d370 --- /dev/null +++ b/tests/test_overrides_gdkpixbuf.py @@ -0,0 +1,49 @@ +# Copyright 2018 Christoph Reiter +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +# USA + +from __future__ import absolute_import + +import pytest + +from gi import PyGIDeprecationWarning +GdkPixbuf = pytest.importorskip("gi.repository.GdkPixbuf") + + +def test_new_from_data(): + width = 600 + height = 32769 + pixbuf = GdkPixbuf.Pixbuf.new( + GdkPixbuf.Colorspace.RGB, True, 8, width, height) + pixels = pixbuf.get_pixels() + new_pixbuf = GdkPixbuf.Pixbuf.new_from_data( + pixels, GdkPixbuf.Colorspace.RGB, True, 8, + pixbuf.get_width(), pixbuf.get_height(), pixbuf.get_rowstride()) + del pixbuf + del pixels + new_pixels = new_pixbuf.get_pixels() + assert len(new_pixels) == width * height * 4 + + +def test_new_from_data_deprecated_args(): + GdkPixbuf.Pixbuf.new_from_data(b"1234", 0, True, 8, 1, 1, 4) + GdkPixbuf.Pixbuf.new_from_data(b"1234", 0, True, 8, 1, 1, 4, None) + with pytest.warns(PyGIDeprecationWarning, match=".*destroy_fn.*"): + GdkPixbuf.Pixbuf.new_from_data( + b"1234", 0, True, 8, 1, 1, 4, object(), object(), object()) + with pytest.warns(PyGIDeprecationWarning, match=".*destroy_fn_data.*"): + GdkPixbuf.Pixbuf.new_from_data( + b"1234", 0, True, 8, 1, 1, 4, object(), object(), object()) diff --git a/tests/test_source.py b/tests/test_source.py index e4e6399..1a600fd 100644 --- a/tests/test_source.py +++ b/tests/test_source.py @@ -212,8 +212,7 @@ class TestSource(unittest.TestCase): self.finalized = True source = S() - id = source.attach() - print('source id:', id) + source.attach() self.assertFalse(self.finalized) self.assertFalse(source.is_destroyed()) diff --git a/tools/pygi-convert.sh b/tools/pygi-convert.sh index 43af662..8a2160a 100755 --- a/tools/pygi-convert.sh +++ b/tools/pygi-convert.sh @@ -209,15 +209,13 @@ for f in $FILES_TO_CONVERT; do -pe "s/Gio.OUTPUT_STREAM_SPLICE_/Gio.OutputStreamSpliceFlags./g;" \ -pe "s/Gio.vfs_/Gio.Vfs./g;" \ \ - -pe "#s/import glib\n/from gi.repository import GLib\n/g;" \ - -pe "#s/(?