Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 024d423

Browse files
authored
Merge pull request #9932 from anntzer/pgi
TST: Support pgi as alternative gobject bindings.
2 parents 64ffc46 + 0ed289c commit 024d423

File tree

8 files changed

+121
-55
lines changed

8 files changed

+121
-55
lines changed

.travis.yml

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,25 @@ addons:
1919
- result_images.tar.bz2
2020
apt:
2121
packages:
22+
- cm-super
23+
- dvipng
24+
- gdb
25+
- gir1.2-gtk-3.0
26+
- graphviz
2227
- inkscape
2328
- libav-tools
24-
- gdb
29+
- libcairo2
30+
- libgeos-dev
31+
- libgirepository-1.0.1
32+
- lmodern
2533
- mencoder
26-
- dvipng
34+
- otf-freefont
2735
- pgf
28-
- lmodern
29-
- cm-super
36+
- texlive-fonts-recommended
3037
- texlive-latex-base
3138
- texlive-latex-extra
32-
- texlive-fonts-recommended
3339
- texlive-latex-recommended
3440
- texlive-xetex
35-
- graphviz
36-
- libgeos-dev
37-
- otf-freefont
3841

3942
env:
4043
global:
@@ -123,6 +126,10 @@ install:
123126
# install was successful by trying to import the toolkit (sometimes, the
124127
# install appears to be successful but shared libraries cannot be loaded at
125128
# runtime, so an actual import is a better check).
129+
pip install cairocffi pgi &&
130+
python -c 'import pgi as gi; gi.require_version("Gtk", "3.0"); from pgi.repository import Gtk' &&
131+
echo 'pgi is available' ||
132+
echo 'pgi is not available'
126133
pip install pyqt5 &&
127134
python -c 'import PyQt5.QtCore' &&
128135
echo 'PyQt5 is available' ||

doc/glossary/index.rst

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ Glossary
88
.. glossary::
99

1010
AGG
11-
The Anti-Grain Geometry (`Agg <http://antigrain.com/>`_) rendering engine, capable of rendering
12-
high-quality images
11+
The Anti-Grain Geometry (`Agg <http://antigrain.com/>`_) rendering
12+
engine, capable of rendering high-quality images
1313

1414
Cairo
1515
The `Cairo graphics <https://cairographics.org>`_ engine
@@ -20,7 +20,8 @@ Glossary
2020
provides extensions to the standard datetime module
2121

2222
EPS
23-
Encapsulated Postscript (`EPS <https://en.wikipedia.org/wiki/Encapsulated_PostScript>`_)
23+
Encapsulated Postscript (`EPS
24+
<https://en.wikipedia.org/wiki/Encapsulated_PostScript>`_)
2425

2526
FreeType
2627
`FreeType <https://www.freetype.org/>`_ is a font rasterization
@@ -32,7 +33,8 @@ Glossary
3233
The Gimp Drawing Kit for GTK+
3334

3435
GTK
35-
The GIMP Toolkit (`GTK <https://www.gtk.org/>`_) graphical user interface library
36+
The GIMP Toolkit (`GTK <https://www.gtk.org/>`_) graphical user interface
37+
library
3638

