`_ provides python
wrappers for the :term:`Qt` widgets library and is required by
@@ -82,14 +97,12 @@ Glossary
language widely used for scripting, application development, web
application servers, scientific computing and more.
-
pytz
`pytz `_ provides the Olson tz
database in Python. it allows accurate and cross platform
timezone calculations and solves the issue of ambiguous times at
the end of daylight savings
-
Qt
`Qt `__ is a cross-platform
application framework for desktop and embedded development.
diff --git a/doc/users/next_whats_new/2017-12-04-AL-pgi.rst b/doc/users/next_whats_new/2017-12-04-AL-pgi.rst
new file mode 100644
index 000000000000..4f774bef6989
--- /dev/null
+++ b/doc/users/next_whats_new/2017-12-04-AL-pgi.rst
@@ -0,0 +1,19 @@
+PGI bindings for gtk3
+---------------------
+
+The GTK3 backends can now use PGI_ instead of PyGObject_. PGI is a fairly
+incomplete binding for GObject, thus its use is not recommended; its main
+benefit is its availability on Travis (thus allowing CI testing for the gtk3agg
+and gtk3cairo backends).
+
+The binding selection rules are as follows:
+- if ``gi`` has already been imported, use it; else
+- if ``pgi`` has already been imported, use it; else
+- if ``gi`` can be imported, use it; else
+- if ``pgi`` can be imported, use it; else
+- error out.
+
+Thus, to force usage of PGI when both bindings are installed, import it first.
+
+.. _PGI: https://pgi.readthedocs.io/en/latest/
+.. _PyGObject: http://pygobject.readthedocs.io/en/latest/#
diff --git a/lib/matplotlib/backends/_gtk3_compat.py b/lib/matplotlib/backends/_gtk3_compat.py
new file mode 100644
index 000000000000..825fa2341c80
--- /dev/null
+++ b/lib/matplotlib/backends/_gtk3_compat.py
@@ -0,0 +1,41 @@
+"""
+GObject compatibility loader; supports ``gi`` and ``pgi``.
+
+The binding selection rules are as follows:
+- if ``gi`` has already been imported, use it; else
+- if ``pgi`` has already been imported, use it; else
+- if ``gi`` can be imported, use it; else
+- if ``pgi`` can be imported, use it; else
+- error out.
+
+Thus, to force usage of PGI when both bindings are installed, import it first.
+"""
+
+from __future__ import (absolute_import, division, print_function,
+ unicode_literals)
+
+import six
+
+import importlib
+import sys
+
+
+if "gi" in sys.modules:
+ import gi
+elif "pgi" in sys.modules:
+ import pgi as gi
+else:
+ try:
+ import gi
+ except ImportError:
+ try:
+ import pgi as gi
+ except ImportError:
+ raise ImportError("The Gtk3 backend requires PyGObject or pgi")
+
+
+gi.require_version("Gtk", "3.0")
+globals().update(
+ {name:
+ importlib.import_module("{}.repository.{}".format(gi.__name__, name))
+ for name in ["GLib", "GObject", "Gtk", "Gdk"]})
diff --git a/lib/matplotlib/backends/backend_gtk3.py b/lib/matplotlib/backends/backend_gtk3.py
index 3e1225b8a0b1..606b01977cdd 100644
--- a/lib/matplotlib/backends/backend_gtk3.py
+++ b/lib/matplotlib/backends/backend_gtk3.py
@@ -7,39 +7,20 @@
import os
import sys
-try:
- import gi
-except ImportError:
- raise ImportError("Gtk3 backend requires pygobject to be installed.")
-
-try:
- gi.require_version("Gtk", "3.0")
-except AttributeError:
- raise ImportError(
- "pygobject version too old -- it must have require_version")
-except ValueError:
- raise ImportError(
- "Gtk3 backend requires the GObject introspection bindings for Gtk 3 "
- "to be installed.")
-
-try:
- from gi.repository import Gtk, Gdk, GObject, GLib
-except ImportError:
- raise ImportError("Gtk3 backend requires pygobject to be installed.")
-
import matplotlib
+from matplotlib import (
+ backend_tools, cbook, colors as mcolors, lines, rcParams)
from matplotlib._pylab_helpers import Gcf
from matplotlib.backend_bases import (
_Backend, FigureCanvasBase, FigureManagerBase, GraphicsContextBase,
- NavigationToolbar2, RendererBase, TimerBase, cursors)
-from matplotlib.backend_bases import ToolContainerBase, StatusbarBase
+ NavigationToolbar2, RendererBase, StatusbarBase, TimerBase,
+ ToolContainerBase, cursors)
from matplotlib.backend_managers import ToolManager
from matplotlib.cbook import is_writable_file_like
from matplotlib.figure import Figure
from matplotlib.widgets import SubplotTool
+from ._gtk3_compat import GLib, GObject, Gtk, Gdk
-from matplotlib import (
- backend_tools, cbook, colors as mcolors, lines, rcParams)
_log = logging.getLogger(__name__)
diff --git a/lib/matplotlib/backends/backend_gtk3agg.py b/lib/matplotlib/backends/backend_gtk3agg.py
index a8bce0c4e6fc..5d175ec7eccc 100644
--- a/lib/matplotlib/backends/backend_gtk3agg.py
+++ b/lib/matplotlib/backends/backend_gtk3agg.py
@@ -42,7 +42,7 @@ def on_draw_event(self, widget, ctx):
else:
bbox_queue = self._bbox_queue
- if HAS_CAIRO_CFFI:
+ if HAS_CAIRO_CFFI and not isinstance(ctx, cairo.Context):
ctx = cairo.Context._from_pointer(
cairo.ffi.cast('cairo_t **',
id(ctx) + object.__basicsize__)[0],
diff --git a/lib/matplotlib/backends/backend_gtk3cairo.py b/lib/matplotlib/backends/backend_gtk3cairo.py
index 79ba1fc2d24d..f27d38ecdb26 100644
--- a/lib/matplotlib/backends/backend_gtk3cairo.py
+++ b/lib/matplotlib/backends/backend_gtk3cairo.py
@@ -12,7 +12,7 @@
class RendererGTK3Cairo(backend_cairo.RendererCairo):
def set_context(self, ctx):
- if HAS_CAIRO_CFFI:
+ if HAS_CAIRO_CFFI and not isinstance(ctx, cairo.Context):
ctx = cairo.Context._from_pointer(
cairo.ffi.cast(
'cairo_t **',
diff --git a/lib/matplotlib/tests/test_backends_interactive.py b/lib/matplotlib/tests/test_backends_interactive.py
index 0a8b7d80276c..07d5759bbe0c 100644
--- a/lib/matplotlib/tests/test_backends_interactive.py
+++ b/lib/matplotlib/tests/test_backends_interactive.py
@@ -17,17 +17,22 @@
def _get_testable_interactive_backends():
- return [
- pytest.mark.skipif(
- not os.environ.get("DISPLAY")
- or sys.version_info < (3,)
- or importlib.util.find_spec(module_name) is None,
- reason="No $DISPLAY or could not import {!r}".format(module_name))(
- backend)
- for module_name, backend in [
- ("PyQt5", "qt5agg"),
- ("tkinter", "tkagg"),
- ("wx", "wxagg")]]
+ backends = []
+ for deps, backend in [(["cairocffi", "pgi"], "gtk3agg"),
+ (["cairocffi", "pgi"], "gtk3cairo"),
+ (["PyQt5"], "qt5agg"),
+ (["tkinter"], "tkagg"),
+ (["wx"], "wxagg")]:
+ reason = None
+ if sys.version_info < (3,):
+ reason = "Py3-only test"
+ elif not os.environ.get("DISPLAY"):
+ reason = "No $DISPLAY"
+ elif any(importlib.util.find_spec(dep) is None for dep in deps):
+ reason = "Missing dependency"
+ backends.append(pytest.mark.skip(reason=reason)(backend) if reason
+ else backend)
+ return backends
_test_script = """\
pFad - Phonifier reborn
Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy