File: test_matplotlib_eventloops.py

package info (click to toggle)
ipykernel 7.1.0-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,128 kB
  • sloc: python: 9,700; makefile: 165; sh: 8
file content (106 lines) | stat: -rw-r--r-- 2,761 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import os
import sys
import time

import pytest
from jupyter_client.blocking.client import BlockingKernelClient

from .test_eventloop import qt_guis_avail
from .utils import assemble_output

# these tests don't seem to work with xvfb yet
# these tests seem to be a problem on CI in general
pytestmark = pytest.mark.skipif(
    bool(os.getenv("CI")),
    reason="tests not working yet reliably on CI",
)

guis = []
if not sys.platform.startswith("tk"):
    guis.append("tk")
if qt_guis_avail:
    guis.append("qt")
if sys.platform == "darwin":
    guis.append("osx")

backends = {
    "tk": "tkagg",
    "qt": "qtagg",
    "osx": "macosx",
}


def execute(
    kc: BlockingKernelClient,
    code: str,
    timeout=120,
):
    msg_id = kc.execute(code)
    stdout, stderr = assemble_output(kc.get_iopub_msg, timeout=timeout, parent_msg_id=msg_id)
    assert not stderr.strip()
    return stdout.strip(), stderr.strip()


@pytest.mark.parametrize("gui", guis)
@pytest.mark.timeout(300)
def test_matplotlib_gui(kc, gui):
    """Make sure matplotlib activates and its eventloop runs while the kernel is also responsive"""
    pytest.importorskip("matplotlib", reason="this test requires matplotlib")
    stdout, stderr = execute(kc, f"%matplotlib {gui}")
    assert not stderr
    # debug: show output from invoking the matplotlib magic
    print(stdout)
    execute(
        kc,
        """
    from concurrent.futures import Future
    import matplotlib as mpl
    import matplotlib.pyplot as plt
    """,
    )
    stdout, _ = execute(kc, "print(mpl.get_backend())")
    assert stdout == backends[gui]
    execute(
        kc,
        """
fig, ax = plt.subplots()
timer = fig.canvas.new_timer(interval=10)
f = Future()

call_count = 0
def add_call():
    global call_count
    call_count += 1
    if not f.done():
        f.set_result(None)

timer.add_callback(add_call)
timer.start()
""",
    )
    # wait for the first call (up to 60 seconds)
    deadline = time.monotonic() + 60
    done = False
    while time.monotonic() <= deadline:
        stdout, _ = execute(kc, "print(f.done())")
        if stdout.strip() == "True":
            done = True
            break
        if stdout == "False":
            time.sleep(0.1)
        else:
            pytest.fail(f"Unexpected output {stdout}")
    if not done:
        pytest.fail("future never finished...")

    time.sleep(0.25)
    stdout, _ = execute(kc, "print(call_count)")
    call_count = int(stdout)
    assert call_count > 0
    time.sleep(0.25)
    stdout, _ = execute(kc, "timer.stop()\nprint(call_count)")
    call_count_2 = int(stdout)
    assert call_count_2 > call_count
    stdout, _ = execute(kc, "print(call_count)")
    call_count_3 = int(stdout)
    assert call_count_3 <= call_count_2 + 5