3739
JPG
3840
The Joint Photographic Experts Group (`JPEG
@@ -47,13 +49,14 @@ Glossary
4749
deviation, fourier transforms, and convolutions.
4850

4951
PDF
50-
Adobe's Portable Document Format (`PDF <https://en.wikipedia.org/wiki/Portable_Document_Format>`_)
52+
Adobe's Portable Document Format (`PDF
53+
<https://en.wikipedia.org/wiki/Portable_Document_Format>`_)
5154

5255
PNG
5356
Portable Network Graphics (`PNG
54-
<https://en.wikipedia.org/wiki/Portable_Network_Graphics>`_), a raster graphics format
55-
that employs lossless data compression which is more suitable
56-
for line art than the lossy jpg format. Unlike the gif format,
57+
<https://en.wikipedia.org/wiki/Portable_Network_Graphics>`_), a raster
58+
graphics format that employs lossless data compression which is more
59+
suitable for line art than the lossy jpg format. Unlike the gif format,
5760
png is not encumbered by requirements for a patent license.
5861

5962
PS
@@ -64,12 +67,24 @@ Glossary
6467
channel. PDF was designed in part as a next-generation document
6568
format to replace postscript
6669

70+
pgi
71+
`pgi <https://pypi.python.org/pypi/pgi/>` exists as a relatively
72+
new Python wrapper to GTK3 and acts as a pure python alternative to
73+
PyGObject. pgi still exists in its infancy, currently missing many
74+
features of PyGObject. However Matplotlib does not use any of these
75+
missing features.
76+
6777
pygtk
6878
`pygtk <http://www.pygtk.org/>`_ provides python wrappers for
6979
the :term:`GTK` widgets library for use with the GTK or GTKAgg
7080
backend. Widely used on linux, and is often packages as
7181
'python-gtk2'
7282

83+
PyGObject
84+
Like :term:`pygtk`, `PyGObject <http://www.pygtk.org/>` provides
85+
python wrappers for the :term:`GTK` widgets library; unlike pygtk,
86+
PyGObject wraps GTK3 instead of the now obsolete GTK2.
87+
7388
pyqt
7489
`pyqt <https://wiki.python.org/moin/PyQt>`_ provides python
7590
wrappers for the :term:`Qt` widgets library and is required by
@@ -82,14 +97,12 @@ Glossary
8297
language widely used for scripting, application development, web
8398
application servers, scientific computing and more.
8499

85-
86100
pytz
87101
`pytz <http://pythonhosted.org/pytz/>`_ provides the Olson tz
88102
database in Python. it allows accurate and cross platform
89103
timezone calculations and solves the issue of ambiguous times at
90104
the end of daylight savings
91105

92-
93106
Qt
94107
`Qt <https://www.qt.io/>`__ is a cross-platform
95108
application framework for desktop and embedded development.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
PGI bindings for gtk3
2+
---------------------
3+
4+
The GTK3 backends can now use PGI_ instead of PyGObject_. PGI is a fairly
5+
incomplete binding for GObject, thus its use is not recommended; its main
6+
benefit is its availability on Travis (thus allowing CI testing for the gtk3agg
7+
and gtk3cairo backends).
8+
9+
The binding selection rules are as follows:
10+
- if ``gi`` has already been imported, use it; else
11+
- if ``pgi`` has already been imported, use it; else
12+
- if ``gi`` can be imported, use it; else
13+
- if ``pgi`` can be imported, use it; else
14+
- error out.
15+
16+
Thus, to force usage of PGI when both bindings are installed, import it first.
17+
18+
.. _PGI: https://pgi.readthedocs.io/en/latest/
19+
.. _PyGObject: http://pygobject.readthedocs.io/en/latest/#
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
"""
2+
GObject compatibility loader; supports ``gi`` and ``pgi``.
3+
4+
The binding selection rules are as follows:
5+
- if ``gi`` has already been imported, use it; else
6+
- if ``pgi`` has already been imported, use it; else
7+
- if ``gi`` can be imported, use it; else
8+
- if ``pgi`` can be imported, use it; else
9+
- error out.
10+
11+
Thus, to force usage of PGI when both bindings are installed, import it first.
12+
"""
13+
14+
from __future__ import (absolute_import, division, print_function,
15+
unicode_literals)
16+
17+
import six
18+
19+
import importlib
20+
import sys
21+
22+
23+
if "gi" in sys.modules:
24+
import gi
25+
elif "pgi" in sys.modules:
26+
import pgi as gi
27+
else:
28+
try:
29+
import gi
30+
except ImportError:
31+
try:
32+
import pgi as gi
33+
except ImportError:
34+
raise ImportError("The Gtk3 backend requires PyGObject or pgi")
35+
36+
37+
gi.require_version("Gtk", "3.0")
38+
globals().update(
39+
{name:
40+
importlib.import_module("{}.repository.{}".format(gi.__name__, name))
41+
for name in ["GLib", "GObject", "Gtk", "Gdk"]})

lib/matplotlib/backends/backend_gtk3.py

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,39 +7,20 @@
77
import os
88
import sys
99

10-
try:
11-
import gi
12-
except ImportError:
13-
raise ImportError("Gtk3 backend requires pygobject to be installed.")
14-
15-
try:
16-
gi.require_version("Gtk", "3.0")
17-
except AttributeError:
18-
raise ImportError(
19-
"pygobject version too old -- it must have require_version")
20-
except ValueError:
21-
raise ImportError(
22-
"Gtk3 backend requires the GObject introspection bindings for Gtk 3 "
23-
"to be installed.")
24-
25-
try:
26-
from gi.repository import Gtk, Gdk, GObject, GLib
27-
except ImportError:
28-
raise ImportError("Gtk3 backend requires pygobject to be installed.")
29-
3010
import matplotlib
11+
from matplotlib import (
12+
backend_tools, cbook, colors as mcolors, lines, rcParams)
3113
from matplotlib._pylab_helpers import Gcf
3214
from matplotlib.backend_bases import (
3315
_Backend, FigureCanvasBase, FigureManagerBase, GraphicsContextBase,
34-
NavigationToolbar2, RendererBase, TimerBase, cursors)
35-
from matplotlib.backend_bases import ToolContainerBase, StatusbarBase
16+
NavigationToolbar2, RendererBase, StatusbarBase, TimerBase,
17+
ToolContainerBase, cursors)
3618
from matplotlib.backend_managers import ToolManager
3719
from matplotlib.cbook import is_writable_file_like
3820
from matplotlib.figure import Figure
3921
from matplotlib.widgets import SubplotTool
22+
from ._gtk3_compat import GLib, GObject, Gtk, Gdk
4023

41-
from matplotlib import (
42-
backend_tools, cbook, colors as mcolors, lines, rcParams)
4324

4425
_log = logging.getLogger(__name__)
4526

lib/matplotlib/backends/backend_gtk3agg.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def on_draw_event(self, widget, ctx):
4242
else:
4343
bbox_queue = self._bbox_queue
4444

45-
if HAS_CAIRO_CFFI:
45+
if HAS_CAIRO_CFFI and not isinstance(ctx, cairo.Context):
4646
ctx = cairo.Context._from_pointer(
4747
cairo.ffi.cast('cairo_t **',
4848
id(ctx) + object.__basicsize__)[0],

lib/matplotlib/backends/backend_gtk3cairo.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
class RendererGTK3Cairo(backend_cairo.RendererCairo):
1414
def set_context(self, ctx):
15-
if HAS_CAIRO_CFFI:
15+
if HAS_CAIRO_CFFI and not isinstance(ctx, cairo.Context):
1616
ctx = cairo.Context._from_pointer(
1717
cairo.ffi.cast(
1818
'cairo_t **',

lib/matplotlib/tests/test_backends_interactive.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,22 @@
1717

1818

1919
def _get_testable_interactive_backends():
20-
return [
21-
pytest.mark.skipif(
22-
not os.environ.get("DISPLAY")
23-
or sys.version_info < (3,)
24-
or importlib.util.find_spec(module_name) is None,
25-
reason="No $DISPLAY or could not import {!r}".format(module_name))(
26-
backend)
27-
for module_name, backend in [
28-
("PyQt5", "qt5agg"),
29-
("tkinter", "tkagg"),
30-
("wx", "wxagg")]]
20+
backends = []
21+
for deps, backend in [(["cairocffi", "pgi"], "gtk3agg"),
22+
(["cairocffi", "pgi"], "gtk3cairo"),
23+
(["PyQt5"], "qt5agg"),
24+
(["tkinter"], "tkagg"),
25+
(["wx"], "wxagg")]:
26+
reason = None
27+
if sys.version_info < (3,):
28+
reason = "Py3-only test"
29+
elif not os.environ.get("DISPLAY"):
30+
reason = "No $DISPLAY"
31+
elif any(importlib.util.find_spec(dep) is None for dep in deps):
32+
reason = "Missing dependency"
33+
backends.append(pytest.mark.skip(reason=reason)(backend) if reason
34+
else backend)
35+
return backends
3136

3237

3338
_test_script = """\

0 commit comments

Comments
 (0)