Skip to content

Commit 954e84d

Browse files
committed
Propagate changes to backend loading to setup/setupext.
1) Restore the ability to set the default backend from setup.cfg. 2) Remove the backend fallback code. Note that not including `mpl-data/*.glade` in the package data is fine: that file had been removed in 962388f anyways.
1 parent 32ad86f commit 954e84d

File tree

4 files changed

+12
-261
lines changed

4 files changed

+12
-261
lines changed

.flake8

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ exclude =
2323

2424
per-file-ignores =
2525
setup.py: E402
26-
setupext.py: E302, E501
26+
setupext.py: E501
2727

2828
tools/compare_backend_driver_results.py: E501
2929
tools/subset.py: E221, E231, E251, E261, E302, E501, E701

setup.cfg.template

+1-8
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,9 @@
6363
# behavior
6464
#
6565
#agg = auto
66-
#cairo = auto
67-
#gtk3agg = auto
68-
#gtk3cairo = auto
6966
#macosx = auto
70-
#pyside = auto
71-
#qt4agg = auto
7267
#tkagg = auto
7368
#windowing = auto
74-
#wxagg = auto
7569

7670
[rc_options]
7771
# User-configurable options
@@ -81,10 +75,9 @@
8175
#
8276
# The Agg, Ps, Pdf and SVG backends do not require external dependencies. Do
8377
# not choose MacOSX, or TkAgg if you have disabled the relevant extension
84-
# modules. Agg will be used by default.
78+
# modules. The default is determined by fallback.
8579
#
8680
#backend = Agg
87-
#
8881

8982
[package_data]
9083
# Package additional files found in the lib/matplotlib directories.

setup.py

+10-22
Original file line numberDiff line numberDiff line change
@@ -70,18 +70,9 @@
7070
setupext.Tests(),
7171
setupext.Toolkits_Tests(),
7272
'Optional backend extensions',
73-
# These backends are listed in order of preference, the first
74-
# being the most preferred. The first one that looks like it will
75-
# work will be selected as the default backend.
76-
setupext.BackendMacOSX(),
77-
setupext.BackendQt5(),
78-
setupext.BackendQt4(),
79-
setupext.BackendGtk3Agg(),
80-
setupext.BackendGtk3Cairo(),
81-
setupext.BackendTkAgg(),
82-
setupext.BackendWxAgg(),
8373
setupext.BackendAgg(),
84-
setupext.BackendCairo(),
74+
setupext.BackendTkAgg(),
75+
setupext.BackendMacOSX(),
8576
setupext.Windowing(),
8677
'Optional package data',
8778
setupext.Dlls(),
@@ -133,7 +124,6 @@ def run(self):
133124
package_dir = {'': 'lib'}
134125
install_requires = []
135126
setup_requires = []
136-
default_backend = None
137127

138128
# If the user just queries for information, don't bother figuring out which
139129
# packages to build or install.
@@ -169,10 +159,6 @@ def run(self):
169159
required_failed.append(package)
170160
else:
171161
good_packages.append(package)
172-
if (isinstance(package, setupext.OptionalBackendPackage)
173-
and package.runtime_check()
174-
and default_backend is None):
175-
default_backend = package.name
176162
print_raw('')
177163

178164
# Abort if any of the required packages can not be built.
@@ -203,14 +189,16 @@ def run(self):
203189
setup_requires.extend(package.get_setup_requires())
204190

205191
# Write the default matplotlibrc file
206-
if default_backend is None:
207-
default_backend = 'svg'
208-
if setupext.options['backend']:
209-
default_backend = setupext.options['backend']
210192
with open('matplotlibrc.template') as fd:
211-
template = fd.read()
193+
template_lines = fd.read().splitlines(True)
194+
backend_line_idx, = [ # Also asserts that there is a single such line.
195+
idx for idx, line in enumerate(template_lines)
196+
if line.startswith('#backend ')]
197+
if setupext.options['backend']:
198+
template_lines[backend_line_idx] = (
199+
'backend: {}'.format(setupext.options['backend']))
212200
with open('lib/matplotlib/mpl-data/matplotlibrc', 'w') as fd:
213-
fd.write(template)
201+
fd.write(''.join(template_lines))
214202

215203
# Finalize the extension modules so they can get the Numpy include
216204
# dirs

setupext.py

