Skip to content

Commit 2888c0b

Browse files
authored
Merge pull request matplotlib#29993 from anntzer/undoevent
Trigger events via standard callbacks in widget testing.
2 parents 4a60fac + 2b9f263 commit 2888c0b

File tree

5 files changed

+235
-231
lines changed

5 files changed

+235
-231
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
``testing.widgets.mock_event`` and ``testing.widgets.do_event``
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
... are deprecated. Directly construct Event objects (typically `.MouseEvent`
4+
or `.KeyEvent`) and pass them to ``canvas.callbacks.process()`` instead.

lib/matplotlib/backend_bases.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1413,6 +1413,23 @@ def __init__(self, name, canvas, x, y, button=None, key=None,
14131413
self.step = step
14141414
self.dblclick = dblclick
14151415

1416+
@classmethod
1417+
def _from_ax_coords(cls, name, ax, xy, *args, **kwargs):
1418+
"""
1419+
Generate a synthetic event at a given axes coordinate.
1420+
1421+
This method is intended for creating events during testing. The event
1422+
can be emitted by calling its ``_process()`` method.
1423+
1424+
args and kwargs are mapped to `.MouseEvent.__init__` parameters,
1425+
starting with `button`.
1426+
"""
1427+
x, y = ax.transData.transform(xy)
1428+
event = cls(name, ax.figure.canvas, x, y, *args, **kwargs)
1429+
event.inaxes = ax
1430+
event.xdata, event.ydata = xy # Force exact xy to avoid fp roundtrip issues.
1431+
return event
1432+
14161433
def __str__(self):
14171434
return (f"{self.name}: "
14181435
f"xy=({self.x}, {self.y}) xydata=({self.xdata}, {self.ydata}) "
@@ -1505,6 +1522,22 @@ def __init__(self, name, canvas, key, x=0, y=0, guiEvent=None):
15051522
super().__init__(name, canvas, x, y, guiEvent=guiEvent)
15061523
self.key = key
15071524

1525+
@classmethod
1526+
def _from_ax_coords(cls, name, ax, xy, key, *args, **kwargs):
1527+
"""
1528+
Generate a synthetic event at a given axes coordinate.
1529+
1530+
This method is intended for creating events during testing. The event
1531+
can be emitted by calling its ``_process()`` method.
1532+
"""
1533+
# Separate from MouseEvent._from_ax_coords instead of being defined in the base
1534+
# class, due to different parameter order in the constructor signature.
1535+
x, y = ax.transData.transform(xy)
1536+
event = cls(name, ax.figure.canvas, key, x, y, *args, **kwargs)
1537+
event.inaxes = ax
1538+
event.xdata, event.ydata = xy # Force exact xy to avoid fp roundtrip issues.
1539+
return event
1540+
15081541

15091542
# Default callback for key events.
15101543
def _key_handler(event):

lib/matplotlib/testing/widgets.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
from unittest import mock
1010

11+
from matplotlib import _api
12+
from matplotlib.backend_bases import MouseEvent, KeyEvent
1113
import matplotlib.pyplot as plt
1214

1315

@@ -24,6 +26,7 @@ def noop(*args, **kwargs):
2426
pass
2527

2628

29+
@_api.deprecated("3.11", alternative="MouseEvent or KeyEvent")
2730
def mock_event(ax, button=1, xdata=0, ydata=0, key=None, step=1):
2831
r"""
2932
Create a mock event that can stand in for `.Event` and its subclasses.
@@ -65,6 +68,7 @@ def mock_event(ax, button=1, xdata=0, ydata=0, key=None, step=1):
6568
return event
6669

6770

71+
@_api.deprecated("3.11", alternative="callbacks.process(event)")
6872
def do_event(tool, etype, button=1, xdata=0, ydata=0, key=None, step=1):
6973
"""
7074
Trigger an event on the given tool.
@@ -105,15 +109,12 @@ def click_and_drag(tool, start, end, key=None):
105109
An optional key that is pressed during the whole operation
106110
(see also `.KeyEvent`).
107111
"""
108-
if key is not None:
109-
# Press key
110-
do_event(tool, 'on_key_press', xdata=start[0], ydata=start[1],
111-
button=1, key=key)
112+
ax = tool.ax
113+
if key is not None: # Press key
114+
KeyEvent._from_ax_coords("key_press_event", ax, start, key)._process()
112115
# Click, move, and release mouse
113-
do_event(tool, 'press', xdata=start[0], ydata=start[1], button=1)
114-
do_event(tool, 'onmove', xdata=end[0], ydata=end[1], button=1)
115-
do_event(tool, 'release', xdata=end[0], ydata=end[1], button=1)
116-
if key is not None:
117-
# Release key
118-
do_event(tool, 'on_key_release', xdata=end[0], ydata=end[1],
119-
button=1, key=key)
116+
MouseEvent._from_ax_coords("button_press_event", ax, start, 1)._process()
117+
MouseEvent._from_ax_coords("motion_notify_event", ax, end, 1)._process()
118+
MouseEvent._from_ax_coords("button_release_event", ax, end, 1)._process()
119+
if key is not None: # Release key
120+
KeyEvent._from_ax_coords("key_release_event", ax, end, key)._process()

0 commit comments

Comments
 (0)