+image: registry.gitlab.gnome.org/gnome/pygobject/main:v6
+
stages:
- build_and_test
- coverage
.defaults: &defaults
stage: build_and_test
- image: lazka/pygobject:v3
artifacts:
paths:
- coverage/
coverage:
stage: coverage
- image: lazka/pygobject:v3
artifacts:
paths:
- coverage/
pages:
stage: deploy
- image: lazka/pygobject:v3
dependencies:
- coverage
script:
<<: *mingw-defaults
python2-mingw64:
+ when: manual
variables:
PYTHON: "python2"
MSYSTEM: "MINGW64"
<<: *mingw-defaults
python3-mingw32:
+ when: manual
variables:
PYTHON: "python3"
MSYSTEM: "MINGW32"
python2.7:
variables:
- PYENV_VERSION: "2.7.14"
- <<: *defaults
-
-python3.4:
- variables:
- PYENV_VERSION: "3.4.8"
+ PYENV_VERSION: "2.7.15"
<<: *defaults
python3.5:
+ when: manual
variables:
PYENV_VERSION: "3.5.5"
<<: *defaults
<<: *defaults
pypy2:
+ allow_failure: true
variables:
- PYENV_VERSION: "pypy2.7-5.10.0"
+ PYENV_VERSION: "pypy2.7-6.0.0"
<<: *defaults
pypy3:
+ when: manual
+ allow_failure: true
variables:
- PYENV_VERSION: "pypy3.5-5.10.1"
+ PYENV_VERSION: "pypy3.5-6.0.0"
<<: *defaults
xenial-i386-py2:
stage: build_and_test
- image: lazka/pygobject:pyenv-old
+ image: registry.gitlab.gnome.org/gnome/pygobject/old:v2
script:
- bash -x ./.gitlab-ci/test-docker-old.sh
-FROM ubuntu:artful
+FROM ubuntu:bionic
RUN apt-get update && apt-get install -y \
- autoconf-archive \
build-essential \
ccache \
curl \
libreadline-dev \
libsqlite3-dev \
libssl-dev \
- libtool \
- locales \
+ ninja-build \
+ python3-pip \
xauth \
xvfb \
&& rm -rf /var/lib/apt/lists/*
ENV CI true
ENV PYENV_ROOT /home/user/.pyenv
ENV PATH="${PYENV_ROOT}/shims:${PYENV_ROOT}/bin:${PATH}"
+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.14
-RUN pyenv install 3.4.8
+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 pypy2.7-5.10.0
-RUN pyenv install pypy3.5-5.10.1
+RUN pyenv install pypy2.7-6.0.0
+RUN pyenv install pypy3.5-6.0.0
ENV PATH="/usr/lib/ccache:${PATH}"
-The Dockerfile is available at https://hub.docker.com/r/lazka/pygobject/
+The images are available at
+https://gitlab.gnome.org/GNOME/pygobject/container_registry
set -e
-TAG="lazka/pygobject:pyenv-old"
+TAG="registry.gitlab.gnome.org/gnome/pygobject/old:v2"
sudo docker build --build-arg HOST_USER_ID="$UID" --tag "${TAG}" \
--file "Dockerfile.old" .
-sudo docker run --rm \
+sudo docker run --rm --security-opt label=disable \
--volume "$(pwd)/..:/home/user/app" --workdir "/home/user/app" \
--tty --interactive "${TAG}" bash
set -e
-TAG="lazka/pygobject:v3"
+TAG="registry.gitlab.gnome.org/gnome/pygobject/main:v6"
sudo docker build --build-arg HOST_USER_ID="$UID" --tag "${TAG}" \
--file "Dockerfile" .
-sudo docker run -e PYENV_VERSION='3.6.5' --rm \
+sudo docker run -e PYENV_VERSION='3.6.5' --rm --security-opt label=disable \
--volume "$(pwd)/..:/home/user/app" --workdir "/home/user/app" \
--tty --interactive "${TAG}" bash
python --version
-PYVER=$(python -c "import sys; sys.stdout.write(''.join(map(str, sys.version_info[:3])))")
+PYVER=$(python -c "import sys; sys.stdout.write('.'.join(map(str, sys.version_info[:2])))")
PYIMPL=$(python -c "import sys, platform; sys.stdout.write(platform.python_implementation())")
SOURCE_DIR="$(pwd)"
COV_DIR="${SOURCE_DIR}/coverage"
export MALLOC_CHECK_=3
export MALLOC_PERTURB_=$((${RANDOM} % 255 + 1))
export G_SLICE="debug-blocks"
-export COVERAGE_FILE="${COV_DIR}/.coverage.${PYVER}"
+export COVERAGE_FILE="${COV_DIR}/.coverage.${CI_JOB_NAME}"
export CCACHE_BASEDIR="$(pwd)"
export CCACHE_DIR="${CCACHE_BASEDIR}/_ccache"
mkdir -p "${CCACHE_DIR}"
mkdir -p "${COV_DIR}"
-if [[ "${PYIMPL}" == "PyPy" ]]; then
- # https://bitbucket.org/pypy/pypy/issues/2776
- export MALLOC_CHECK_=
-fi;
-
python -m pip install git+https://github.com/pygobject/pycairo.git
python -m pip install flake8 pytest pytest-faulthandler coverage
export CFLAGS="-coverage -ftest-coverage -fprofile-arcs -Werror"
+# MESON
+/usr/bin/python3 -m pip install --user git+https://github.com/mesonbuild/meson.git
+export PATH="${HOME}/.local/bin:${PATH}"
+export PKG_CONFIG_PATH="$(python -c 'import sys; sys.stdout.write(sys.prefix)')/lib/pkgconfig"
+# pycairo install under PyPy doesn't install a .pc file
if [[ "${PYIMPL}" == "PyPy" ]]; then
- python setup.py build_tests
- exit 0;
-fi;
+ meson _build -Dpython="$(which python)" -Dpycairo=false
+else
+ meson _build -Dpython="$(which python)"
+fi
+ninja -C _build
+xvfb-run -a meson test -C _build -v
+rm -Rf _build
# CODE QUALITY
python -m flake8
# DOCUMENTATION CHECKS
-if [[ "${PYENV_VERSION}" == "2.7.14" ]]; then
+if [[ "${PYVER}" == "2.7" ]] && [[ "${PYIMPL}" == "CPython" ]]; then
python -m pip install sphinx sphinx_rtd_theme
python -m sphinx -W -a -E -b html -n docs docs/_build
fi;
# COLLECT GCOV COVERAGE
lcov --rc lcov_branch_coverage=1 --directory . --capture --output-file \
- "${COV_DIR}/${PYVER}.lcov"
+ "${COV_DIR}/${CI_JOB_NAME}.lcov"
include setup.cfg
-include pyproject.toml
include COPYING
include *.in
include NEWS
include pygobject.doap
include README.rst
include .gitlab-ci.yml
+include subprojects/*.wrap
+include meson.build
+include meson_options.txt
recursive-include examples *.py *.png *.css *.ui *.gif *.gresource *.jpg *.xml
-recursive-include gi *.h
-recursive-include tests *.py *.c *.h *.xml
+recursive-include gi *.h meson.build
+recursive-include tests *.py *.c *.h *.xml *.supp meson.build
recursive-include docs *.rst *.svg LICENSE *.ico *.png *.css *.py *.dia Makefile
recursive-include .gitlab-ci *.sh *.rst *.py Dockerfile*
+recursive-include pygtkcompat meson.build
+3.29.2 - 2018-05-16
+-------------------
+
+* Add a meson build system. :issue:`165`
+ (:user:`Mathieu Duponchelle<mathieudu>`)
+* Gtk.Template: Allow marking children as "internal-child". :mr:`58`
+* Gio.ListModel: implement most of the mutable sequence protocol.
+ :issue:`115` :mr:`59`
+* Gio.Settings: implement __iter__.
+* Gio.Settings: support range types in __setitem__. :issue:`134`
+* Add overrides for Gio.ListStore.sort and Gio.ListStore.insert_sorted.
+ :issue:`130`
+* Make Gtk.Widget.freeze_child_notify a context manager. :issue:`45`
+* OptionParser.parse_args: return leftover arguments. :issue:`200`
+* Release the GIL when emitting a signal. :mr:`66`
+ (John Bassett <john.bassett@pexip.com>)
+* Add ActionMap and ActionMap.add_action_entries() to overrides.
+ :issue:`29` :mr:`65` (:user:`yangfl`)
+* importer: raise ImportError in load_module() and not find_module().
+ :issue:`213`
+* Don't wrap GValue in GValue when creating GValueArray. :mr:`66`
+ (Stian Selnes <stian@pexip.com>)
+* ossig: Don't leak the callbacks in case the event loops are not stopped
+ through SIGINT. :issue:`219` :mr:`72`
+* Various fixes (Havard Graff <havard.graff@gmail.com>)
+* Destroy custom GLib.Source instances when they get freed. :issue:`193`
+* Revert "Add PEP518/pyproject.toml file", fixes installation with pip 10,
+ see https://github.com/pypa/pip/issues/5244
+* Various fixes/improvements for PyPy.
+* Don't crash on multiple calls to GObject.Value.__del__. :mr:`66`
+
+Documentation:
+ * Added StackOverflow (with PyGObject tag) as an contact resource.
+ (:user:`buhtz`)
+ * Add introduction to handling GLib.Error. :mr:`68`
+ (:user:`Kai Willadsen <kaiw>`)
+ * Add pycairo requires for development setup. :mr:`70`
+ (:user:`Kai Willadsen <kaiw>`)
+
+
3.29.1 - 2018-04-15
-------------------
Metadata-Version: 1.2
Name: PyGObject
-Version: 3.29.1
+Version: 3.29.2
Summary: Python bindings for GObject Introspection
Home-page: https://pygobject.readthedocs.io
Author: James Henstridge
Maintainer: Simon Feltman
Maintainer-email: sfeltman@src.gnome.org
License: GNU LGPL
-Description: .. image:: https://gitlab.gnome.org/GNOME/pygobject/badges/master/coverage.svg
- :target: https://gnome.pages.gitlab.gnome.org/pygobject
-
- ᅟ
-
- .. image:: https://pygobject.readthedocs.io/en/latest/_images/pygobject.svg
+Description: .. image:: https://pygobject.readthedocs.io/en/latest/_images/pygobject.svg
:align: center
:width: 400px
:height: 98px
<https://developer.gnome.org/glib/stable/>`__, `GIO
<https://developer.gnome.org/gio/stable/>`__ and many more.
- It supports Linux, Windows and macOS and works with **Python 2.7+** as well as
- **Python 3.4+**. PyGObject, including this documentation, is licensed under
- the **LGPLv2.1+**.
+ It supports Linux, Windows and macOS and works with **Python 2.7+**, **Python
+ 3.5+**, **PyPy** and **PyPy3**. PyGObject, including this documentation, is
+ licensed under the **LGPLv2.1+**.
+
----
Metadata-Version: 1.2
Name: PyGObject
-Version: 3.29.1
+Version: 3.29.2
Summary: Python bindings for GObject Introspection
Home-page: https://pygobject.readthedocs.io
Author: James Henstridge
Maintainer: Simon Feltman
Maintainer-email: sfeltman@src.gnome.org
License: GNU LGPL
-Description: .. image:: https://gitlab.gnome.org/GNOME/pygobject/badges/master/coverage.svg
- :target: https://gnome.pages.gitlab.gnome.org/pygobject
-
- ᅟ
-
- .. image:: https://pygobject.readthedocs.io/en/latest/_images/pygobject.svg
+Description: .. image:: https://pygobject.readthedocs.io/en/latest/_images/pygobject.svg
:align: center
:width: 400px
:height: 98px
<https://developer.gnome.org/glib/stable/>`__, `GIO
<https://developer.gnome.org/gio/stable/>`__ and many more.
- It supports Linux, Windows and macOS and works with **Python 2.7+** as well as
- **Python 3.4+**. PyGObject, including this documentation, is licensed under
- the **LGPLv2.1+**.
+ It supports Linux, Windows and macOS and works with **Python 2.7+**, **Python
+ 3.5+**, **PyPy** and **PyPy3**. PyGObject, including this documentation, is
+ licensed under the **LGPLv2.1+**.
+
----
NEWS
PKG-INFO.in
README.rst
+meson.build
+meson_options.txt
pygobject-3.0.pc.in
pygobject.doap
-pyproject.toml
setup.cfg
setup.py
.gitlab-ci/Dockerfile
docs/guide/threading.rst
docs/guide/api/api.rst
docs/guide/api/basic_types.rst
+docs/guide/api/error_handling.rst
docs/guide/api/flags_enums.rst
docs/guide/api/gobject.rst
docs/guide/api/index.rst
gi/gimodule.c
gi/gimodule.h
gi/importer.py
+gi/meson.build
gi/module.py
gi/pygboxed.c
gi/pygboxed.h
gi/overrides/Pango.py
gi/overrides/__init__.py
gi/overrides/keysyms.py
+gi/overrides/meson.build
gi/repository/__init__.py
+gi/repository/meson.build
pygtkcompat/__init__.py
pygtkcompat/generictreemodel.py
+pygtkcompat/meson.build
pygtkcompat/pygtkcompat.py
+subprojects/glib.wrap
+subprojects/gobject-introspection.wrap
+subprojects/libffi.wrap
tests/__init__.py
tests/conftest.py
tests/gimarshallingtestsextra.c
tests/gimarshallingtestsextra.h
tests/helper.py
+tests/meson.build
tests/org.gnome.test.gschema.xml
tests/regressextra.c
tests/regressextra.h
tests/test_option.py
tests/test_ossig.py
tests/test_overrides_gdk.py
+tests/test_overrides_gio.py
tests/test_overrides_glib.py
tests/test_overrides_gtk.py
tests/test_overrides_pango.py
tests/test_typeclass.py
tests/test_unknown.py
tests/testhelpermodule.c
+tests/valgrind.supp
tests/gi/overrides/Regress.py
tests/gi/overrides/__init__.py
tools/pygi-convert.sh
\ No newline at end of file
-.. image:: https://gitlab.gnome.org/GNOME/pygobject/badges/master/coverage.svg
- :target: https://gnome.pages.gitlab.gnome.org/pygobject
-
-ᅟ
-
.. image:: https://pygobject.readthedocs.io/en/latest/_images/pygobject.svg
:align: center
:width: 400px
<https://developer.gnome.org/glib/stable/>`__, `GIO
<https://developer.gnome.org/gio/stable/>`__ and many more.
-It supports Linux, Windows and macOS and works with **Python 2.7+** as well as
-**Python 3.4+**. PyGObject, including this documentation, is licensed under
-the **LGPLv2.1+**.
+It supports Linux, Windows and macOS and works with **Python 2.7+**, **Python
+3.5+**, **PyPy** and **PyPy3**. PyGObject, including this documentation, is
+licensed under the **LGPLv2.1+**.
+
----
of the GNOME project use the mailing list at
https://mail.gnome.org/mailman/listinfo/python-hackers-list.
+StackOverflow / StackExchange
+ If you have technical questions about PyGObject you can find answers on
+ `Stack Overflow <https://stackoverflow.com/questions/tagged/pygobject>`__.
+ When asking there please use the tag `PyGObject`.
+
If you are unsure which communication channel to use **please use the issue
tracker**.
pipenv --python 3
pipenv install pytest
pipenv install flake8
+ pipenv install pycairo
pipenv shell
--- /dev/null
+==============
+Error Handling
+==============
+
+GLib has its own method of handling errors using :obj:`GLib.Error`. These are
+raised as Python exceptions, but with a few small differences.
+
+It's common in Python for exception subclasses to be used (e.g.,
+:obj:`ValueError` versus :obj:`IOError`) to distinguish different types of
+errors. Libraries often define their own :obj:`Exception` subclasses, and
+library users will handle these cases explicitly.
+
+In GLib-using libraries, errors are all :obj:`GLib.Error` instances, with no
+subclassing for different error types. Instead, every :obj:`GLib.Error`
+instance has attributes that distinguish types of error:
+
+* :attr:`GLib.Error.domain` is the error domain, usually a string that you can
+ convert to a ``GLib`` quark with :func:`GLib.quark_from_string`
+* :attr:`GLib.Error.code` identifies a specific error within the domain
+* :attr:`GLib.Error.message` is a human-readable description of the error
+
+Error domains are defined per-module, and you can get an error domain from
+``*_error_quark`` functions on the relevant module. For example, IO errors
+from ``Gio`` are in the domain returned by :func:`Gio.io_error_quark`, and
+possible error code values are enumerated in :obj:`Gio.IOErrorEnum`.
+
+Once you've caught a :obj:`GLib.Error`, you can call
+:meth:`GLib.Error.matches` to see whether it matches the specific error you
+want to handle.
+
+
+Examples
+--------
+
+Catching a specific error:
+
+.. code:: pycon
+
+ >>> from gi.repository import GLib, Gio
+ >>> f = Gio.File.new_for_path('missing-path')
+ >>> try:
+ ... f.read()
+ ... except GLib.Error as err:
+ ... if err.matches(Gio.io_error_quark(), Gio.IOErrorEnum.NOT_FOUND):
+ ... print('File not found')
+ ... else:
+ ... raise
+ File not found
basic_types
flags_enums
gobject
+ error_handling
text_type = eval("unicode")
reload = eval("reload")
+ xrange = eval("xrange")
+ cmp = eval("cmp")
exec("def reraise(tp, value, tb):\n raise tp, value, tb")
else:
from importlib import reload
reload
+ xrange = range
+ cmp = lambda a, b: (a > b) - (a < b)
def reraise(tp, value, tb):
raise tp(value).with_traceback(tb)
widget_name, attr_name, old_attr_name))
else:
bound_widgets[widget_name] = attr_name
- cls.bind_template_child_full(widget_name, False, 0)
+ cls.bind_template_child_full(widget_name, obj._internal, 0)
cls.__gtktemplate_methods__ = bound_methods
cls.__gtktemplate_widgets__ = bound_widgets
class Child(object):
- def __init__(self, name=None):
+ def __init__(self, name=None, **kwargs):
self._name = name
+ self._internal = kwargs.pop("internal", False)
+ if kwargs:
+ raise TypeError("Unhandled arguments: %r" % kwargs)
class CallThing(object):
rargs[:] = context.parse([sys.argv[0]] + rargs)[1:]
def parse_args(self, args=None, values=None):
- old_args = args or []
try:
options, args = optparse.OptionParser.parse_args(
self, args, values)
for key, value in group.values.__dict__.items():
options.ensure_value(key, value)
- args = args[2:-len(old_args)]
return options, args
try:
yield
finally:
+ cb = _callback_stack.pop()
if _sigint_called:
- _callback_stack.pop()()
+ cb()
else:
# There is a signal handler set by the user, just do nothing
yield
_callback_stack.pop()()
_callback_stack.append(callback)
- with sigint_handler_set_and_restore_default(sigint_handler):
- try:
+ try:
+ with sigint_handler_set_and_restore_default(sigint_handler):
yield
- finally:
- if _sigint_called:
- signal.default_int_handler(signal.SIGINT, None)
+ finally:
+ if _sigint_called:
+ signal.default_int_handler(signal.SIGINT, None)
+ else:
+ _callback_stack.pop()
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, see <http://www.gnu.org/licenses/>.
-import traceback
-
from . import _gi
from ._compat import string_types, long_
from ._constants import \
return self
self._exc = None
-
- # Simply return the result of fget directly, no need to go through GObject.
- # See: https://bugzilla.gnome.org/show_bug.cgi?id=723872
- # We catch and print any exception occurring within the fget for compatibility
- # prior to the fast path addition from bug 723872, this should eventually
- # be removed and exceptions raised directly to the caller as in:
- # https://bugzilla.gnome.org/show_bug.cgi?id=575652
- try:
- value = self.fget(instance)
- except Exception:
- traceback.print_exc()
- value = None
-
+ value = self.fget(instance)
if self._exc:
exc = self._exc
self._exc = None
gpointer g_class)
{
GObject *object = (GObject *) instance;
- PyObject *wrapper, *args, *kwargs;
+ PyObject *wrapper, *result;
PyGILState_STATE state;
wrapper = g_object_get_qdata(object, pygobject_wrapper_key);
* so we don't destroy the wrapper. The next call to pygobject_new_full
* will take the ref */
pygobject_ref_float ((PyGObject *) wrapper);
- args = PyTuple_New(0);
- kwargs = PyDict_New();
- if (Py_TYPE(wrapper)->tp_init(wrapper, args, kwargs))
- PyErr_Print();
- Py_DECREF(args);
- Py_DECREF(kwargs);
+ result = PyObject_CallMethod (wrapper, "__init__", NULL);
+ if (result == NULL)
+ PyErr_Print ();
+ else
+ Py_DECREF (result);
}
/* XXX: used for Gtk.Template */
if (PyObject_HasAttrString (wrapper, "__dontuse_ginstance_init__")) {
- PyObject *result;
result = PyObject_CallMethod (wrapper, "__dontuse_ginstance_init__", NULL);
if (result == NULL)
PyErr_Print ();
return py_variant;
}
-static PyObject *
-_wrap_pyg_source_new (PyObject *self, PyObject *args)
-{
- return pyg_source_new ();
-}
-
#define CHUNK_SIZE 8192
static PyObject*
return PyLong_FromVoidPtr ((void *)(PyOS_getsig (sig_num)));
}
+static PyObject *
+_wrap_pygobject_new_full (PyObject *self, PyObject *args)
+{
+ PyObject *ptr_value, *long_value;
+ PyObject *steal;
+ GObject *obj;
+
+ if (!PyArg_ParseTuple (args, "OO", &ptr_value, &steal))
+ return NULL;
+
+ long_value = PyNumber_Long (ptr_value);
+ if (!long_value) {
+ PyErr_SetString (PyExc_TypeError, "first argument must be an integer");
+ return NULL;
+ }
+ obj = PyLong_AsVoidPtr (long_value);
+ Py_DECREF (long_value);
+
+ if (!G_IS_OBJECT (obj)) {
+ PyErr_SetString (PyExc_TypeError, "pointer is not a GObject");
+ return NULL;
+ }
+
+ return pygobject_new_full (obj, PyObject_IsTrue (steal), NULL);
+}
+
static PyMethodDef _gi_functions[] = {
+ { "pygobject_new_full", (PyCFunction) _wrap_pygobject_new_full, METH_VARARGS },
{ "enum_add", (PyCFunction) _wrap_pyg_enum_add, METH_VARARGS | METH_KEYWORDS },
{ "enum_register_new_gtype_and_add", (PyCFunction) _wrap_pyg_enum_register_new_gtype_and_add, METH_VARARGS | METH_KEYWORDS },
{ "flags_add", (PyCFunction) _wrap_pyg_flags_add, METH_VARARGS | METH_KEYWORDS },
{ "register_interface_info", (PyCFunction) _wrap_pyg_register_interface_info, METH_VARARGS },
{ "hook_up_vfunc_implementation", (PyCFunction) _wrap_pyg_hook_up_vfunc_implementation, METH_VARARGS },
{ "variant_type_from_string", (PyCFunction) _wrap_pyg_variant_type_from_string, METH_VARARGS },
- { "source_new", (PyCFunction) _wrap_pyg_source_new, METH_NOARGS },
+ { "source_new", (PyCFunction) pygi_source_new, METH_NOARGS },
{ "pyos_getsig", (PyCFunction) _wrap_pyig_pyos_getsig, METH_VARARGS },
- { "source_set_callback", (PyCFunction) pyg_source_set_callback, METH_VARARGS },
+ { "source_set_callback", (PyCFunction) pygi_source_set_callback, METH_VARARGS },
{ "io_channel_read", (PyCFunction) pyg_channel_read, METH_VARARGS },
{ "require_foreign", (PyCFunction) pygi_require_foreign, METH_VARARGS | METH_KEYWORDS },
{ "spawn_async",
{
PyObject *api;
- api = PYGLIB_CPointer_WrapPointer(&pygobject_api_functions, "gobject._PyGObject_API");
+ api = PyCapsule_New (&pygobject_api_functions, "gobject._PyGObject_API", NULL);
if (api == NULL)
return -1;
PyDict_SetItemString(d, "_PyGObject_API", api);
Py_INCREF(PyGIDeprecationWarning);
PyModule_AddObject(module, "PyGIDeprecationWarning", PyGIDeprecationWarning);
- api = PYGLIB_CPointer_WrapPointer ( (void *) &CAPI, "gi._API");
+ api = PyCapsule_New ( (void *) &CAPI, "gi._API", NULL);
if (api == NULL) {
return PYGLIB_MODULE_ERROR_RETURN;
}
if path != self.path:
return
- # is_registered() is faster than enumerate_versions() and
- # in the common case of a namespace getting loaded before its
- # dependencies, is_registered() returns True for all dependencies.
- if repository.is_registered(namespace) or \
- repository.enumerate_versions(namespace):
- return self
- else:
- raise ImportError('cannot import name %s, '
- 'introspection typelib not found' % namespace)
+ return self
def load_module(self, fullname):
if fullname in sys.modules:
path, namespace = fullname.rsplit('.', 1)
+ # is_registered() is faster than enumerate_versions() and
+ # in the common case of a namespace getting loaded before its
+ # dependencies, is_registered() returns True for all dependencies.
+ if not repository.is_registered(namespace) and not \
+ repository.enumerate_versions(namespace):
+ raise ImportError('cannot import name %s, '
+ 'introspection typelib not found' % namespace)
+
stacklevel = get_import_stacklevel(import_hook=True)
with _check_require_version(namespace, stacklevel=stacklevel):
try:
--- /dev/null
+sources = [
+ 'pygboxed.c',
+ 'pygenum.c',
+ 'pygflags.c',
+ 'pyginterface.c',
+ 'pygobject-object.c',
+ 'pygparamspec.c',
+ 'pygpointer.c',
+ 'pygoptioncontext.c',
+ 'pygoptiongroup.c',
+ 'pygspawn.c',
+ 'gimodule.c',
+ 'pygi-repository.c',
+ 'pygi-info.c',
+ 'pygi-foreign.c',
+ 'pygi-struct.c',
+ 'pygi-source.c',
+ 'pygi-argument.c',
+ 'pygi-resulttuple.c',
+ 'pygi-type.c',
+ 'pygi-boxed.c',
+ 'pygi-closure.c',
+ 'pygi-ccallback.c',
+ 'pygi-util.c',
+ 'pygi-property.c',
+ 'pygi-signal-closure.c',
+ 'pygi-invoke.c',
+ 'pygi-cache.c',
+ 'pygi-marshal-cleanup.c',
+ 'pygi-basictype.c',
+ 'pygi-list.c',
+ 'pygi-array.c',
+ 'pygi-error.c',
+ 'pygi-object.c',
+ 'pygi-value.c',
+ 'pygi-enum-marshal.c',
+ 'pygi-struct-marshal.c',
+ 'pygi-hashtable.c']
+
+headers = [
+ 'pygobject.h'
+]
+
+install_headers(headers, subdir : 'pygobject-@0@'.format(platform_version))
+
+python_sources = [
+ '_compat.py',
+ '_constants.py',
+ 'docstring.py',
+ '_error.py',
+ '_gtktemplate.py',
+ 'importer.py',
+ '__init__.py',
+ 'module.py',
+ '_option.py',
+ '_ossighelper.py',
+ '_propertyhelper.py',
+ 'pygtkcompat.py',
+ '_signalhelper.py',
+ 'types.py',
+]
+
+python.install_sources(python_sources,
+ pure : false,
+ subdir : 'gi'
+)
+
+giext = python.extension_module('_gi', sources,
+ dependencies : [python_dep, glib_dep, gi_dep, ffi_dep],
+ include_directories: include_directories('..'),
+ install: true,
+ subdir : 'gi',
+ c_args: pyext_c_args + main_c_args
+)
+
+if with_pycairo
+ gicairoext = python.extension_module('_gi_cairo', ['pygi-foreign-cairo.c'],
+ dependencies : [python_dep, glib_dep, gi_dep, ffi_dep, pycairo_dep, cairo_dep, cairo_gobject_dep],
+ install: true,
+ subdir : 'gi',
+ c_args: pyext_c_args + main_c_args)
+endif
+
+subdir('overrides')
+subdir('repository')
class Source(GLib.Source):
def __new__(cls, *args, **kwargs):
- # use our custom pyg_source_new() here as g_source_new() is not
+ # use our custom pygi_source_new() here as g_source_new() is not
# bindable
source = source_new()
source.__class__ = cls
def __del__(self):
if hasattr(self, '__pygi_custom_source'):
- self.unref()
+ self.destroy()
+ super(Source, self).__del__()
def set_callback(self, fn, user_data=None):
if hasattr(self, '__pygi_custom_source'):
- # use our custom pyg_source_set_callback() if for a GSource object
+ # use our custom pygi_source_set_callback() if for a GSource object
# with custom functions
source_set_callback(self, fn, user_data)
else:
self.set_value(py_value)
def __del__(self):
- if self._free_on_dealloc and self.g_type != TYPE_INVALID:
- self.unset()
+ if self._is_valid:
+ if self._free_on_dealloc and self.g_type != TYPE_INVALID:
+ self.unset()
# We must call base class __del__() after unset.
super(Value, self).__del__()
from .._ossighelper import wakeup_on_signal, register_sigint_fallback
from ..overrides import override, deprecated_init
from ..module import get_introspection_module
+from .._compat import xrange
+from gi._gi import pygobject_new_full
from gi import PyGIWarning
from gi.repository import GLib
__all__.append('VolumeMonitor')
+class ActionMap(Gio.ActionMap):
+ def add_action_entries(self, entries, user_data=None):
+ """
+ The add_action_entries() method is a convenience function for creating
+ multiple Gio.SimpleAction instances and adding them to a Gio.ActionMap.
+ Each action is constructed as per one entry.
+
+ :param list entries:
+ List of entry tuples for add_action() method. The entry tuple can
+ vary in size with the following information:
+
+ * The name of the action. Must be specified.
+ * The callback to connect to the "activate" signal of the
+ action. Since GLib 2.40, this can be None for stateful
+ actions, in which case the default handler is used. For
+ boolean-stated actions with no parameter, this is a toggle.
+ For other state types (and parameter type equal to the state
+ type) this will be a function that just calls change_state
+ (which you should provide).
+ * The type of the parameter that must be passed to the activate
+ function for this action, given as a single GLib.Variant type
+ string (or None for no parameter)
+ * The initial state for this action, given in GLib.Variant text
+ format. The state is parsed with no extra type information, so
+ type tags must be added to the string if they are necessary.
+ Stateless actions should give None here.
+ * The callback to connect to the "change-state" signal of the
+ action. All stateful actions should provide a handler here;
+ stateless actions should not.
+
+ :param user_data:
+ The user data for signal connections, or None
+ """
+ try:
+ iter(entries)
+ except (TypeError):
+ raise TypeError('entries must be iterable')
+
+ def _process_action(name, activate=None, parameter_type=None,
+ state=None, change_state=None):
+ if parameter_type:
+ if not GLib.VariantType.string_is_valid(parameter_type):
+ raise TypeError("The type string '%s' given as the "
+ "parameter type for action '%s' is "
+ "not a valid GVariant type string. " %
+ (parameter_type, name))
+ variant_parameter = GLib.VariantType.new(parameter_type)
+ else:
+ variant_parameter = None
+
+ if state is not None:
+ # stateful action
+ variant_state = GLib.Variant.parse(None, state, None, None)
+ action = Gio.SimpleAction.new_stateful(name, variant_parameter,
+ variant_state)
+ if change_state is not None:
+ action.connect('change-state', change_state, user_data)
+ else:
+ # stateless action
+ if change_state is not None:
+ raise ValueError("Stateless action '%s' should give "
+ "None for 'change_state', not '%s'." %
+ (name, change_state))
+ action = Gio.SimpleAction(name=name, parameter_type=variant_parameter)
+
+ if activate is not None:
+ action.connect('activate', activate, user_data)
+ self.add_action(action)
+
+ for entry in entries:
+ # using inner function above since entries can leave out optional arguments
+ _process_action(*entry)
+
+
+ActionMap = override(ActionMap)
+__all__.append('ActionMap')
+
+
class FileEnumerator(Gio.FileEnumerator):
def __iter__(self):
return self
def __len__(self):
return len(self.list_keys())
+ def __iter__(self):
+ for key in self.list_keys():
+ yield key
+
def __bool__(self):
# for "if mysettings" we don't want a dictionary-like test here, just
# if the object isn't None
allowed = v.unpack()
if value not in allowed:
raise ValueError('value %s is not an allowed enum (%s)' % (value, allowed))
+ elif type_ == 'range':
+ tuple_ = v.get_child_value(0)
+ type_str = tuple_.get_child_value(0).get_type_string()
+ min_, max_ = tuple_.unpack()
+ if value < min_ or value > max_:
+ raise ValueError(
+ 'value %s not in range (%s - %s)' % (value, min_, max_))
else:
raise NotImplementedError('Cannot handle allowed type range class ' + str(type_))
DBusProxy = override(DBusProxy)
__all__.append('DBusProxy')
+
+
+class ListModel(Gio.ListModel):
+
+ def __getitem__(self, key):
+ if isinstance(key, slice):
+ return [self.get_item(i) for i in xrange(*key.indices(len(self)))]
+ elif isinstance(key, int):
+ if key < 0:
+ key += len(self)
+ if key < 0:
+ raise IndexError
+ ret = self.get_item(key)
+ if ret is None:
+ raise IndexError
+ return ret
+ else:
+ raise TypeError
+
+ def __contains__(self, item):
+ pytype = self.get_item_type().pytype
+ if not isinstance(item, pytype):
+ raise TypeError(
+ "Expected type %s.%s" % (pytype.__module__, pytype.__name__))
+ for i in self:
+ if i == item:
+ return True
+ return False
+
+ def __len__(self):
+ return self.get_n_items()
+
+ def __iter__(self):
+ for i in xrange(len(self)):
+ yield self.get_item(i)
+
+
+ListModel = override(ListModel)
+__all__.append('ListModel')
+
+
+def _wrap_list_store_sort_func(func):
+
+ def wrap(a, b, *user_data):
+ a = pygobject_new_full(a, False)
+ b = pygobject_new_full(b, False)
+ return func(a, b, *user_data)
+
+ return wrap
+
+
+class ListStore(Gio.ListStore):
+
+ def sort(self, compare_func, *user_data):
+ compare_func = _wrap_list_store_sort_func(compare_func)
+ return super(ListStore, self).sort(compare_func, *user_data)
+
+ def insert_sorted(self, item, compare_func, *user_data):
+ compare_func = _wrap_list_store_sort_func(compare_func)
+ return super(ListStore, self).insert_sorted(
+ item, compare_func, *user_data)
+
+ def __delitem__(self, key):
+ if isinstance(key, slice):
+ start, stop, step = key.indices(len(self))
+ if step == 1:
+ self.splice(start, max(stop - start, 0), [])
+ elif step == -1:
+ self.splice(stop + 1, max(start - stop, 0), [])
+ else:
+ for i in sorted(xrange(start, stop, step), reverse=True):
+ self.remove(i)
+ elif isinstance(key, int):
+ if key < 0:
+ key += len(self)
+ if key < 0 or key >= len(self):
+ raise IndexError
+ self.remove(key)
+ else:
+ raise TypeError
+
+ def __setitem__(self, key, value):
+ if isinstance(key, slice):
+ pytype = self.get_item_type().pytype
+ valuelist = []
+ for v in value:
+ if not isinstance(v, pytype):
+ raise TypeError(
+ "Expected type %s.%s" % (
+ pytype.__module__, pytype.__name__))
+ valuelist.append(v)
+
+ start, stop, step = key.indices(len(self))
+ if step == 1:
+ self.__delitem__(key)
+ for v in reversed(valuelist):
+ self.insert(start, v)
+ 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)
+ elif isinstance(key, int):
+ if key < 0:
+ key += len(self)
+ if key < 0 or key >= len(self):
+ raise IndexError
+
+ pytype = self.get_item_type().pytype
+ if not isinstance(value, pytype):
+ raise TypeError(
+ "Expected type %s.%s" % (
+ pytype.__module__, pytype.__name__))
+
+ self.remove(key)
+ self.insert(key, value)
+ else:
+ raise TypeError
+
+
+ListStore = override(ListStore)
+__all__.append('ListStore')
gobj.connect(signal_name, handler, *args)
+class _FreezeNotifyManager(object):
+ def __init__(self, obj):
+ self.obj = obj
+
+ def __enter__(self):
+ pass
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ self.obj.thaw_child_notify()
+
+
class Widget(Gtk.Widget):
translate_coordinates = strip_boolean_result(Gtk.Widget.translate_coordinates)
+ def freeze_child_notify(self):
+ super(Widget, self).freeze_child_notify()
+ return _FreezeNotifyManager(self)
+
def drag_dest_set_target_list(self, target_list):
if (target_list is not None) and (not isinstance(target_list, Gtk.TargetList)):
target_list = Gtk.TargetList.new(_construct_target_list(target_list))
--- /dev/null
+python_sources = [
+ 'GLib.py',
+ 'Gtk.py',
+ 'Gdk.py',
+ 'GObject.py',
+ 'Gio.py',
+ 'GIMarshallingTests.py',
+ 'Pango.py',
+ 'keysyms.py',
+ '__init__.py']
+
+python.install_sources(python_sources,
+ subdir : join_paths('gi', 'overrides')
+)
if (!PySequence_Check (py_arg)) {
PyErr_Format (PyExc_TypeError, "Must be sequence, not %s",
- py_arg->ob_type->tp_name);
+ Py_TYPE (py_arg)->tp_name);
return FALSE;
}
if (py_arg == Py_None) {
*result = NULL;
return TRUE;
- } else if (PYGLIB_CPointer_Check(py_arg)) {
- temp = PYGLIB_CPointer_GetPointer (py_arg, NULL);
+ } else if (PyCapsule_CheckExact (py_arg)) {
+ temp = PyCapsule_GetPointer (py_arg, NULL);
if (temp == NULL)
return FALSE;
*result = temp;
{
if (!PyNumber_Check (object)) {
PyErr_Format (PyExc_TypeError, "Must be number, not %s",
- object->ob_type->tp_name);
+ Py_TYPE (object)->tp_name);
return NULL;
}
#endif
} else {
PyErr_Format (PyExc_TypeError, "Must be string, not %s",
- py_arg->ob_type->tp_name);
+ Py_TYPE (py_arg)->tp_name);
return FALSE;
}
if (temp == 0) {
PyErr_Format (PyExc_TypeError, "Must be gobject.GType, not %s",
- py_arg->ob_type->tp_name);
+ Py_TYPE (py_arg)->tp_name);
return FALSE;
}
#endif
else {
PyErr_Format (PyExc_TypeError, "Must be string, not %s",
- py_arg->ob_type->tp_name);
+ Py_TYPE (py_arg)->tp_name);
return FALSE;
}
Py_DECREF (bytes);
} else {
PyErr_Format (PyExc_TypeError, "Must be bytes, not %s",
- py_arg->ob_type->tp_name);
+ Py_TYPE (py_arg)->tp_name);
return FALSE;
}
Py_DECREF (bytes);
} else {
PyErr_Format (PyExc_TypeError, "Must be unicode, not %s",
- py_arg->ob_type->tp_name);
+ Py_TYPE (py_arg)->tp_name);
return FALSE;
}
#else
Py_DECREF (bytes);
} else {
PyErr_Format (PyExc_TypeError, "Must be str, not %s",
- py_arg->ob_type->tp_name);
+ Py_TYPE (py_arg)->tp_name);
return FALSE;
}
#endif
if (!PyNumber_Check (object)) {
PyErr_Format (PyExc_TypeError, "Must be number, not %s",
- object->ob_type->tp_name);
+ Py_TYPE (object)->tp_name);
return NULL;
}
return PyBool_FromLong (value);
}
+/* A super set of pygi_gint8_from_py (also handles unicode) */
+gboolean
+pygi_gschar_from_py (PyObject *object, gint8 *result)
+{
+ if (PyUnicode_Check (object)) {
+ gunichar uni;
+ PyObject *temp;
+ gboolean status;
+
+ if (!pygi_gunichar_from_py (object, &uni))
+ return FALSE;
+
+ temp = pygi_guint32_to_py (uni);
+ status = pygi_gint8_from_py (temp, result);
+ Py_DECREF (temp);
+ return status;
+ } else {
+ /* pygi_gint8_from_py handles numbers and bytes */
+ return pygi_gint8_from_py (object, result);
+ }
+
+ return FALSE;
+}
+
+/* A super set of pygi_guint8_from_py (also handles unicode) */
+gboolean
+pygi_guchar_from_py (PyObject *object, guchar *result)
+{
+ if (PyUnicode_Check (object)) {
+ gunichar uni;
+ PyObject *temp;
+ gboolean status;
+ gint8 codepoint;
+
+ if (!pygi_gunichar_from_py (object, &uni))
+ return FALSE;
+
+ temp = pygi_guint32_to_py (uni);
+ status = pygi_gint8_from_py (temp, &codepoint);
+ Py_DECREF (temp);
+ if (status)
+ *result = (guchar)codepoint;
+ return status;
+ } else {
+ /* pygi_guint8_from_py handles numbers and bytes */
+ return pygi_guint8_from_py (object, result);
+ }
+}
+
gboolean
pygi_gint_from_py (PyObject *object, gint *result)
{
return PyLong_FromUnsignedLong (value);
}
-static gboolean
+gboolean
pygi_gint8_from_py (PyObject *object, gint8 *result)
{
long long_value;
return PYGLIB_PyLong_FromLong (value);
}
-static gboolean
+gboolean
pygi_guint8_from_py (PyObject *object, guint8 *result)
{
long long_value;
return FALSE;
}
-static PyObject *
+PyObject *
pygi_guint32_to_py (guint32 value)
{
#if (G_MAXUINT <= LONG_MAX)
PyObject *pygi_filename_to_py (gchar *value);
PyObject *pygi_gsize_to_py (gsize value);
PyObject *pygi_gssize_to_py (gssize value);
+PyObject *pygi_guint32_to_py (guint32 value);
gboolean pygi_gboolean_from_py (PyObject *object, gboolean *result);
gboolean pygi_gint64_from_py (PyObject *object, gint64 *result);
gboolean pygi_gint_from_py (PyObject *object, gint *result);
gboolean pygi_guint_from_py (PyObject *object, guint *result);
gboolean pygi_gunichar_from_py (PyObject *py_arg, gunichar *result);
+gboolean pygi_gint8_from_py (PyObject *object, gint8 *result);
+gboolean pygi_gschar_from_py (PyObject *object, gint8 *result);
+gboolean pygi_guint8_from_py (PyObject *object, guint8 *result);
+gboolean pygi_guchar_from_py (PyObject *object, guchar *result);
G_END_DECLS
if (!PyArg_ParseTupleAndKeywords (args, kwargs, "", kwlist)) {
PyErr_Clear ();
- PyErr_Warn (PyExc_TypeError,
+ PyErr_Warn (PyExc_DeprecationWarning,
"Passing arguments to gi.types.Boxed.__init__() is deprecated. "
"All arguments passed will be ignored.");
}
return pygi_gboolean_to_py( ((PyGBoxed *)self)->free_on_dealloc );
}
+static PyObject *
+boxed_get_is_valid (PyGIBoxed *self, void *closure)
+{
+ return pygi_gboolean_to_py (pyg_boxed_get_ptr (self) != NULL);
+}
+
/**
* pygi_boxed_copy_in_place:
*
static PyGetSetDef pygi_boxed_getsets[] = {
{ "_free_on_dealloc", (getter)boxed_get_free_on_dealloc, (setter)0 },
+ { "_is_valid", (getter)boxed_get_is_valid, (setter)0 },
{ NULL, 0, 0 }
};
if (!PyCallable_Check (py_arg)) {
PyErr_Format (PyExc_TypeError,
"Callback needs to be a function or method not %s",
- py_arg->ob_type->tp_name);
+ Py_TYPE (py_arg)->tp_name);
return FALSE;
}
if (interface)
g_base_info_unref (interface);
PyErr_Format (PyExc_TypeError, "Expected a %s, but got %s",
- iface_cache->type_name, py_arg->ob_type->tp_name);
+ iface_cache->type_name, Py_TYPE (py_arg)->tp_name);
return FALSE;
}
err:
PyErr_Format (PyExc_TypeError, "Expected a %s, but got %s",
- iface_cache->type_name, py_arg->ob_type->tp_name);
+ iface_cache->type_name, Py_TYPE (py_arg)->tp_name);
return FALSE;
}
if (PyObject_IsInstance (pyerr, PyGError) != 1) {
PyErr_Format (PyExc_TypeError, "Must be GLib.Error, not %s",
- pyerr->ob_type->tp_name);
+ Py_TYPE (pyerr)->tp_name);
return FALSE;
}
py_keys = PyMapping_Keys (py_arg);
if (py_keys == NULL) {
PyErr_Format (PyExc_TypeError, "Must be mapping, not %s",
- py_arg->ob_type->tp_name);
+ Py_TYPE (py_arg)->tp_name);
return FALSE;
}
return NULL;
info = get_child_info_by_name ((GIObjectInfo*)self->info, name);
+ g_free (name);
if (info == NULL) {
Py_RETURN_NONE;
}
return NULL;
value = g_base_info_get_attribute (self->info, name);
+ g_free (name);
if (value == NULL) {
Py_RETURN_NONE;
}
py_str_name = tmp;
}
-#if PY_VERSION_HEX < 0x03000000
- str_name = PyString_AsString (py_str_name);
-#else
- str_name = PyBytes_AsString (py_str_name);
-#endif
-
+ str_name = PYGLIB_PyBytes_AsString (py_str_name);
if (strcmp (str_name, _safe_base_info_get_name (container_info))) {
PyErr_Format (PyExc_TypeError,
"%s constructor cannot be used to create instances of "
attr = g_callable_info_get_return_attribute (self->info, name);
if (attr) {
- return pygi_utf8_to_py (
- g_callable_info_get_return_attribute (self->info, name));
+ g_free (name);
+ return pygi_utf8_to_py (attr);
} else {
PyErr_Format(PyExc_AttributeError, "return attribute %s not found", name);
+ g_free (name);
return NULL;
}
}
if (!PySequence_Check (py_arg)) {
PyErr_Format (PyExc_TypeError, "Must be sequence, not %s",
- py_arg->ob_type->tp_name);
+ Py_TYPE (py_arg)->tp_name);
return FALSE;
}
if (!PySequence_Check (py_arg)) {
PyErr_Format (PyExc_TypeError, "Must be sequence, not %s",
- py_arg->ob_type->tp_name);
+ Py_TYPE (py_arg)->tp_name);
return FALSE;
}
* https://bugzilla.gnome.org/show_bug.cgi?id=693393
*/
gobj = arg->v_pointer;
- if (py_arg->ob_refcnt == 1 && gobj->ref_count == 1) {
+ if (Py_REFCNT (py_arg) == 1 && gobj->ref_count == 1) {
/* If both object ref counts are only 1 at this point (the reference held
* in a return tuple), we assume the GObject will be free'd before reaching
* its target and become invalid. So instead of getting invalid object errors
( (PyGIInterfaceCache *)arg_cache)->type_name,
module ? PYGLIB_PyUnicode_AsString(module) : "",
module ? "." : "",
- py_arg->ob_type->tp_name);
+ Py_TYPE (py_arg)->tp_name);
if (module)
Py_DECREF (module);
return FALSE;
py_pspec = pyg_param_spec_new (pspec);
retval = PyObject_CallMethod (instance, "do_get_property", "O", py_pspec);
- if (retval == NULL) {
- PyErr_Print();
- }
-
Py_DECREF (py_pspec);
- if (retval) {
- return retval;
- }
-
- Py_RETURN_NONE;
+ return retval;
}
PyObject *
#include <Python.h>
-# define PYGLIB_CPointer_Check PyCapsule_CheckExact
-# define PYGLIB_CPointer_WrapPointer(ptr, typename) \
- PyCapsule_New(ptr, typename, NULL)
-# define PYGLIB_CPointer_GetPointer(obj, typename) \
- PyCapsule_GetPointer(obj, typename)
-# define PYGLIB_CPointer_Import(module, symbol) \
- PyCapsule_Import(##module##.##symbol##, FALSE)
-
#define PYGLIB_MODULE_ERROR_RETURN NULL
#ifdef __GNUC__
/* Compilation on Python 2.x */
#if PY_VERSION_HEX < 0x03000000
-#define RO READONLY
-
-#define PYGLIB_PyBaseString_Check(ob) (PyString_Check(ob) || PyUnicode_Check(ob))
-
#define PYGLIB_PyUnicode_Check PyString_Check
#define PYGLIB_PyUnicode_AsString PyString_AsString
#define PYGLIB_PyUnicode_AsStringAndSize PyString_AsStringAndSize
#define PYGLIB_PyUnicode_FromString PyString_FromString
#define PYGLIB_PyUnicode_FromStringAndSize PyString_FromStringAndSize
#define PYGLIB_PyUnicode_FromFormat PyString_FromFormat
-#define PYGLIB_PyUnicode_AS_STRING PyString_AS_STRING
-#define PYGLIB_PyUnicode_GET_SIZE PyString_GET_SIZE
#define PYGLIB_PyUnicode_Type PyString_Type
#define PYGLIB_PyUnicode_InternFromString PyString_InternFromString
#define PYGLIB_PyUnicode_InternInPlace PyString_InternInPlace
#define PYGLIB_PyLongObject PyIntObject
#define PYGLIB_PyLong_Type PyInt_Type
#define PYGLIB_PyLong_AS_LONG PyInt_AS_LONG
-#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
#define PYGLIB_Py_hash_t long
#define PYGLIB_PyNumber_Long PyNumber_Int
-#ifndef PyVarObject_HEAD_INIT
-#define PyVarObject_HEAD_INIT(base, size) \
- PyObject_HEAD_INIT(base) \
- size,
-#endif
-
#define PYGLIB_MODULE_START(symbol, modname) \
PyObject * pyglib_##symbol##_module_create(void); \
PYGI_MODINIT_FUNC init##symbol(void); \
return -1; \
PyDict_SetItemString(d, name, (PyObject *)&type);
-#define PYGLIB_PyBaseString_Check PyUnicode_Check
-
#define PYGLIB_PyUnicode_Check PyUnicode_Check
#define PYGLIB_PyUnicode_AsString _PyUnicode_AsString
#define PYGLIB_PyUnicode_AsStringAndSize(obj, buf, size) \
#define PYGLIB_PyUnicode_FromString PyUnicode_FromString
#define PYGLIB_PyUnicode_FromStringAndSize PyUnicode_FromStringAndSize
#define PYGLIB_PyUnicode_FromFormat PyUnicode_FromFormat
-#define PYGLIB_PyUnicode_GET_SIZE PyUnicode_GET_SIZE
#define PYGLIB_PyUnicode_Resize PyUnicode_Resize
#define PYGLIB_PyUnicode_Type PyUnicode_Type
#define PYGLIB_PyUnicode_InternFromString PyUnicode_InternFromString
Py_DECREF (mapping_attr);
if (mapping == NULL)
goto error;
- items = PyObject_Dir ((PyObject*)self->ob_type);
+ items = PyObject_Dir ((PyObject*)Py_TYPE (self));
if (items == NULL)
goto error;
mapping_values = PyDict_Keys (mapping);
list_item = pass_by_ref_structs;
while (list_item) {
PyObject *item = list_item->data;
- if (item->ob_refcnt > 1) {
+ if (Py_REFCNT (item) > 1) {
pygi_boxed_copy_in_place ((PyGIBoxed *)item);
}
list_item = g_slist_next (list_item);
} PyGRealSource;
static gboolean
-pyg_source_prepare(GSource *source, gint *timeout)
+source_prepare(GSource *source, gint *timeout)
{
PyGRealSource *pysource = (PyGRealSource *)source;
PyObject *t;
}
static gboolean
-pyg_source_check(GSource *source)
+source_check(GSource *source)
{
PyGRealSource *pysource = (PyGRealSource *)source;
PyObject *t;
}
static gboolean
-pyg_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
+source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
{
PyGRealSource *pysource = (PyGRealSource *)source;
PyObject *func, *args, *tuple, *t;
}
static void
-pyg_source_finalize(GSource *source)
+source_finalize(GSource *source)
{
PyGRealSource *pysource = (PyGRealSource *)source;
PyObject *func, *t;
static GSourceFuncs pyg_source_funcs =
{
- pyg_source_prepare,
- pyg_source_check,
- pyg_source_dispatch,
- pyg_source_finalize
+ source_prepare,
+ source_check,
+ source_dispatch,
+ source_finalize
};
/**
* call Py_DECREF on the data.
*/
static void
-_pyglib_destroy_notify(gpointer user_data)
+destroy_notify(gpointer user_data)
{
PyObject *obj = (PyObject *)user_data;
PyGILState_STATE state;
}
static gboolean
-_pyglib_handler_marshal(gpointer user_data)
+handler_marshal(gpointer user_data)
{
PyObject *tuple, *ret;
gboolean res;
}
PyObject *
-pyg_source_set_callback(PyGObject *self_module, PyObject *args)
+pygi_source_set_callback (PyGObject *self_module, PyObject *args)
{
PyObject *self, *first, *callback, *cbargs = NULL, *data;
Py_ssize_t len;
return NULL;
g_source_set_callback(pyg_boxed_get (self, GSource),
- _pyglib_handler_marshal, data,
- _pyglib_destroy_notify);
+ handler_marshal, data,
+ destroy_notify);
Py_INCREF(Py_None);
return Py_None;
}
/**
- * pyg_source_new:
+ * pygi_source_new:
*
* Wrap the un-bindable g_source_new() and provide wrapper callbacks in the
* GSourceFuncs which call back to Python.
+ *
+ * Returns NULL on error and sets an exception.
*/
PyObject*
-pyg_source_new (void)
+pygi_source_new (PyObject *self, PyObject *args)
{
- PyGRealSource *source = NULL;
- PyObject *py_type;
+ PyGRealSource *source;
+ PyObject *py_type, *boxed;
- source = (PyGRealSource*) g_source_new (&pyg_source_funcs, sizeof (PyGRealSource));
+ g_assert (args == NULL);
py_type = pygi_type_import_by_name ("GLib", "Source");
+ if (!py_type)
+ return NULL;
+
+ source = (PyGRealSource*) g_source_new (&pyg_source_funcs, sizeof (PyGRealSource));
/* g_source_new uses malloc, not slices */
- source->obj = pygi_boxed_new ( (PyTypeObject *) py_type, source, FALSE, 0);
+ boxed = pygi_boxed_new ( (PyTypeObject *) py_type, source, TRUE, 0);
+ Py_DECREF (py_type);
+ if (!boxed) {
+ g_source_unref ((GSource *)source);
+ return NULL;
+ }
+ source->obj = boxed;
return source->obj;
}
#ifndef __PYGI_SOURCE_H__
#define __PYGI_SOURCE_H__
-PyObject *pyg_source_new (void);
-PyObject *pyg_source_set_callback (PyGObject *self, PyObject *args);
+PyObject *pygi_source_new (PyObject *self, PyObject *args);
+PyObject *pygi_source_set_callback (PyGObject *self, PyObject *args);
#endif /* __PYGI_SOURCE_H__ */
GValue *value;
GType object_type;
- object_type = pyg_type_from_object_strict ( (PyObject *) py_arg->ob_type, FALSE);
+ object_type = pyg_type_from_object_strict ( (PyObject *) Py_TYPE (py_arg), FALSE);
if (object_type == G_TYPE_INVALID) {
PyErr_SetString (PyExc_RuntimeError, "unable to retrieve object's GType");
return FALSE;
/* Note py_arg can be NULL for hash table which is a bug. */
if (was_processed && py_arg != NULL) {
GType py_object_type =
- pyg_type_from_object_strict ( (PyObject *) py_arg->ob_type, FALSE);
+ pyg_type_from_object_strict ( (PyObject *) Py_TYPE (py_arg), FALSE);
/* When a GValue was not passed, it means the marshalers created a new
* one to pass in, clean this up.
if ( !(PyCallable_Check(py_arg) ||
g_type_is_a (object_gtype, G_TYPE_CLOSURE))) {
PyErr_Format (PyExc_TypeError, "Must be callable, not %s",
- py_arg->ob_type->tp_name);
+ Py_TYPE (py_arg)->tp_name);
return FALSE;
}
type_name,
module ? PYGLIB_PyUnicode_AsString(module) : "",
module ? "." : "",
- py_arg->ob_type->tp_name);
+ Py_TYPE (py_arg)->tp_name);
if (module)
Py_DECREF (module);
g_free (type_name);
for (i = 0; i < len; i++) {
PyObject *item = PyTuple_GetItem(params, i);
if (item != NULL && PyObject_TypeCheck(item, &PyGBoxed_Type)
- && item->ob_refcnt != 1) {
+ && Py_REFCNT (item) != 1) {
PyGBoxed* boxed_item = (PyGBoxed*)item;
if (!boxed_item->free_on_dealloc) {
gpointer boxed_ptr = pyg_boxed_get_ptr (boxed_item);
for (i = 0; i < len; ++i) {
PyObject *item = PySequence_GetItem(obj, i);
GType type;
- GValue item_value = { 0, };
- int status;
if (! item) {
PyErr_Clear();
}
}
- g_value_init(&item_value, type);
- status = (pspec && pspec->element_spec)
- ? pyg_param_gvalue_from_pyobject(&item_value, item, pspec->element_spec)
- : pyg_value_from_pyobject(&item_value, item);
- Py_DECREF(item);
+ if (type == G_TYPE_VALUE) {
+ const GValue * item_value = pyg_boxed_get(item, GValue);
+ g_value_array_append(value_array, item_value);
+ } else {
+ GValue item_value = { 0, };
+ int status;
- if (status == -1) {
- g_value_array_free(value_array);
+ g_value_init(&item_value, type);
+ status = (pspec && pspec->element_spec)
+ ? pyg_param_gvalue_from_pyobject(&item_value, item, pspec->element_spec)
+ : pyg_value_from_pyobject(&item_value, item);
+ Py_DECREF(item);
+
+ if (status == -1) {
+ g_value_array_free(value_array);
+ g_value_unset(&item_value);
+ return -1;
+ }
+ g_value_array_append(value_array, &item_value);
g_value_unset(&item_value);
- return -1;
}
-
- g_value_array_append(value_array, &item_value);
- g_value_unset(&item_value);
}
g_value_take_boxed(value, value_array);
int
pyg_value_from_pyobject_with_error(GValue *value, PyObject *obj)
{
- PyObject *tmp;
GType value_type = G_VALUE_TYPE(value);
switch (G_TYPE_FUNDAMENTAL(value_type)) {
}
break;
case G_TYPE_CHAR:
- if (PYGLIB_PyLong_Check(obj)) {
- glong val;
- val = PYGLIB_PyLong_AsLong(obj);
- if (val >= -128 && val <= 127)
- g_value_set_schar(value, (gchar) val);
- else
- return -1;
- }
-#if PY_VERSION_HEX < 0x03000000
- else if (PyString_Check(obj)) {
- g_value_set_schar(value, PyString_AsString(obj)[0]);
- }
-#endif
- else if (PyUnicode_Check(obj)) {
- tmp = PyUnicode_AsUTF8String(obj);
- g_value_set_schar(value, PYGLIB_PyBytes_AsString(tmp)[0]);
- Py_DECREF(tmp);
- } else {
- PyErr_SetString(PyExc_TypeError, "Cannot convert to TYPE_CHAR");
+ {
+ gint8 temp;
+ if (pygi_gschar_from_py (obj, &temp)) {
+ g_value_set_schar (value, temp);
+ return 0;
+ } else
return -1;
- }
-
- break;
+ }
case G_TYPE_UCHAR:
- if (PYGLIB_PyLong_Check(obj)) {
- glong val;
- val = PYGLIB_PyLong_AsLong(obj);
- if (val >= 0 && val <= 255)
- g_value_set_uchar(value, (guchar) val);
- else
- return -1;
-#if PY_VERSION_HEX < 0x03000000
- } else if (PyString_Check(obj)) {
- g_value_set_uchar(value, PyString_AsString(obj)[0]);
-#endif
- } else if (PyUnicode_Check(obj)) {
- tmp = PyUnicode_AsUTF8String(obj);
- g_value_set_uchar(value, PYGLIB_PyBytes_AsString(tmp)[0]);
- Py_DECREF(tmp);
- } else {
- PyErr_Clear();
+ {
+ guchar temp;
+ if (pygi_guchar_from_py (obj, &temp)) {
+ g_value_set_uchar (value, temp);
+ return 0;
+ } else
return -1;
- }
- break;
+ }
case G_TYPE_BOOLEAN:
{
gboolean temp;
{
gchar *temp;
if (pygi_utf8_from_py (obj, &temp)) {
- g_value_set_string (value, temp);
+ g_value_take_string (value, temp);
return 0;
} else {
/* also allows setting anything implementing __str__ */
return -1;
if (pygi_utf8_from_py (str, &temp)) {
Py_DECREF (str);
- g_value_set_string (value, temp);
+ g_value_take_string (value, temp);
return 0;
}
Py_DECREF (str);
else if (PyObject_TypeCheck(obj, &PyGPointer_Type) &&
G_VALUE_HOLDS(value, ((PyGPointer *)obj)->gtype))
g_value_set_pointer(value, pyg_pointer_get(obj, gpointer));
- else if (PYGLIB_CPointer_Check(obj))
- g_value_set_pointer(value, PYGLIB_CPointer_GetPointer(obj, NULL));
+ else if (PyCapsule_CheckExact (obj))
+ g_value_set_pointer(value, PyCapsule_GetPointer (obj, NULL));
else if (G_VALUE_HOLDS_GTYPE (value))
g_value_set_gtype (value, pyg_type_from_object (obj));
else {
}
else if ((bm = pyg_type_lookup(G_VALUE_TYPE(value))) != NULL)
return bm->tovalue(value, obj);
- else if (PYGLIB_CPointer_Check(obj))
- g_value_set_boxed(value, PYGLIB_CPointer_GetPointer(obj, NULL));
+ else if (PyCapsule_CheckExact (obj))
+ g_value_set_boxed(value, PyCapsule_GetPointer (obj, NULL));
else {
PyErr_SetString(PyExc_TypeError, "Expected Boxed");
return -1;
if (G_IS_PARAM_SPEC (pygobject_get (obj)))
g_value_set_param(value, G_PARAM_SPEC (pygobject_get (obj)));
else if (pyg_param_spec_check (obj))
- g_value_set_param(value, PYGLIB_CPointer_GetPointer(obj, NULL));
+ g_value_set_param(value, PyCapsule_GetPointer (obj, NULL));
else {
PyErr_SetString(PyExc_TypeError, "Expected ParamSpec");
return -1;
if (query.return_type != G_TYPE_NONE)
g_value_init(&ret, query.return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE);
+ Py_BEGIN_ALLOW_THREADS;
g_signal_emitv(params, signal_id, detail, &ret);
+ Py_END_ALLOW_THREADS;
for (i = 0; i < query.n_params + 1; i++)
g_value_unset(¶ms[i]);
static PyObject *
pygobject_get_pointer(PyGObject *self, void *closure)
{
- return PYGLIB_CPointer_WrapPointer (self->obj, NULL);
+ return PyCapsule_New (self->obj, NULL, NULL);
}
static int
}
cobject = PyObject_GetAttrString(gobject, "_PyGObject_API");
- if (cobject && PyCapsule_CheckExact(cobject))
+ if (cobject && PyCapsule_CheckExact(cobject)) {
_PyGObject_API = (struct _PyGObject_Functions *) PyCapsule_GetPointer(cobject, "gobject._PyGObject_API");
- else {
+ Py_DECREF (cobject);
+ } else {
PyErr_SetString(PyExc_ImportError,
"could not import gobject (could not find _PyGObject_API object)");
+ Py_XDECREF (cobject);
Py_DECREF(gobject);
return NULL;
}
static PyObject *
pyg_option_get_context(PyGOptionContext *self)
{
- return PYGLIB_CPointer_WrapPointer(self->context, "goption.context");
+ return PyCapsule_New (self->context, "goption.context", NULL);
}
static PyMethodDef pyg_option_context_methods[] = {
--- /dev/null
+python_sources = ['__init__.py']
+
+python.install_sources(python_sources,
+ subdir : join_paths('gi', 'repository')
+)
--- /dev/null
+project('pygobject', 'c',
+ version : '3.29.2',
+ meson_version : '>= 0.46.0',
+ default_options : [ 'warning_level=1',
+ 'buildtype=debugoptimized'])
+
+pygobject_version = meson.project_version()
+version_arr = pygobject_version.split('.')
+pygobject_version_major = version_arr[0].to_int()
+pygobject_version_minor = version_arr[1].to_int()
+pygobject_version_micro = version_arr[2].to_int()
+
+platform_version = '@0@.0'.format(pygobject_version_major)
+
+pymod = import('python')
+python = pymod.find_installation(get_option('python'))
+
+python_dep = python.dependency()
+
+glib_version_req = '>= 2.38.0'
+gi_version_req = '>= 1.46.0'
+pycairo_version_req = '>= 1.11.1'
+libffi_version_req = '>= 3.0'
+
+gi_dep = dependency('gobject-introspection-1.0', version : gi_version_req,
+ fallback: ['gobject-introspection', 'girepo_dep'])
+glib_dep = dependency('glib-2.0', version : glib_version_req,
+ fallback: ['glib', 'libglib_dep'])
+gobject_dep = dependency('gobject-2.0', version : glib_version_req,
+ fallback: ['glib', 'libgobject_dep'])
+gio_dep = dependency('gio-2.0', version : glib_version_req,
+ fallback: ['glib', 'libgio_dep'])
+gmodule_dep = dependency('gmodule-2.0', version : glib_version_req,
+ fallback: ['glib', 'libgmodule_dep'])
+ffi_dep = dependency('libffi', version : '>= 3.0',
+ fallback : ['libffi', 'ffi_dep'])
+
+with_pycairo = get_option('pycairo')
+
+if with_pycairo
+ cairo_dep = dependency('cairo')
+ cairo_gobject_dep = dependency('cairo-gobject')
+
+ if python.language_version().version_compare('>= 3.0')
+ pycairo_dep = dependency('py3cairo', version : pycairo_version_req)
+ else
+ pycairo_dep = dependency('pycairo', version : pycairo_version_req)
+ endif
+endif
+
+cc = meson.get_compiler('c')
+
+main_c_args = [
+ '-Wall',
+ '-Warray-bounds',
+ '-Wcast-align',
+ '-Wdeclaration-after-statement',
+ '-Wduplicated-branches',
+ '-Wextra',
+ '-Wformat=2',
+ '-Wformat-nonliteral',
+ '-Wformat-security',
+ '-Wimplicit-function-declaration',
+ '-Winit-self',
+ '-Winline',
+ '-Wjump-misses-init',
+ '-Wlogical-op',
+ '-Wmissing-declarations',
+ '-Wmissing-format-attribute',
+ '-Wmissing-include-dirs',
+ '-Wmissing-noreturn',
+ '-Wmissing-prototypes',
+ '-Wnested-externs',
+ '-Wnull-dereference',
+ '-Wold-style-definition',
+ '-Wpacked',
+ '-Wpointer-arith',
+ '-Wrestrict',
+ '-Wreturn-type',
+ '-Wshadow',
+ '-Wsign-compare',
+ '-Wstrict-aliasing',
+ '-Wstrict-prototypes',
+ '-Wundef',
+ '-Wunused-but-set-variable',
+ '-Wwrite-strings',
+ '-Wconversion',
+]
+
+main_c_args += [
+ '-Wno-incompatible-pointer-types-discards-qualifiers',
+ '-Wno-missing-field-initializers',
+ '-Wno-unused-parameter',
+ '-Wno-discarded-qualifiers',
+ '-Wno-sign-conversion',
+ '-Wno-cast-function-type',
+]
+
+main_c_args += [
+ '-fno-strict-aliasing',
+ '-fvisibility=hidden',
+]
+
+if not ['3.3', '3.4'].contains(python.language_version())
+ main_c_args += [
+ '-Wswitch-default',
+ ]
+endif
+
+main_c_args = cc.get_supported_arguments(main_c_args)
+
+pyext_c_args = ['-DPY_SSIZE_T_CLEAN']
+
+cdata = configuration_data()
+
+cdata.set('PYGOBJECT_MAJOR_VERSION', pygobject_version_major)
+cdata.set('PYGOBJECT_MINOR_VERSION', pygobject_version_minor)
+cdata.set('PYGOBJECT_MICRO_VERSION', pygobject_version_micro)
+
+configure_file(output : 'config.h', configuration : cdata)
+
+pkgconf = configuration_data()
+
+pkgconf.set('prefix', join_paths(get_option('prefix')))
+pkgconf.set('exec_prefix', '${prefix}')
+pkgconf.set('includedir', join_paths('${prefix}', get_option('includedir')))
+pkgconf.set('datarootdir', join_paths('${prefix}', get_option('datadir')))
+pkgconf.set('datadir', '${datarootdir}')
+pkgconf.set('VERSION', pygobject_version)
+
+pkg_install_dir = '@0@/pkgconfig'.format(get_option('libdir'))
+
+configure_file(input : 'pygobject-@0@.pc.in'.format(platform_version),
+ output : 'pygobject-@0@.pc'.format(platform_version),
+ configuration : pkgconf,
+ install_dir : pkg_install_dir)
+
+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'))
+
+subdir('gi')
+subdir('pygtkcompat')
+subdir('tests')
--- /dev/null
+option('python', type : 'string', value : 'python3')
+option('pycairo', type : 'boolean', value : true, description : 'build with pycairo integration')
--- /dev/null
+python_sources = [
+ '__init__.py',
+ 'generictreemodel.py',
+ 'pygtkcompat.py']
+
+python.install_sources(python_sources,
+ subdir : 'pygtkcompat'
+)
+++ /dev/null
-[build-system]
-requires = ["setuptools", "wheel", "pycairo"]
from distutils.spawn import find_executable
-PYGOBJECT_VERISON = "3.29.1"
+PYGOBJECT_VERISON = "3.29.2"
GLIB_VERSION_REQUIRED = "2.38.0"
GI_VERSION_REQUIRED = "1.46.0"
PYCAIRO_VERSION_REQUIRED = "1.11.1"
assert process.returncode == 0
tracked_files = out.splitlines()
- for ignore in [".gitignore"]:
- if ignore in tracked_files:
- tracked_files.remove(ignore)
+ tracked_files = [
+ f for f in tracked_files
+ if os.path.basename(f) not in [".gitignore"]]
diff = set(tracked_files) - set(included_files)
assert not diff, (
"--library=gimarshallingtests",
"--pkg=glib-2.0",
"--pkg=gio-2.0",
+ "--cflags-begin",
+ "-I%s" % gi_tests_dir,
+ "--cflags-end",
"--output=%s" % gir_path,
] + ext.sources + ext.depends)
files = []
for prefix in prefixes:
files.extend(get_suppression_files_for_prefix(prefix))
+
+ files.append(os.path.join(get_script_dir(), "tests", "valgrind.supp"))
return sorted(set(files))
"libffi": ["ffi"],
}
+ def add(target, new):
+ for entry in new:
+ if entry not in target:
+ target.append(entry)
+
fallback_libs = msvc_libraries[name]
if compiler_type == "msvc":
# assume that INCLUDE and LIB contains the right paths
- ext.libraries += fallback_libs
+ add(ext.libraries, fallback_libs)
else:
min_version = get_version_requirement(name)
pkg_config_version_check(name, min_version)
- ext.include_dirs += pkg_config_parse("--cflags-only-I", name)
- ext.library_dirs += pkg_config_parse("--libs-only-L", name)
- ext.libraries += pkg_config_parse("--libs-only-l", name)
+ add(ext.include_dirs, pkg_config_parse("--cflags-only-I", name))
+ add(ext.library_dirs, pkg_config_parse("--libs-only-L", name))
+ add(ext.libraries, pkg_config_parse("--libs-only-l", name))
def add_ext_compiler_flags(ext, compiler, _cache={}):
"-Wno-unused-parameter",
"-Wno-discarded-qualifiers",
"-Wno-sign-conversion",
+ "-Wno-cast-function-type",
]
# silence clang for unused gcc CFLAGS added by Debian
--- /dev/null
+[wrap-git]
+directory=glib
+url=git://git.gnome.org/glib
+push-url=ssh://git.gnome.org/git/glib
+revision=master
--- /dev/null
+[wrap-git]
+directory=gobject-introspection
+url=https://gitlab.gnome.org/GNOME/gobject-introspection.git
+push-url=git@gitlab.gnome.org:GNOME/gobject-introspection.git
+revision=master
--- /dev/null
+[wrap-git]
+directory=libffi
+url=https://github.com/centricular/libffi.git
+revision=meson
import subprocess
import atexit
import warnings
+import imp
+
+
+class GIImport:
+ def find_module(self, fullname, path=None):
+ if fullname == 'gi._gi':
+ 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)
+ sys.modules[name] = module
+ return module
+
+
+sys.meta_path.insert(0, GIImport())
def init_test_environ():
tests_srcdir = os.path.abspath(os.path.dirname(__file__))
srcdir = os.path.dirname(tests_srcdir)
+ sys.path.insert(0, os.path.join(builddir, 'gi'))
sys.path.insert(0, tests_srcdir)
sys.path.insert(0, srcdir)
sys.path.insert(0, tests_builddir)
# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
import sys
import pytest
#define EXTRA_TESTS
#include <glib-object.h>
+#include <gitestmacros.h>
typedef enum
{
GI_MARSHALLING_TESTS_EXTRA_FLAGS_VALUE2 = (gint)(1 << 31),
} GIMarshallingTestsExtraFlags;
+
+_GI_TEST_EXTERN
GType gi_marshalling_tests_extra_flags_get_type (void) G_GNUC_CONST;
#define GI_MARSHALLING_TESTS_TYPE_EXTRA_FLAGS (gi_marshalling_tests_extra_flags_get_type ())
+_GI_TEST_EXTERN
void gi_marshalling_tests_compare_two_gerrors_in_gvalue (GValue *v, GValue *v1);
+_GI_TEST_EXTERN
void gi_marshalling_tests_ghashtable_enum_none_in (GHashTable *hash_table);
+_GI_TEST_EXTERN
GHashTable * gi_marshalling_tests_ghashtable_enum_none_return (void);
+_GI_TEST_EXTERN
gchar * gi_marshalling_tests_filename_copy (gchar *path_in);
+_GI_TEST_EXTERN
gboolean gi_marshalling_tests_filename_exists (gchar *path);
+_GI_TEST_EXTERN
gchar * gi_marshalling_tests_filename_to_glib_repr (gchar *path_in, gsize *len);
+_GI_TEST_EXTERN
GIMarshallingTestsExtraEnum * gi_marshalling_tests_enum_array_return_type (gsize *n_members);
+_GI_TEST_EXTERN
void gi_marshalling_tests_extra_flags_large_in (GIMarshallingTestsExtraFlags value);
+_GI_TEST_EXTERN
gchar *gi_marshalling_tests_extra_utf8_full_return_invalid (void);
+_GI_TEST_EXTERN
void gi_marshalling_tests_extra_utf8_full_out_invalid (gchar **utf8);
#endif /* EXTRA_TESTS */
--- /dev/null
+gnome = import('gnome')
+
+host_system = host_machine.system()
+
+cc = meson.get_compiler('c')
+
+visibility_args = []
+if get_option('default_library') != 'static'
+ if host_system == 'windows'
+ visibility_args += ['-DDLL_EXPORT']
+ if cc.get_id() == 'msvc'
+ visibility_args += ['-D_GI_EXTERN=__declspec(dllexport) extern']
+ elif cc.has_argument('-fvisibility=hidden')
+ visibility_args += ['-D_GI_EXTERN=__attribute__((visibility("default"))) __declspec(dllexport) extern']
+ visibility_args += ['-fvisibility=hidden']
+ endif
+ elif cc.has_argument('-fvisibility=hidden')
+ visibility_args += ['-D_GI_EXTERN=__attribute__((visibility("default"))) extern']
+ visibility_args += ['-fvisibility=hidden']
+ endif
+endif
+
+if gi_dep.type_name() == 'pkgconfig'
+ gi_datadir = gi_dep.get_pkgconfig_variable('gidatadir')
+ regress_sources = [join_paths(gi_datadir, 'tests', 'regress.c')]
+ regress_headers = [join_paths(gi_datadir, 'tests', 'regress.h')]
+ regress_incdir = include_directories(join_paths(gi_datadir, 'tests'))
+ marshalling_sources = [join_paths(gi_datadir, 'tests', 'gimarshallingtests.c')]
+ marshalling_headers = [join_paths(gi_datadir, 'tests', 'gimarshallingtests.h')]
+else
+ gi_subproject = subproject('gobject-introspection')
+ regress_sources = gi_subproject.get_variable('test_regress_sources')
+ regress_headers = gi_subproject.get_variable('test_regress_headers')
+ regress_incdir = gi_subproject.get_variable('test_regress_incdirs')
+ marshalling_sources = gi_subproject.get_variable('test_marshalling_sources')
+ marshalling_headers = gi_subproject.get_variable('test_marshalling_headers')
+ gi_datadir = join_paths(meson.source_root(), 'subprojects', 'gobject-introspection', 'tests')
+endif
+
+marshalling_sources += ['gimarshallingtestsextra.c']
+
+marshalling_headers += ['gimarshallingtestsextra.h']
+
+marshalling_lib = library(
+ 'gimarshallingtests',
+ sources : marshalling_sources,
+ dependencies : [glib_dep, gobject_dep, gio_dep, gmodule_dep],
+ include_directories : regress_incdir,
+ c_args: visibility_args,
+)
+
+gnome.generate_gir(
+ marshalling_lib,
+ sources : marshalling_sources + marshalling_headers,
+ nsversion : '1.0',
+ namespace : 'GIMarshallingTests',
+ dependencies : [glib_dep, gobject_dep, gio_dep, gmodule_dep],
+ symbol_prefix : 'gi_marshalling_tests',
+ includes : ['Gio-2.0'],
+ build_by_default : true,
+)
+
+regress_sources += ['regressextra.c']
+
+regress_headers += ['regressextra.h']
+
+regress_deps = [glib_dep, gobject_dep, gio_dep, gmodule_dep]
+regress_c_args = []
+
+if with_pycairo
+ regress_deps += [cairo_dep, cairo_gobject_dep]
+else
+ regress_c_args += ['-D_GI_DISABLE_CAIRO']
+endif
+
+regress_lib = library(
+ 'regress',
+ sources : regress_sources,
+ dependencies : regress_deps,
+ include_directories : regress_incdir,
+ c_args: regress_c_args + visibility_args,
+)
+
+gnome.generate_gir(
+ regress_lib,
+ sources : regress_sources + regress_headers,
+ nsversion : '1.0',
+ namespace : 'Regress',
+ includes : ['Gio-2.0', 'cairo-1.0'],
+ build_by_default : true,
+ dependencies : regress_deps,
+ extra_args: regress_c_args,
+)
+
+helper_sources = [
+ 'testhelpermodule.c',
+ 'test-floating.c',
+ 'test-thread.c',
+ 'test-unknown.c']
+
+helperext = python.extension_module('testhelper', helper_sources,
+ dependencies : [python_dep, glib_dep, gobject_dep],
+ c_args: pyext_c_args + main_c_args,
+ include_directories: include_directories(join_paths('..', 'gi'))
+)
+
+schemas = gnome.compile_schemas(build_by_default: true)
+
+envdata = environment()
+envdata.append('GI_TYPELIB_PATH', meson.current_build_dir())
+if gi_dep.type_name() == 'internal'
+ envdata.append('GI_TYPELIB_PATH', join_paths(meson.build_root(), 'subprojects', 'gobject-introspection', 'gir'))
+endif
+
+if host_machine.system() == 'linux'
+ envdata.prepend('LD_LIBRARY_PATH', meson.current_build_dir())
+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(), '..'))
+envdata.append('TESTS_BUILDDIR', meson.current_build_dir())
+
+test('pygobject-test-suite', python,
+ args : [join_paths(meson.current_source_dir(), 'runtests.py')],
+ env : envdata,
+ timeout : 90)
<key name="test-enum" enum="org.gnome.test.FruitType">
<default>'banana'</default>
</key>
+ <key name="test-range" type="i">
+ <range min="7" max="65535"/>
+ <default>123</default>
+ </key>
</schema>
<schema id="org.gnome.nopathtest">
#ifndef _GI_DISABLE_CAIRO
+_GI_TEST_EXTERN
cairo_t *regress_test_cairo_context_none_return (void);
+_GI_TEST_EXTERN
void regress_test_cairo_context_full_in (cairo_t *context);
+_GI_TEST_EXTERN
cairo_path_t *regress_test_cairo_path_full_return (void);
+_GI_TEST_EXTERN
void regress_test_cairo_path_none_in (cairo_path_t *path);
+_GI_TEST_EXTERN
cairo_path_t * regress_test_cairo_path_full_in_full_return (cairo_path_t *path);
+_GI_TEST_EXTERN
cairo_font_options_t *regress_test_cairo_font_options_full_return (void);
+_GI_TEST_EXTERN
cairo_font_options_t *regress_test_cairo_font_options_none_return (void);
+_GI_TEST_EXTERN
void regress_test_cairo_font_options_full_in (cairo_font_options_t *options);
+_GI_TEST_EXTERN
void regress_test_cairo_font_options_none_in (cairo_font_options_t *options);
+_GI_TEST_EXTERN
void regress_test_cairo_region_full_in (cairo_region_t *region);
+_GI_TEST_EXTERN
void regress_test_cairo_surface_full_in (cairo_surface_t *surface);
+_GI_TEST_EXTERN
void regress_test_cairo_matrix_none_in (const cairo_matrix_t *matrix);
+_GI_TEST_EXTERN
cairo_matrix_t *regress_test_cairo_matrix_none_return (void);
+_GI_TEST_EXTERN
void regress_test_cairo_matrix_out_caller_allocates (cairo_matrix_t *matrix);
#endif
import os
import re
import platform
+import gc
import pytest
with warnings.catch_warnings(record=True) as warn:
warnings.simplefilter('always')
boxed = Everything.TestBoxedB(42, 47)
- self.assertTrue(issubclass(warn[0].category, TypeError))
+ self.assertTrue(issubclass(warn[0].category, DeprecationWarning))
self.assertEqual(boxed.some_int8, 0)
self.assertEqual(boxed.some_long, 0)
# - another owned by @obj
self.assertEqual(obj.refcount, 2)
del wrapper
+ gc.collect()
+ gc.collect()
self.assertEqual(obj.refcount, 1)
def test_boxed_c_wrapper_copy(self):
# - another owned by @obj
self.assertEqual(obj.refcount, 3)
del wrapper
+ gc.collect()
+ gc.collect()
self.assertEqual(obj.refcount, 2)
del wrapper_copy
+ gc.collect()
+ gc.collect()
self.assertEqual(obj.refcount, 1)
del obj
+ gc.collect()
+ gc.collect()
def test_array_fixed_boxed_none_out(self):
arr = Everything.test_array_fixed_boxed_none_out()
warnings.simplefilter('always')
GIMarshallingTests.Union(42)
- self.assertTrue(issubclass(warn[0].category, TypeError))
+ self.assertTrue(issubclass(warn[0].category, DeprecationWarning))
with warnings.catch_warnings(record=True) as warn:
warnings.simplefilter('always')
GIMarshallingTests.Union(f=42)
- self.assertTrue(issubclass(warn[0].category, TypeError))
+ self.assertTrue(issubclass(warn[0].category, DeprecationWarning))
def test_union(self):
union = GIMarshallingTests.Union()
import unittest
import warnings
+import pytest
+
import gi.overrides
from gi import PyGIWarning
from gi.repository import GLib, Gio
self.settings.reset('test-boolean')
self.settings.reset('test-enum')
+ def test_iter(self):
+ assert list(self.settings) == [
+ 'test-tuple', 'test-array', 'test-boolean', 'test-string',
+ 'test-enum', 'test-range']
+
+ def test_get_set(self):
+ for key in self.settings:
+ old_value = self.settings[key]
+ self.settings[key] = old_value
+ assert self.settings[key] == old_value
+
def test_native(self):
self.assertTrue('test-array' in self.settings.list_keys())
v = self.settings.get_value('test-tuple')
self.assertEqual(v.unpack(), (1, 2))
+ v = self.settings.get_value('test-range')
+ assert v.unpack() == 123
+
# set a value
self.settings.set_string('test-string', 'World')
self.assertEqual(self.settings.get_string('test-string'), 'World')
self.assertEqual(with_path['np-int'], 42)
def test_dictionary_api(self):
- self.assertEqual(len(self.settings), 5)
+ self.assertEqual(len(self.settings), 6)
self.assertTrue('test-array' in self.settings)
self.assertTrue('test-array' in self.settings.keys())
self.assertFalse('nonexisting' in self.settings)
self.assertRaises(ValueError, self.settings.__setitem__, 'test-enum', 'plum')
self.assertRaises(KeyError, self.settings.__setitem__, 'unknown', 'moo')
+ def test_set_range(self):
+ self.settings['test-range'] = 7
+ assert self.settings['test-range'] == 7
+ self.settings['test-range'] = 65535
+ assert self.settings['test-range'] == 65535
+
+ with pytest.raises(ValueError, match=".*7 - 65535.*"):
+ self.settings['test-range'] = 7 - 1
+
+ with pytest.raises(ValueError, match=".*7 - 65535.*"):
+ self.settings['test-range'] = 65535 + 1
+
def test_empty(self):
empty = Gio.Settings.new_with_path('org.gnome.empty', '/tests/')
self.assertEqual(len(empty), 0)
import unittest
import warnings
-from gi.repository import GObject, GLib
+import pytest
+
+from gi.repository import GObject, GLib, Gio
from gi import PyGIDeprecationWarning
from gi.module import get_introspection_module
from gi import _gi
-from . import testhelper
+import testhelper
class TestGObjectAPI(unittest.TestCase):
value.set_value(42.0)
self.assertEqual(value.get_value(), 42)
+ def test_multi_del(self):
+ value = GObject.Value(str, 'foo_bar')
+ value.__del__()
+ value.__del__()
+ del value
+
def test_string(self):
value = GObject.Value(str, 'foo_bar')
self.assertEqual(value.g_type, GObject.TYPE_STRING)
value.set_value([32, 'foo_bar', 0.3])
self.assertEqual(value.get_value(), [32, 'foo_bar', 0.3])
+ def test_value_array_from_gvalue_list(self):
+ value = GObject.Value(GObject.ValueArray, [
+ GObject.Value(GObject.TYPE_UINT, 0xffffffff),
+ GObject.Value(GObject.TYPE_STRING, 'foo_bar')])
+ self.assertEqual(value.g_type, GObject.type_from_name('GValueArray'))
+ self.assertEqual(value.get_value(), [0xffffffff, 'foo_bar'])
+ self.assertEqual(testhelper.value_array_get_nth_type(value, 0), GObject.TYPE_UINT)
+ 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)
+
def test_gerror_boxing(self):
error = GLib.Error('test message', domain='mydomain', code=42)
value = GObject.Value(GLib.Error, error)
value = GObject.Value(GLib.Error)
self.assertEqual(value.g_type, GObject.type_from_name('GError'))
self.assertEqual(value.get_value(), None)
+
+
+def test_list_properties():
+
+ def find_param(l, name):
+ for param in l:
+ if param.name == name:
+ return param
+ return
+
+ list_props = GObject.list_properties
+
+ props = list_props(Gio.Action)
+ param = find_param(props, "enabled")
+ assert param
+ assert param.value_type == GObject.TYPE_BOOLEAN
+ assert list_props("GAction") == list_props(Gio.Action)
+ assert list_props(Gio.Action.__gtype__) == list_props(Gio.Action)
+
+ props = list_props(Gio.SimpleAction)
+ assert find_param(props, "enabled")
+
+ def names(l):
+ return [p.name for p in l]
+
+ assert (set(names(list_props(Gio.Action))) <=
+ set(names(list_props(Gio.SimpleAction))))
+
+ props = list_props(Gio.FileIcon)
+ param = find_param(props, "file")
+ assert param
+ assert param.value_type == Gio.File.__gtype__
+
+ assert list_props("GFileIcon") == list_props(Gio.FileIcon)
+ assert list_props(Gio.FileIcon.__gtype__) == list_props(Gio.FileIcon)
+ assert list_props(Gio.FileIcon()) == list_props(Gio.FileIcon)
+
+ for obj in [Gio.ActionEntry, Gio.DBusError, 0, object()]:
+ with pytest.raises(TypeError):
+ list_props(obj)
Gtk.Template.from_string("bla")
Gtk.Template.from_resource("foo")
Gtk.Template.from_file("foo")
+
+
+def test_child_construct():
+ Gtk.Template.Child()
+ Gtk.Template.Child("name")
+ with pytest.raises(TypeError):
+ Gtk.Template.Child("name", True)
+ Gtk.Template.Child("name", internal=True)
+ with pytest.raises(TypeError):
+ Gtk.Template.Child("name", internal=True, something=False)
+
+
+def test_internal_child():
+
+ main_type_name = new_gtype_name()
+
+ xml = """\
+ <interface>
+ <template class="{0}" parent="GtkBox">
+ <child>
+ <object class="GtkBox" id="somechild">
+ <property name="margin">42</property>
+ </object>
+ </child>
+ </template>
+ </interface>
+ """.format(main_type_name)
+
+ @Gtk.Template.from_string(xml)
+ class MainThing(Gtk.Box):
+ __gtype_name__ = main_type_name
+
+ somechild = Gtk.Template.Child(internal=True)
+
+ thing = MainThing()
+ assert thing.somechild.props.margin == 42
+
+ other_type_name = new_gtype_name()
+
+ xml = """\
+ <interface>
+ <template class="{0}" parent="GtkBox">
+ <child>
+ <object class="{1}">
+ <child internal-child="somechild">
+ <object class="GtkBox">
+ <property name="margin">24</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="label">foo</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+ </interface>
+ """.format(other_type_name, main_type_name)
+
+ @Gtk.Template.from_string(xml)
+ class OtherThing(Gtk.Box):
+ __gtype_name__ = other_type_name
+
+ other = OtherThing()
+ child = other.get_children()[0]
+ assert isinstance(child, MainThing)
+ child = child.get_children()[0]
+ assert isinstance(child, Gtk.Box)
+ assert child.props.margin == 24
+ child = child.get_children()[0]
+ assert isinstance(child, Gtk.Label)
+ assert child.props.label == "foo"
import unittest
from gi.repository import GObject
-from . import testhelper
+import testhelper
GUnknown = GObject.type_from_name("TestUnknown")
from gi.repository import GLib, GObject
from gi._compat import PY3
-from . import testhelper
+import testhelper
class PyGObject(GObject.GObject):
with pytest.raises(TypeError):
testhelper.test_to_unichar_conv(u"AA")
+
+
+def test_constant_strip_prefix():
+ assert testhelper.constant_strip_prefix("foo", "bar") == "foo"
+ assert testhelper.constant_strip_prefix("foo", "f") == "oo"
+ assert testhelper.constant_strip_prefix("foo", "f") == "oo"
+ assert testhelper.constant_strip_prefix("ha2foo", "ha") == "a2foo"
+ assert testhelper.constant_strip_prefix("2foo", "ha") == "2foo"
+ assert testhelper.constant_strip_prefix("bla_foo", "bla") == "_foo"
+
+
+def test_state_ensure_release():
+ testhelper.test_state_ensure_release()
with warnings.catch_warnings(record=True) as warn:
warnings.simplefilter('always')
ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_out_object_transfer_none()
- self.assertTrue(issubclass(warn[0].category, RuntimeWarning))
+ if hasattr(sys, "getrefcount"):
+ self.assertTrue(issubclass(warn[0].category, RuntimeWarning))
# The ref count of the GObject returned to the caller (get_ref_info_for_vfunc_return_object_transfer_none)
# should be a single floating ref
- self.assertEqual(ref_count, 1)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(ref_count, 1)
self.assertFalse(is_floating)
gc.collect()
with warnings.catch_warnings(record=True) as warn:
warnings.simplefilter('always')
ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_out_object_transfer_none()
- self.assertTrue(issubclass(warn[0].category, RuntimeWarning))
+ if hasattr(sys, "getrefcount"):
+ self.assertTrue(issubclass(warn[0].category, RuntimeWarning))
- self.assertEqual(ref_count, 1)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(ref_count, 1)
self.assertFalse(is_floating)
gc.collect()
# The vfunc caller receives full ownership of a single ref which should not
# be floating.
- self.assertEqual(ref_count, 1)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(ref_count, 1)
self.assertFalse(is_floating)
gc.collect()
vfuncs = self.VFuncs()
ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_out_object_transfer_full()
- self.assertEqual(ref_count, 1)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(ref_count, 1)
self.assertFalse(is_floating)
gc.collect()
self.assertEqual(vfuncs.in_object_grefcount, 2) # initial + python wrapper
self.assertFalse(vfuncs.in_object_is_floating)
- self.assertEqual(ref_count, 1) # ensure python wrapper released
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(ref_count, 1) # ensure python wrapper released
self.assertFalse(is_floating)
+ gc.collect()
+ gc.collect()
self.assertTrue(vfuncs.object_ref() is None)
def test_vfunc_in_object_transfer_full(self):
self.assertFalse(vfuncs.in_object_is_floating)
# ensure python wrapper took ownership and released, after vfunc was complete
- self.assertEqual(ref_count, 0)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(ref_count, 0)
self.assertFalse(is_floating)
+ gc.collect()
+ gc.collect()
self.assertTrue(vfuncs.object_ref() is None)
Object = GObject.InitiallyUnowned
ObjectRef = weakref.ref
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), "refcount specific")
def test_vfunc_return_object_transfer_none_with_floating(self):
# Python is expected to return a single floating reference without warning.
vfuncs = self.VFuncs()
gc.collect()
self.assertTrue(vfuncs.object_ref() is None)
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), "refcount specific")
def test_vfunc_out_object_transfer_none_with_floating(self):
# Same as above except uses out arg instead of return
vfuncs = self.VFuncs()
ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_return_object_transfer_full()
# The vfunc caller receives full ownership of a single ref.
- self.assertEqual(ref_count, 1)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(ref_count, 1)
self.assertFalse(is_floating)
gc.collect()
vfuncs = self.VFuncs()
ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_out_object_transfer_full()
- self.assertEqual(ref_count, 1)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(ref_count, 1)
self.assertFalse(is_floating)
gc.collect()
self.assertTrue(vfuncs.in_object_is_floating)
# vfunc caller should only have a single floating ref after the vfunc finishes
- self.assertEqual(ref_count, 1)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(ref_count, 1)
self.assertTrue(is_floating)
+ gc.collect()
+ gc.collect()
self.assertTrue(vfuncs.object_ref() is None)
def test_vfunc_in_object_transfer_full_with_floating(self):
self.assertFalse(vfuncs.in_object_is_floating)
# ensure python wrapper took ownership and released
- self.assertEqual(ref_count, 0)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(ref_count, 0)
self.assertFalse(is_floating)
+ gc.collect()
+ gc.collect()
self.assertTrue(vfuncs.object_ref() is None)
self.parser.add_option_group(group)
return group
- def test_parse_args(self):
+ def test_integer(self):
+ self._create_group()
options, args = self.parser.parse_args(
- ["test_option.py"])
- self.assertFalse(args)
+ ["--test-integer", "42", "bla"])
+ assert options.test_integer == 42
+ assert args == ["bla"]
+
+ def test_file(self):
+ self._create_group()
options, args = self.parser.parse_args(
- ["test_option.py", "foo"])
- self.assertEqual(args, [])
+ ["--file", "fn", "bla"])
+ assert options.unit_file == "fn"
+ assert args == ["bla"]
+
+ def test_mixed(self):
+ self._create_group()
options, args = self.parser.parse_args(
- ["test_option.py", "foo", "bar"])
- self.assertEqual(args, [])
+ ["--file", "fn", "--test-integer", "12", "--test",
+ "--g-fatal-warnings", "nope"])
+
+ assert options.unit_file == "fn"
+ assert options.test_integer == 12
+ assert options.test is False
+ assert options.fatal_warnings is True
+ assert args == ["nope"]
+
+ def test_parse_args(self):
+ options, args = self.parser.parse_args([])
+ self.assertFalse(args)
+
+ options, args = self.parser.parse_args(["foo"])
+ self.assertEqual(args, ["foo"])
+
+ options, args = self.parser.parse_args(["foo", "bar"])
+ self.assertEqual(args, ["foo", "bar"])
def test_parse_args_double_dash(self):
- options, args = self.parser.parse_args(
- ["test_option.py", "--", "-xxx"])
- # self.assertEqual(args, ["-xxx"])
+ options, args = self.parser.parse_args(["--", "-xxx"])
+ self.assertEqual(args, ["--", "-xxx"])
def test_parse_args_group(self):
group = self._create_group()
options, args = self.parser.parse_args(
- ["test_option.py", "--test", "-f", "test"])
+ ["--test", "-f", "test"])
self.assertFalse(options.test)
self.assertEqual(options.unit_file, "test")
def test_option_value_error(self):
self._create_group()
self.assertRaises(GLib.option.OptionValueError, self.parser.parse_args,
- ["test_option.py", "--test-integer=text"])
+ ["--test-integer=text"])
def test_bad_option_error(self):
self.assertRaises(GLib.option.BadOptionError,
self.parser.parse_args,
- ["test_option.py", "--unknwon-option"])
+ ["--unknwon-option"])
def test_option_group_constructor(self):
self.assertRaises(TypeError, GLib.option.OptionGroup)
self._create_group()
with capture_exceptions() as exc:
- self.parser.parse_args(
- ["test_option.py", "--callback-failure-test"])
+ self.parser.parse_args(["--callback-failure-test"])
assert len(exc) == 1
assert exc[0].value.args[0] == "foo"
--- /dev/null
+from __future__ import absolute_import
+
+import random
+import platform
+
+import pytest
+
+from gi.repository import Gio, GObject
+from gi._compat import cmp
+
+
+class Item(GObject.Object):
+ _id = 0
+
+ def __init__(self, **kwargs):
+ super(Item, self).__init__(**kwargs)
+ Item._id += 1
+ self._id = self._id
+
+ def __repr__(self):
+ return str(self._id)
+
+
+class NamedItem(Item):
+
+ name = GObject.Property(type=str, default='')
+
+ def __repr__(self):
+ return self.props.name
+
+
+def test_list_store_sort():
+ store = Gio.ListStore()
+ items = [NamedItem(name=n) for n in "cabx"]
+ sorted_items = sorted(items, key=lambda i: i.props.name)
+
+ user_data = [object(), object()]
+
+ def sort_func(a, b, *args):
+ assert list(args) == user_data
+ assert isinstance(a, NamedItem)
+ assert isinstance(b, NamedItem)
+ return cmp(a.props.name, b.props.name)
+
+ store[:] = items
+ assert store[:] != sorted_items
+ store.sort(sort_func, *user_data)
+ assert store[:] == sorted_items
+
+
+def test_list_store_insert_sorted():
+ store = Gio.ListStore()
+ items = [NamedItem(name=n) for n in "cabx"]
+ sorted_items = sorted(items, key=lambda i: i.props.name)
+
+ user_data = [object(), object()]
+
+ def sort_func(a, b, *args):
+ assert list(args) == user_data
+ assert isinstance(a, NamedItem)
+ assert isinstance(b, NamedItem)
+ return cmp(a.props.name, b.props.name)
+
+ for item in items:
+ index = store.insert_sorted(item, sort_func, *user_data)
+ assert isinstance(index, int)
+ assert store[:] == sorted_items
+
+
+def test_list_model_len():
+ model = Gio.ListStore.new(Item)
+ assert len(model) == 0
+ assert not model
+ for i in range(1, 10):
+ model.append(Item())
+ assert len(model) == i
+ assert model
+ model.remove_all()
+ assert not model
+ assert len(model) == 0
+
+
+def test_list_model_get_item_simple():
+ model = Gio.ListStore.new(Item)
+ with pytest.raises(IndexError):
+ model[0]
+ first_item = Item()
+ model.append(first_item)
+ assert model[0] is first_item
+ assert model[-1] is first_item
+ second_item = Item()
+ model.append(second_item)
+ assert model[1] is second_item
+ assert model[-1] is second_item
+ assert model[-2] is first_item
+ with pytest.raises(IndexError):
+ model[-3]
+
+ with pytest.raises(TypeError):
+ model[object()]
+
+
+def test_list_model_get_item_slice():
+ model = Gio.ListStore.new(Item)
+ source = [Item() for i in range(30)]
+ for i in source:
+ model.append(i)
+ assert model[1:10] == source[1:10]
+ assert model[1:-2] == source[1:-2]
+ assert model[-4:-1] == source[-4:-1]
+ assert model[-100:-1] == source[-100:-1]
+ assert model[::-1] == source[::-1]
+ assert model[:] == source[:]
+
+
+def test_list_model_contains():
+ model = Gio.ListStore.new(Item)
+ item = Item()
+ model.append(item)
+ assert item in model
+ assert Item() not in model
+ with pytest.raises(TypeError):
+ object() in model
+ with pytest.raises(TypeError):
+ None in model
+
+
+def test_list_model_iter():
+ model = Gio.ListStore.new(Item)
+ item = Item()
+ model.append(item)
+
+ it = iter(model)
+ assert next(it) is item
+ repr(item)
+
+
+def test_list_store_delitem_simple():
+ store = Gio.ListStore.new(Item)
+ store.append(Item())
+ del store[0]
+ assert not store
+ with pytest.raises(IndexError):
+ del store[0]
+ with pytest.raises(IndexError):
+ del store[-1]
+
+ store.append(Item())
+ with pytest.raises(IndexError):
+ del store[-2]
+ del store[-1]
+ assert not store
+
+ source = [Item(), Item()]
+ store.append(source[0])
+ store.append(source[1])
+ del store[-1]
+ assert store[:] == [source[0]]
+
+ with pytest.raises(TypeError):
+ del store[object()]
+
+
+def test_list_store_delitem_slice():
+
+ def do_del(count, key):
+
+ events = []
+
+ def on_changed(m, *args):
+ events.append(args)
+
+ store = Gio.ListStore.new(Item)
+ source = [Item() for i in range(count)]
+ for item in source:
+ store.append(item)
+ store.connect("items-changed", on_changed)
+ source.__delitem__(key)
+ store.__delitem__(key)
+ assert source == store[:]
+ return events
+
+ values = [None, 1, -15, 3, -2, 0, -3, 5, 7]
+ variants = set()
+ for i in range(500):
+ start = random.choice(values)
+ stop = random.choice(values)
+ step = random.choice(values)
+ length = abs(random.choice(values) or 0)
+ if step == 0:
+ step += 1
+ variants.add((length, start, stop, step))
+
+ for length, start, stop, step in variants:
+ do_del(length, slice(start, stop, step))
+
+ # basics
+ do_del(10, slice(None, None, None))
+ do_del(10, slice(None, None, None))
+ do_del(10, slice(None, None, -1))
+ do_del(10, slice(0, 5, None))
+ do_del(10, slice(0, 10, 1))
+ do_del(10, slice(0, 10, 2))
+ do_del(10, slice(14, 2, -1))
+
+ # test some fast paths
+ assert do_del(100, slice(None, None, None)) == [(0, 100, 0)]
+ assert do_del(100, slice(None, None, -1)) == [(0, 100, 0)]
+ assert do_del(100, slice(0, 50, 1)) == [(0, 50, 0)]
+
+
+def test_list_store_setitem_simple():
+
+ store = Gio.ListStore.new(Item)
+ first = Item()
+ store.append(first)
+
+ class Wrong(GObject.Object):
+ pass
+
+ with pytest.raises(TypeError):
+ store[0] = object()
+ with pytest.raises(TypeError):
+ store[0] = None
+ with pytest.raises(TypeError):
+ store[0] = Wrong()
+
+ assert store[:] == [first]
+
+ new = Item()
+ store[0] = new
+ assert len(store) == 1
+ store[-1] = Item()
+ assert len(store) == 1
+
+ with pytest.raises(IndexError):
+ store[1] = Item()
+ with pytest.raises(IndexError):
+ store[-2] = Item()
+
+ store = Gio.ListStore.new(Item)
+ source = [Item(), Item(), Item()]
+ for item in source:
+ store.append(item)
+ new = Item()
+ store[1] = new
+ assert store[:] == [source[0], new, source[2]]
+
+ with pytest.raises(TypeError):
+ store[object()] = Item()
+
+
+def test_list_store_setitem_slice():
+
+ def do_set(count, key, new_count):
+ if count == 0 and key.step is not None \
+ and platform.python_implementation() == "PyPy":
+ # https://bitbucket.org/pypy/pypy/issues/2804
+ return
+ store = Gio.ListStore.new(Item)
+ source = [Item() for i in range(count)]
+ new = [Item() for i in range(new_count)]
+ for item in source:
+ store.append(item)
+ source_error = None
+ try:
+ source.__setitem__(key, new)
+ except ValueError as e:
+ source_error = type(e)
+
+ store_error = None
+ try:
+ store.__setitem__(key, new)
+ except Exception as e:
+ store_error = type(e)
+
+ assert source_error == store_error
+ assert source == store[:]
+
+ values = [None, 1, -15, 3, -2, 0, 3, 4, 100]
+ variants = set()
+ for i in range(500):
+ start = random.choice(values)
+ stop = random.choice(values)
+ step = random.choice(values)
+ length = abs(random.choice(values) or 0)
+ new = random.choice(values) or 0
+ if step == 0:
+ step += 1
+ variants.add((length, start, stop, step, new))
+
+ for length, start, stop, step, new in variants:
+ do_set(length, slice(start, stop, step), new)
+
+ # basics
+ do_set(10, slice(None, None, None), 20)
+ do_set(10, slice(None, None, None), 0)
+ do_set(10, slice(None, None, -1), 20)
+ do_set(10, slice(None, None, -1), 10)
+ do_set(10, slice(0, 5, None), 20)
+ do_set(10, slice(0, 10, 1), 0)
+
+ # test iterators
+ store = Gio.ListStore.new(Item)
+ store[:] = iter([Item() for i in range(10)])
+ assert len(store) == 10
+
+ # make sure we do all or nothing
+ store = Gio.ListStore.new(Item)
+ with pytest.raises(TypeError):
+ store[:] = [Item(), object()]
+ assert len(store) == 0
+
+
+def test_action_map_add_action_entries():
+ actionmap = Gio.SimpleActionGroup()
+
+ test_data = []
+
+ def f(action, parameter, data):
+ test_data.append('test back')
+
+ actionmap.add_action_entries((
+ ("simple", f),
+ ("with_type", f, "i"),
+ ("with_state", f, "s", "'left'", f),
+ ))
+ assert actionmap.has_action("simple")
+ assert actionmap.has_action("with_type")
+ assert actionmap.has_action("with_state")
+ actionmap.add_action_entries((
+ ("with_user_data", f),
+ ), "user_data")
+ assert actionmap.has_action("with_user_data")
+
+ with pytest.raises(TypeError):
+ actionmap.add_action_entries((
+ ("invaild_type_string", f, 'asdf'),
+ ))
+ with pytest.raises(ValueError):
+ actionmap.add_action_entries((
+ ("stateless_with_change_state", f, None, None, f),
+ ))
+
+ actionmap.activate_action("simple")
+ assert test_data[0] == 'test back'
@unittest.skipUnless(Gtk, 'Gtk not available')
+def test_freeze_child_notif():
+
+ events = []
+
+ def on_notify(widget, spec):
+ events.append(spec.name)
+
+ b = Gtk.Box()
+ c = Gtk.Button()
+ c.connect("child-notify", on_notify)
+ c.freeze_child_notify()
+ b.pack_start(c, True, True, 0)
+ b.child_set_property(c, "expand", False)
+ b.child_set_property(c, "expand", True)
+ c.thaw_child_notify()
+ assert events.count("expand") == 1
+ del events[:]
+
+ with c.freeze_child_notify():
+ b.child_set_property(c, "expand", True)
+ b.child_set_property(c, "expand", False)
+
+ assert events.count("expand") == 1
+
+
+@unittest.skipUnless(Gtk, 'Gtk not available')
def test_wrapper_toggle_refs():
class MyButton(Gtk.Button):
def __init__(self, height):
from gi import _propertyhelper as propertyhelper
from gi._compat import long_, PY3, PY2
-from .helper import capture_glib_warnings, capture_output
+from .helper import capture_glib_warnings
class PropertyObject(GObject.GObject):
self.assertEqual(o.prop, 'value')
self.assertRaises(TypeError, setattr, o, 'prop', 'xxx')
- @unittest.expectedFailure # https://bugzilla.gnome.org/show_bug.cgi?id=575652
def test_getter_exception(self):
class C(GObject.Object):
@GObject.Property(type=int)
o = C()
- # silence exception printed to stderr
- with capture_output():
- with self.assertRaisesRegex(ValueError, 'something bad happend'):
- o.prop
+ with self.assertRaisesRegex(ValueError, 'something bad happend'):
+ o.prop
- with self.assertRaisesRegex(ValueError, 'something bad happend'):
- o.get_property('prop')
+ with self.assertRaisesRegex(ValueError, 'something bad happend'):
+ o.get_property('prop')
- with self.assertRaisesRegex(ValueError, 'something bad happend'):
- o.props.prop
+ with self.assertRaisesRegex(ValueError, 'something bad happend'):
+ o.props.prop
def test_custom_setter(self):
class C(GObject.GObject):
obj = GIMarshallingTests.PropertiesObject(some_char=-42)
self.assertEqual(self.get_prop(obj, 'some-char'), -42)
+ with pytest.raises(OverflowError):
+ self.set_prop(obj, 'some-char', GLib.MAXINT8 + 1)
+ with pytest.raises(OverflowError):
+ self.set_prop(obj, 'some-char', GLib.MININT8 - 1)
+
+ self.set_prop(obj, 'some-char', b"\x44")
+ assert self.get_prop(obj, 'some-char') == 0x44
+
+ self.set_prop(obj, 'some-char', b"\xff")
+ assert self.get_prop(obj, 'some-char') == -1
+
+ obj = GIMarshallingTests.PropertiesObject(some_char=u"\x7f")
+ assert self.get_prop(obj, 'some-char') == 0x7f
+
+ with pytest.raises(TypeError):
+ GIMarshallingTests.PropertiesObject(some_char=u"€")
+
+ with pytest.raises(TypeError):
+ GIMarshallingTests.PropertiesObject(some_char=u"\ud83d")
+
def test_uchar(self):
self.assertEqual(self.get_prop(self.obj, 'some-uchar'), 0)
self.set_prop(self.obj, 'some-uchar', GLib.MAXUINT8)
obj = GIMarshallingTests.PropertiesObject(some_uchar=42)
self.assertEqual(self.get_prop(obj, 'some-uchar'), 42)
+ with pytest.raises(OverflowError):
+ self.set_prop(obj, 'some-uchar', GLib.MAXUINT8 + 1)
+ with pytest.raises(OverflowError):
+ self.set_prop(obj, 'some-uchar', -1)
+
+ self.set_prop(obj, 'some-uchar', b"\x57")
+ assert self.get_prop(obj, 'some-uchar') == 0x57
+
+ self.set_prop(obj, 'some-uchar', b"\xff")
+ assert self.get_prop(obj, 'some-uchar') == 255
+
+ obj = GIMarshallingTests.PropertiesObject(some_uchar=u"\x7f")
+ assert self.get_prop(obj, 'some-uchar') == 127
+
+ with pytest.raises(TypeError):
+ GIMarshallingTests.PropertiesObject(some_uchar=u"\x80")
+
+ with pytest.raises(TypeError):
+ GIMarshallingTests.PropertiesObject(some_uchar=u"\ud83d")
+
def test_int(self):
self.assertEqual(self.get_prop(self.obj, 'some_int'), 0)
self.set_prop(self.obj, 'some-int', GLib.MAXINT)
from gi.module import repository as repo
from gi._compat import PY3, long_
-from . import testhelper
+import testhelper
from .helper import capture_glib_warnings, capture_gi_deprecation_warnings
gc.collect()
self.assertTrue(self.finalized)
- @unittest.skip('https://bugzilla.gnome.org/show_bug.cgi?id=722387')
def test_python_unref_with_active_source(self):
# Tests a Python derived Source which is free'd in the context of
- # Python, but remains active in the MainContext (via source.attach())
+ # Python, but which was attached to a MainContext (via source.attach())
self.dispatched = False
self.finalized = False
def finalize(s):
self.finalized = True
+ context = GLib.MainContext.new()
source = S()
- id = source.attach()
+ id_ = source.attach(context)
self.assertFalse(self.finalized)
self.assertFalse(source.is_destroyed())
- # Delete the source from Python but should still remain
- # active in the main context.
+ # Delete the source from Python, it should detach
del source
+ gc.collect()
+ gc.collect()
- context = GLib.MainContext.default()
while context.iteration(may_block=False):
pass
- self.assertTrue(self.dispatched)
- self.assertFalse(self.finalized)
-
- source = context.find_source_by_id(id)
- source.destroy() # Remove from main context.
- self.assertTrue(source.is_destroyed())
-
- # Source should be finalized called after del
- del source
- self.assertTrue(self.finalized)
+ assert self.finalized
+ assert not self.dispatched
+ assert context.find_source_by_id(id_) is None
def test_extra_init_args(self):
class SourceWithInitArgs(GLib.Source):
from gi.repository import GLib
-from . import testhelper
+import testhelper
class TestThread(unittest.TestCase):
from gi.repository import GObject
-from . import testhelper
+import testhelper
TestInterface = GObject.GType.from_name('TestInterface')
}
static PyObject *
+_wrap_test_state_ensure_release(PyObject *self, PyObject *args)
+{
+ int state = pyg_gil_state_ensure ();
+ pyg_gil_state_release (state);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *
_wrap_test_value_array(PyObject *self, PyObject *args)
{
GValue tvalue = {0,}, *value = &tvalue;
return pyg_value_as_pyobject(value, FALSE);
}
+
+static PyObject *
+_wrap_value_array_get_nth_type(PyObject *self, PyObject *args)
+{
+ guint n;
+ GType type;
+ GValue *nth;
+ GValueArray *arr;
+ PyObject *obj;
+
+ if (!PyArg_ParseTuple(args, "OI", &obj, &n))
+ return NULL;
+
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+
+ if (pyg_boxed_check(obj, G_TYPE_VALUE) &&
+ G_VALUE_HOLDS(pyg_boxed_get(obj, GValue), G_TYPE_VALUE_ARRAY)) {
+ arr = g_value_get_boxed(pyg_boxed_get(obj, GValue));
+ } else if (pyg_boxed_check(obj, G_TYPE_VALUE_ARRAY)) {
+ arr = pyg_boxed_get(obj, GValueArray);
+ } else {
+ PyErr_SetString(PyExc_TypeError, "First argument is not GValueArray");
+ return NULL;
+ }
+
+ if (n >= arr->n_values) {
+ PyErr_SetString(PyExc_TypeError, "Index is out of bounds");
+ return NULL;
+ }
+ nth = g_value_array_get_nth(arr, n);
+ type = G_VALUE_TYPE(nth);
+
+ G_GNUC_END_IGNORE_DEPRECATIONS
+
+ return pyg_type_wrapper_new(type);
+}
+
+static PyObject *
+_wrap_constant_strip_prefix(PyObject *self, PyObject *args)
+{
+ const char *name, *strip_prefix;
+ const gchar *result;
+
+ if (!PyArg_ParseTuple (args, "ss", &name, &strip_prefix))
+ return NULL;
+
+ result = pyg_constant_strip_prefix (name, strip_prefix);
+ return PYGLIB_PyUnicode_FromString (result);
+}
+
static PyObject *
_wrap_test_gerror_exception(PyObject *self, PyObject *args)
{
{ "test_to_unichar_conv", (PyCFunction)_wrap_test_to_unichar_conv, METH_VARARGS },
{ "get_unknown", (PyCFunction)_wrap_get_unknown, METH_NOARGS },
{ "create_test_type", (PyCFunction)_wrap_create_test_type, METH_NOARGS },
+ { "test_state_ensure_release", (PyCFunction)_wrap_test_state_ensure_release, METH_NOARGS },
{ "test_g_object_new", (PyCFunction)_wrap_test_g_object_new, METH_NOARGS },
{ "connectcallbacks", (PyCFunction)_wrap_connectcallbacks, METH_VARARGS },
{ "test_value", (PyCFunction)_wrap_test_value, METH_VARARGS },
{ "test_value_array", (PyCFunction)_wrap_test_value_array, METH_VARARGS },
+ { "value_array_get_nth_type", (PyCFunction)_wrap_value_array_get_nth_type, METH_VARARGS },
+ { "constant_strip_prefix", (PyCFunction)_wrap_constant_strip_prefix, METH_VARARGS },
{ "test_gerror_exception", (PyCFunction)_wrap_test_gerror_exception, METH_VARARGS },
{ "owned_by_library_get_instance_list", (PyCFunction)_wrap_test_owned_by_library_get_instance_list, METH_NOARGS },
{ "floating_and_sunk_get_instance_list", (PyCFunction)_wrap_test_floating_and_sunk_get_instance_list, METH_NOARGS },
--- /dev/null
+# https://bugzilla.redhat.com/show_bug.cgi?id=1538073
+
+{
+ <py36-start1>
+ Memcheck:Cond
+ fun:__wcsnlen_sse4_1
+ fun:wcsrtombs
+ fun:wcstombs
+ fun:wcstombs
+ fun:encode_current_locale*
+}
+
+{
+ <fontconfig>
+ Memcheck:Leak
+ match-leak-kinds: definite
+ fun:malloc
+ fun:FcPatternObjectInsertElt
+ fun:FcPatternObjectAddWithBinding
+}
+
+{
+ <fontconfig-2>
+ Memcheck:Leak
+ match-leak-kinds: definite
+ fun:malloc
+ fun:FcPatternCreate
+ fun:FcParsePattern
+ fun:FcEndElement
+}