-230
Original file line numberDiff line numberDiff line change
@@ -384,13 +384,6 @@ def check(self):
384384
"""
385385
pass
386386

387-
def runtime_check(self):
388-
"""
389-
True if the runtime dependencies of the backend are met. Assumes that
390-
the build-time dependencies are met.
391-
"""
392-
return True
393-
394387
def get_packages(self):
395388
"""
396389
Get a list of package names to add to the configuration.
@@ -1368,10 +1361,6 @@ class BackendTkAgg(OptionalBackendPackage):
13681361
def check(self):
13691362
return "installing; run-time loading from Python Tcl / Tk"
13701363

1371-
def runtime_check(self):
1372-
"""Checks whether TkAgg runtime dependencies are met."""
1373-
return importlib.util.find_spec("tkinter") is not None
1374-
13751364
def get_extension(self):
13761365
sources = [
13771366
'src/_tkagg.cpp'
@@ -1391,57 +1380,6 @@ def add_flags(self, ext):
13911380
ext.libraries.extend(['dl'])
13921381

13931382

1394-
class BackendGtk3Agg(OptionalBackendPackage):
1395-
name = "gtk3agg"
1396-
1397-
def check_requirements(self):
1398-
if not any(map(importlib.util.find_spec, ["cairocffi", "cairo"])):
1399-
raise CheckFailed("Requires cairocffi or pycairo to be installed.")
1400-
1401-
try:
1402-
import gi
1403-
except ImportError:
1404-
raise CheckFailed("Requires pygobject to be installed.")
1405-
1406-
try:
1407-
gi.require_version("Gtk", "3.0")
1408-
except ValueError:
1409-
raise CheckFailed(
1410-
"Requires gtk3 development files to be installed.")
1411-
except AttributeError:
1412-
raise CheckFailed("pygobject version too old.")
1413-
1414-
try:
1415-
from gi.repository import Gtk, Gdk, GObject
1416-
except (ImportError, RuntimeError):
1417-
raise CheckFailed("Requires pygobject to be installed.")
1418-
1419-
return "version {}.{}.{}".format(
1420-
Gtk.get_major_version(),
1421-
Gtk.get_minor_version(),
1422-
Gtk.get_micro_version())
1423-
1424-
def get_package_data(self):
1425-
return {'matplotlib': ['mpl-data/*.glade']}
1426-
1427-
1428-
class BackendGtk3Cairo(BackendGtk3Agg):
1429-
name = "gtk3cairo"
1430-
1431-
1432-
class BackendWxAgg(OptionalBackendPackage):
1433-
name = "wxagg"
1434-
1435-
def check_requirements(self):
1436-
try:
1437-
import wx
1438-
backend_version = wx.VERSION_STRING
1439-
except ImportError:
1440-
raise CheckFailed("requires wxPython")
1441-
1442-
return "version %s" % backend_version
1443-
1444-
14451383
class BackendMacOSX(OptionalBackendPackage):
14461384
name = 'macosx'
14471385

@@ -1487,174 +1425,6 @@ def get_extension(self):
14871425
return ext
14881426

14891427

1490-
class BackendQtBase(OptionalBackendPackage):
1491-
1492-
def convert_qt_version(self, version):
1493-
version = '%x' % version
1494-
temp = []
1495-
while len(version) > 0:
1496-
version, chunk = version[:-2], version[-2:]
1497-
temp.insert(0, str(int(chunk, 16)))
1498-
return '.'.join(temp)
1499-
1500-
def check_requirements(self):
1501-
"""
1502-
If PyQt4/PyQt5 is already imported, importing PyQt5/PyQt4 will fail
1503-
so we need to test in a subprocess (as for Gtk3).
1504-
"""
1505-
try:
1506-
p = multiprocessing.Pool()
1507-
1508-
except:
1509-
# Can't do multiprocessing, fall back to normal approach
1510-
# (this will fail if importing both PyQt4 and PyQt5).
1511-
try:
1512-
# Try in-process
1513-
msg = self.callback(self)
1514-
except RuntimeError:
1515-
raise CheckFailed(
1516-
"Could not import: are PyQt4 & PyQt5 both installed?")
1517-
1518-
else:
1519-
# Multiprocessing OK
1520-
try:
1521-
res = p.map_async(self.callback, [self])
1522-
msg = res.get(timeout=10)[0]
1523-
except multiprocessing.TimeoutError:
1524-
p.terminate()
1525-
# No result returned. Probably hanging, terminate the process.
1526-
raise CheckFailed("Check timed out")
1527-
except:
1528-
# Some other error.
1529-
p.close()
1530-
raise
1531-
else:
1532-
# Clean exit
1533-
p.close()
1534-
finally:
1535-
# Tidy up multiprocessing
1536-
p.join()
1537-
1538-
return msg
1539-
1540-
1541-
def backend_pyside_internal_check(self):
1542-
try:
1543-
from PySide import __version__
1544-
from PySide import QtCore
1545-
except ImportError:
1546-
raise CheckFailed("PySide not found")
1547-
else:
1548-
return ("Qt: %s, PySide: %s" %
1549-
(QtCore.__version__, __version__))
1550-
1551-
1552-
def backend_pyqt4_internal_check(self):
1553-
try:
1554-
from PyQt4 import QtCore
1555-
except ImportError:
1556-
raise CheckFailed("PyQt4 not found")
1557-
1558-
try:
1559-
qt_version = QtCore.QT_VERSION
1560-
pyqt_version_str = QtCore.PYQT_VERSION_STR
1561-
except AttributeError:
1562-
raise CheckFailed('PyQt4 not correctly imported')
1563-
else:
1564-
return ("Qt: %s, PyQt: %s" % (self.convert_qt_version(qt_version), pyqt_version_str))
1565-
1566-
1567-
def backend_qt4_internal_check(self):
1568-
successes = []
1569-
failures = []
1570-
try:
1571-
successes.append(backend_pyside_internal_check(self))
1572-
except CheckFailed as e:
1573-
failures.append(str(e))
1574-
1575-
try:
1576-
successes.append(backend_pyqt4_internal_check(self))
1577-
except CheckFailed as e:
1578-
failures.append(str(e))
1579-
1580-
if len(successes) == 0:
1581-
raise CheckFailed('; '.join(failures))
1582-
return '; '.join(successes + failures)
1583-
1584-
1585-
class BackendQt4(BackendQtBase):
1586-
name = "qt4agg"
1587-
1588-
def __init__(self, *args, **kwargs):
1589-
BackendQtBase.__init__(self, *args, **kwargs)
1590-
self.callback = backend_qt4_internal_check
1591-
1592-
def backend_pyside2_internal_check(self):
1593-
try:
1594-
from PySide2 import __version__
1595-
from PySide2 import QtCore
1596-
except ImportError:
1597-
raise CheckFailed("PySide2 not found")
1598-
else:
1599-
return ("Qt: %s, PySide2: %s" %
1600-
(QtCore.__version__, __version__))
1601-
1602-
def backend_pyqt5_internal_check(self):
1603-
try:
1604-
from PyQt5 import QtCore
1605-
except ImportError:
1606-
raise CheckFailed("PyQt5 not found")
1607-
1608-
try:
1609-
qt_version = QtCore.QT_VERSION
1610-
pyqt_version_str = QtCore.PYQT_VERSION_STR
1611-
except AttributeError:
1612-
raise CheckFailed('PyQt5 not correctly imported')
1613-
else:
1614-
return ("Qt: %s, PyQt: %s" % (self.convert_qt_version(qt_version), pyqt_version_str))
1615-
1616-
def backend_qt5_internal_check(self):
1617-
successes = []
1618-
failures = []
1619-
try:
1620-
successes.append(backend_pyside2_internal_check(self))
1621-
except CheckFailed as e:
1622-
failures.append(str(e))
1623-
1624-
try:
1625-
successes.append(backend_pyqt5_internal_check(self))
1626-
except CheckFailed as e:
1627-
failures.append(str(e))
1628-
1629-
if len(successes) == 0:
1630-
raise CheckFailed('; '.join(failures))
1631-
return '; '.join(successes + failures)
1632-
1633-
class BackendQt5(BackendQtBase):
1634-
name = "qt5agg"
1635-
1636-
def __init__(self, *args, **kwargs):
1637-
BackendQtBase.__init__(self, *args, **kwargs)
1638-
self.callback = backend_qt5_internal_check
1639-
1640-
1641-
class BackendCairo(OptionalBackendPackage):
1642-
name = "cairo"
1643-
1644-
def check_requirements(self):
1645-
try:
1646-
import cairocffi
1647-
except ImportError:
1648-
try:
1649-
import cairo
1650-
except ImportError:
1651-
raise CheckFailed("cairocffi or pycairo not found")
1652-
else:
1653-
return "pycairo version %s" % cairo.version
1654-
else:
1655-
return "cairocffi version %s" % cairocffi.version
1656-
1657-
16581428
class OptionalPackageData(OptionalPackage):
16591429
config_category = "package_data"
16601430

0 commit comments

Comments
 (0)