File: test_ipython_magic.py

package info (click to toggle)
python-pyinstrument 5.1.1%2Bds-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,624 kB
  • sloc: python: 6,713; ansic: 897; makefile: 46; sh: 26; javascript: 18
file content (139 lines) | stat: -rw-r--r-- 3,512 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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import signal
import textwrap
from test.fake_time_util import fake_time
from threading import Thread
from time import sleep

import pytest

# note: IPython should be imported within each test. Importing it in our tests
# seems to cause problems with subsequent tests.

cell_code = """
import time

def function_a():
    function_b()
    function_c()

def function_b():
    function_d()

def function_c():
    function_d()

def function_d():
    function_e()

def function_e():
    time.sleep(0.1)

function_a()
"""

# Tests #


@pytest.mark.ipythonmagic
def test_magics(ip):
    from IPython.utils.capture import capture_output as capture_ipython_output

    with fake_time():
        with capture_ipython_output() as captured:
            ip.run_cell_magic("pyinstrument", line="", cell=cell_code)

    assert len(captured.outputs) == 1
    output = captured.outputs[0]
    assert "text/html" in output.data
    assert "text/plain" in output.data

    assert "function_a" in output.data["text/html"]
    assert "<iframe" in output.data["text/html"]
    assert "function_a" in output.data["text/plain"]

    assert "- 0.200 function_a" in output.data["text/plain"]
    assert "- 0.100 FakeClock.sleep" in output.data["text/plain"]

    with fake_time():
        with capture_ipython_output() as captured:
            # this works because function_a was defined in the previous cell
            ip.run_line_magic("pyinstrument", line="function_a()")

    assert len(captured.outputs) == 1
    output = captured.outputs[0]

    assert "function_a" in output.data["text/plain"]
    assert "- 0.100 FakeClock.sleep" in output.data["text/plain"]


@pytest.mark.ipythonmagic
def test_magic_empty_line(ip):
    # check empty line input
    ip.run_line_magic("pyinstrument", line="")


@pytest.mark.ipythonmagic
def test_magic_no_variable_expansion(ip, capsys):
    ip.run_line_magic("pyinstrument", line="print(\"hello {len('world')}\")")

    captured = capsys.readouterr()
    assert "hello {len('world')}" in captured.out
    assert "hello 5" not in captured.out


@pytest.mark.ipythonmagic
def test_pyinstrument_handles_interrupt_silently(ip, capsys):
    from pyinstrument.magic.magic import InterruptSilently

    thread = Thread(target=_interrupt_after_1s)
    thread.start()
    # expect our custom exception to bubble up
    with pytest.raises(InterruptSilently):
        ip.run_cell_magic("pyinstrument", "", "from time import sleep; sleep(2)")

    thread.join()
    # nothing should have hit stderr
    _, err = capsys.readouterr()
    assert err.strip() == ""


@pytest.mark.ipythonmagic
def test_async_cell_with_pyinstrument(ip, capsys):
    ip.run_cell_magic(
        "pyinstrument",
        line="--async_mode=enabled",
        cell=textwrap.dedent(
            """
            import asyncio
            async def function_a():
                await asyncio.sleep(0.1)
                return 42
            a = await function_a()
            print("a:", a)
            """
        ),
    )
    stdout, stderr = capsys.readouterr()
    assert "a: 42" in stdout


# Utils #


@pytest.fixture(scope="module")
def session_ip():
    from IPython.testing.globalipapp import start_ipython

    yield start_ipython()


def _interrupt_after_1s():
    sleep(1)
    signal.raise_signal(signal.SIGINT)


@pytest.fixture(scope="function")
def ip(session_ip):
    session_ip.run_line_magic(magic_name="load_ext", line="pyinstrument")
    yield session_ip
    session_ip.run_line_magic(magic_name="reset", line="-f")