Skip to content

TST: Backend switching API (don't merge) #11612

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions INSTALL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,9 @@ interface toolkits. See :ref:`what-is-a-backend` for more details on the
optional Matplotlib backends and the capabilities they provide.

* :term:`tk` (>= 8.3, != 8.6.0 or 8.6.1): for the TkAgg backend;
* `PyQt4 <https://pypi.python.org/pypi/PyQt4>`_ (>= 4.4) or
`PySide <https://pypi.python.org/pypi/PySide>`_: for the Qt4Agg backend;
* `PyQt4 <https://pypi.python.org/pypi/PyQt4>`_ (>= 4.6) or
`PySide <https://pypi.python.org/pypi/PySide>`_ (>= 1.0.3): for the Qt4Agg
backend;
* `PyQt5 <https://pypi.python.org/pypi/PyQt5>`_: for the Qt5Agg backend;
* :term:`wxpython` (>= 4): for the WX or WXAgg backend;
* `cairocffi <https://cairocffi.readthedocs.io/en/latest/>`_ (>=0.8) or
Expand Down
10 changes: 6 additions & 4 deletions doc/api/backend_qt4agg_api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
:mod:`matplotlib.backends.backend_qt4agg`
=========================================

.. automodule:: matplotlib.backends.backend_qt4agg
:members:
:undoc-members:
:show-inheritance:
**NOTE** Not included, to avoid adding a dependency to building the docs.

.. .. automodule:: matplotlib.backends.backend_qt4agg
.. :members:
.. :undoc-members:
.. :show-inheritance:
10 changes: 6 additions & 4 deletions doc/api/backend_qt4cairo_api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
:mod:`matplotlib.backends.backend_qt4cairo`
===========================================

.. automodule:: matplotlib.backends.backend_qt4cairo
:members:
:undoc-members:
:show-inheritance:
**NOTE** Not included, to avoid adding a dependency to building the docs.

.. .. automodule:: matplotlib.backends.backend_qt4cairo
.. :members:
.. :undoc-members:
.. :show-inheritance:
10 changes: 6 additions & 4 deletions doc/api/backend_qt5agg_api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
:mod:`matplotlib.backends.backend_qt5agg`
=========================================

.. automodule:: matplotlib.backends.backend_qt5agg
:members:
:undoc-members:
:show-inheritance:
**NOTE** Not included, to avoid adding a dependency to building the docs.

.. .. automodule:: matplotlib.backends.backend_qt5agg
.. :members:
.. :undoc-members:
.. :show-inheritance:
10 changes: 6 additions & 4 deletions doc/api/backend_qt5cairo_api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
:mod:`matplotlib.backends.backend_qt5cairo`
===========================================

.. automodule:: matplotlib.backends.backend_qt5cairo
:members:
:undoc-members:
:show-inheritance:
**NOTE** Not included, to avoid adding a dependency to building the docs.

.. .. automodule:: matplotlib.backends.backend_qt5cairo
.. :members:
.. :undoc-members:
.. :show-inheritance:
1 change: 1 addition & 0 deletions doc/api/next_api_changes/2018-02-15-AL-deprecations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ The following classes, methods, functions, and attributes are deprecated:
- ``backend_ps.get_bbox``,
- ``backend_qt5.error_msg_qt``, ``backend_qt5.exception_handler``,
- ``backend_wx.FigureCanvasWx.macros``,
- ``backends.pylab_setup``,
- ``cbook.GetRealpathAndStat``, ``cbook.Locked``,
- ``cbook.is_numlike`` (use ``isinstance(..., numbers.Number)`` instead),
``cbook.listFiles``, ``cbook.unicode_safe``,
Expand Down
3 changes: 3 additions & 0 deletions doc/api/next_api_changes/2018-06-27-AL.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
Changes to backend loading
``````````````````````````

Assignment to ``rcParams["backend"]`` now sets the backend. Backends can now
be switched until a figure is actually created.

Failure to load backend modules (``macosx`` on non-framework builds and
``gtk3`` when running headless) now raises `ImportError` (instead of
`RuntimeError` and `TypeError`, respectively.
Expand Down
104 changes: 0 additions & 104 deletions doc/sphinxext/mock_gui_toolkits.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,108 +6,6 @@ class MyCairoCffi(MagicMock):
__name__ = "cairocffi"


class MyPyQt4(MagicMock):
class QtGui(object):
# PyQt4.QtGui public classes.
# Generated with
# textwrap.fill([name for name in dir(PyQt4.QtGui)
# if isinstance(getattr(PyQt4.QtGui, name), type)])
_QtGui_public_classes = """\
Display QAbstractButton QAbstractGraphicsShapeItem
QAbstractItemDelegate QAbstractItemView QAbstractPrintDialog
QAbstractProxyModel QAbstractScrollArea QAbstractSlider
QAbstractSpinBox QAbstractTextDocumentLayout QAction QActionEvent
QActionGroup QApplication QBitmap QBoxLayout QBrush QButtonGroup
QCalendarWidget QCheckBox QClipboard QCloseEvent QColor QColorDialog
QColumnView QComboBox QCommandLinkButton QCommonStyle QCompleter
QConicalGradient QContextMenuEvent QCursor QDataWidgetMapper QDateEdit
QDateTimeEdit QDesktopServices QDesktopWidget QDial QDialog
QDialogButtonBox QDirModel QDockWidget QDoubleSpinBox QDoubleValidator
QDrag QDragEnterEvent QDragLeaveEvent QDragMoveEvent QDropEvent
QErrorMessage QFileDialog QFileIconProvider QFileOpenEvent
QFileSystemModel QFocusEvent QFocusFrame QFont QFontComboBox
QFontDatabase QFontDialog QFontInfo QFontMetrics QFontMetricsF
QFormLayout QFrame QGesture QGestureEvent QGestureRecognizer QGlyphRun
QGradient QGraphicsAnchor QGraphicsAnchorLayout QGraphicsBlurEffect
QGraphicsColorizeEffect QGraphicsDropShadowEffect QGraphicsEffect
QGraphicsEllipseItem QGraphicsGridLayout QGraphicsItem
QGraphicsItemAnimation QGraphicsItemGroup QGraphicsLayout
QGraphicsLayoutItem QGraphicsLineItem QGraphicsLinearLayout
QGraphicsObject QGraphicsOpacityEffect QGraphicsPathItem
QGraphicsPixmapItem QGraphicsPolygonItem QGraphicsProxyWidget
QGraphicsRectItem QGraphicsRotation QGraphicsScale QGraphicsScene
QGraphicsSceneContextMenuEvent QGraphicsSceneDragDropEvent
QGraphicsSceneEvent QGraphicsSceneHelpEvent QGraphicsSceneHoverEvent
QGraphicsSceneMouseEvent QGraphicsSceneMoveEvent
QGraphicsSceneResizeEvent QGraphicsSceneWheelEvent
QGraphicsSimpleTextItem QGraphicsTextItem QGraphicsTransform
QGraphicsView QGraphicsWidget QGridLayout QGroupBox QHBoxLayout
QHeaderView QHelpEvent QHideEvent QHoverEvent QIcon QIconDragEvent
QIconEngine QIconEngineV2 QIdentityProxyModel QImage QImageIOHandler
QImageReader QImageWriter QInputContext QInputContextFactory
QInputDialog QInputEvent QInputMethodEvent QIntValidator QItemDelegate
QItemEditorCreatorBase QItemEditorFactory QItemSelection
QItemSelectionModel QItemSelectionRange QKeyEvent QKeyEventTransition
QKeySequence QLCDNumber QLabel QLayout QLayoutItem QLineEdit
QLinearGradient QListView QListWidget QListWidgetItem QMainWindow
QMatrix QMatrix2x2 QMatrix2x3 QMatrix2x4 QMatrix3x2 QMatrix3x3
QMatrix3x4 QMatrix4x2 QMatrix4x3 QMatrix4x4 QMdiArea QMdiSubWindow
QMenu QMenuBar QMessageBox QMimeSource QMouseEvent
QMouseEventTransition QMoveEvent QMovie QPageSetupDialog QPaintDevice
QPaintEngine QPaintEngineState QPaintEvent QPainter QPainterPath
QPainterPathStroker QPalette QPanGesture QPen QPicture QPictureIO
QPinchGesture QPixmap QPixmapCache QPlainTextDocumentLayout
QPlainTextEdit QPolygon QPolygonF QPrintDialog QPrintEngine
QPrintPreviewDialog QPrintPreviewWidget QPrinter QPrinterInfo
QProgressBar QProgressDialog QProxyModel QPushButton QPyTextObject
QQuaternion QRadialGradient QRadioButton QRawFont QRegExpValidator
QRegion QResizeEvent QRubberBand QScrollArea QScrollBar
QSessionManager QShortcut QShortcutEvent QShowEvent QSizeGrip
QSizePolicy QSlider QSortFilterProxyModel QSound QSpacerItem QSpinBox
QSplashScreen QSplitter QSplitterHandle QStackedLayout QStackedWidget
QStandardItem QStandardItemModel QStaticText QStatusBar
QStatusTipEvent QStringListModel QStyle QStyleFactory QStyleHintReturn
QStyleHintReturnMask QStyleHintReturnVariant QStyleOption
QStyleOptionButton QStyleOptionComboBox QStyleOptionComplex
QStyleOptionDockWidget QStyleOptionDockWidgetV2 QStyleOptionFocusRect
QStyleOptionFrame QStyleOptionFrameV2 QStyleOptionFrameV3
QStyleOptionGraphicsItem QStyleOptionGroupBox QStyleOptionHeader
QStyleOptionMenuItem QStyleOptionProgressBar QStyleOptionProgressBarV2
QStyleOptionRubberBand QStyleOptionSizeGrip QStyleOptionSlider
QStyleOptionSpinBox QStyleOptionTab QStyleOptionTabBarBase
QStyleOptionTabBarBaseV2 QStyleOptionTabV2 QStyleOptionTabV3
QStyleOptionTabWidgetFrame QStyleOptionTabWidgetFrameV2
QStyleOptionTitleBar QStyleOptionToolBar QStyleOptionToolBox
QStyleOptionToolBoxV2 QStyleOptionToolButton QStyleOptionViewItem
QStyleOptionViewItemV2 QStyleOptionViewItemV3 QStyleOptionViewItemV4
QStylePainter QStyledItemDelegate QSwipeGesture QSyntaxHighlighter
QSystemTrayIcon QTabBar QTabWidget QTableView QTableWidget
QTableWidgetItem QTableWidgetSelectionRange QTabletEvent
QTapAndHoldGesture QTapGesture QTextBlock QTextBlockFormat
QTextBlockGroup QTextBlockUserData QTextBrowser QTextCharFormat
QTextCursor QTextDocument QTextDocumentFragment QTextDocumentWriter
QTextEdit QTextFormat QTextFragment QTextFrame QTextFrameFormat
QTextImageFormat QTextInlineObject QTextItem QTextLayout QTextLength
QTextLine QTextList QTextListFormat QTextObject QTextObjectInterface
QTextOption QTextTable QTextTableCell QTextTableCellFormat
QTextTableFormat QTimeEdit QToolBar QToolBox QToolButton QToolTip
QTouchEvent QTransform QTreeView QTreeWidget QTreeWidgetItem
QTreeWidgetItemIterator QUndoCommand QUndoGroup QUndoStack QUndoView
QVBoxLayout QValidator QVector2D QVector3D QVector4D QWhatsThis
QWhatsThisClickedEvent QWheelEvent QWidget QWidgetAction QWidgetItem
QWindowStateChangeEvent QWizard QWizardPage QWorkspace
QX11EmbedContainer QX11EmbedWidget QX11Info
"""
for _name in _QtGui_public_classes.split():
locals()[_name] = type(_name, (), {})
del _name


class MySip(MagicMock):
def getapi(*args):
return 1


class MyWX(MagicMock):
class Panel(object):
pass
Expand All @@ -125,8 +23,6 @@ class StatusBar(object):
def setup(app):
sys.modules.update(
cairocffi=MyCairoCffi(),
PyQt4=MyPyQt4(),
sip=MySip(),
wx=MyWX(),
)
return {'parallel_read_safe': True, 'parallel_write_safe': True}
85 changes: 31 additions & 54 deletions lib/matplotlib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -803,7 +803,9 @@ def gen_candidates():

# rcParams deprecated and automatically mapped to another key.
# Values are tuples of (version, new_name, f_old2new, f_new2old).
_deprecated_map = {}
_deprecated_map = {
'backend': (3.0, 'default_backends', lambda x: [x], lambda x: x[0])
}

# rcParams deprecated; some can manually be mapped to another key.
# Values are tuples of (version, new_name_or_None).
Expand Down Expand Up @@ -909,8 +911,17 @@ def __setitem__(self, key, val):
'%s is not a valid rc parameter. See rcParams.keys() for a '
'list of valid parameters.' % (key,))

def _set_current_backend(self, backend):
dict.__setitem__(self, 'backend', backend)

def __getitem__(self, key):
if key in _deprecated_map:
if key == 'backend':
cbook.warn_deprecated('3.0',
"The rcParam 'backend' is deprecated. Use the rcParam "
"'default_backends' to access the defaults. Use get_backend() "
"to get the current backend.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But then you need to store the current backend somewhere else and update the implementation of get_backend accordingly.

return dict.__getitem__(self, backend)
elif key in _deprecated_map:
version, alt_key, alt_val, inverse_alt = _deprecated_map[key]
cbook.warn_deprecated(
version, key, obj_type="rcparam", alternative=alt_key)
Expand Down Expand Up @@ -1318,6 +1329,7 @@ def __exit__(self, exc_type, exc_value, exc_tb):
dict.update(rcParams, self._orig)


# FIXME: Remove.
_use_error_msg = """
This call to matplotlib.use() has no effect because the backend has already
been chosen; matplotlib.use() must be called *before* pylab, matplotlib.pyplot,
Expand All @@ -1327,65 +1339,30 @@ def __exit__(self, exc_type, exc_value, exc_tb):
{tb}
"""


def use(arg, warn=True, force=False):
def set_backend(arg, warn=True, force=False):
"""
Set the matplotlib backend to one of the known backends.

The argument is case-insensitive. *warn* specifies whether a
warning should be issued if a backend has already been set up.
*force* is an **experimental** flag that tells matplotlib to
attempt to initialize a new backend by reloading the backend
module.

.. note::
Set the Matplotlib backend.

This function must be called *before* importing pyplot for
the first time; or, if you are not using pyplot, it must be called
before importing matplotlib.backends. If warn is True, a warning
is issued if you try and call this after pylab or pyplot have been
loaded. In certain black magic use cases, e.g.
:func:`pyplot.switch_backend`, we are doing the reloading necessary to
make the backend switch work (in some cases, e.g., pure image
backends) so one can set warn=False to suppress the warnings.
The argument is case-insensitive. Switching to an interactive backend is
only safe if no event loop for another interactive backend has started.
Switching to and from non-interactive backends is safe.

To find out which backend is currently set, see
:func:`matplotlib.get_backend`.
To find out which backend is currently set, see `matplotlib.get_backend`.

Parameters
----------
arg : str
The name of the backend to use.
"""
# Lets determine the proper backend name first
if arg.startswith('module://'):
name = arg
else:
# Lowercase only non-module backend names (modules are case-sensitive)
arg = arg.lower()
name = validate_backend(arg)

# Check if we've already set up a backend
if 'matplotlib.backends' in sys.modules:
# Warn only if called with a different name
if (rcParams['backend'] != name) and warn:
import matplotlib.backends
warnings.warn(
_use_error_msg.format(
backend=rcParams['backend'],
tb=matplotlib.backends._backend_loading_tb),
stacklevel=2)

# Unless we've been told to force it, just return
if not force:
return
need_reload = True
else:
need_reload = False
# We want to keep 'use(...); rcdefaults()' working, which means that
# use(...) needs to force the default backend too.
rcParams["backend"] = \
rcParamsDefault["backend"] = rcParamsOrig["backend"] = arg

# Store the backend name
rcParams['backend'] = name

# If needed we reload here because a lot of setup code is triggered on
# module import. See backends/__init__.py for more detail.
if need_reload:
importlib.reload(sys.modules['matplotlib.backends'])
@cbook.deprecated('3.0', alternative='matplotlib.set_backend')
def use(arg, warn=True, force=False):
set_backend(arg, warn, force)


if os.environ.get('MPLBACKEND'):
Expand Down
7 changes: 6 additions & 1 deletion lib/matplotlib/backend_bases.py
Original file line number Diff line number Diff line change
Expand Up @@ -3210,6 +3210,10 @@ class _Backend(object):
# class FooBackend(_Backend):
# # override the attributes and methods documented below.

# Set to one of {"qt5", "qt4", "gtk3", "wx", "tk", "macosx"} if an
# interactive framework is required, or None otherwise.
required_interactive_framework = None

# `backend_version` may be overridden by the subclass.
backend_version = "unknown"

Expand Down Expand Up @@ -3292,7 +3296,8 @@ def show(cls, block=None):

@staticmethod
def export(cls):
for name in ["backend_version",
for name in ["required_interactive_framework",
"backend_version",
"FigureCanvas",
"FigureManager",
"new_figure_manager",
Expand Down
6 changes: 3 additions & 3 deletions lib/matplotlib/backends/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
import traceback

import matplotlib
from matplotlib import cbook
from matplotlib.backend_bases import _Backend

_log = logging.getLogger(__name__)

backend = matplotlib.get_backend()
# FIXME: Remove.
_backend_loading_tb = "".join(
line for line in traceback.format_stack()
# Filter out line noise from importlib line.
Expand Down Expand Up @@ -54,16 +56,14 @@ def _get_running_interactive_framework():
except ImportError:
pass
else:
# Note that the NSApp event loop is also running when a non-native
# toolkit (e.g. Qt5) is active, but in that case we want to report the
# other toolkit; thus, this check comes after the other toolkits.
if _macosx.event_loop_is_running():
return "macosx"
if sys.platform.startswith("linux") and not os.environ.get("DISPLAY"):
return "headless"
return None


@cbook.deprecated("3.0")
def pylab_setup(name=None):
"""
Return new_figure_manager, draw_if_interactive and show for pyplot.
Expand Down
Loading