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 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
import os
import sys
from pathlib import Path
from unittest.mock import Mock, call
import pytest
from psygnal import EmissionInfo, Signal, SignalGroup
from psygnal.utils import decompile, monitor_events, recompile
def test_event_debugger(capsys) -> None:
"""Test that the event debugger works"""
class M:
sig = Signal(int, int)
m = M()
_logger = Mock()
assert not m.sig._slots
with monitor_events(m, _logger):
assert len(m.sig._slots) == 1
m.sig.emit(1, 2)
m.sig.emit(3, 4)
assert _logger.call_count == 2
_logger.assert_has_calls(
[call(EmissionInfo(m.sig, (1, 2))), call(EmissionInfo(m.sig, (3, 4)))]
)
assert not m.sig._slots
with monitor_events(m):
m.sig.emit(1, 2)
m.sig.emit(3, 4)
captured = capsys.readouterr()
assert captured.out == "sig.emit(1, 2)\nsig.emit(3, 4)\n"
def test_old_monitor_api_dep_warning() -> None:
class M:
sig = Signal(int, int)
mock = Mock()
def _monitor(signal_name: str, args: tuple) -> None:
mock(signal_name, args)
m = M()
with pytest.warns(
UserWarning, match="logger functions must now take a single argument"
):
with monitor_events(m, logger=_monitor): # type: ignore
m.sig.emit(1, 2)
mock.assert_called_once_with("sig", (1, 2))
with pytest.raises(ValueError, match="logger function must take a single argument"):
with monitor_events(logger=_monitor): # type: ignore
m.sig.emit(1, 2)
mock.reset_mock()
with monitor_events(m, logger=mock):
m.sig.emit(1, 2)
mock.assert_called_once_with(EmissionInfo(m.sig, (1, 2)))
# global monitor
mock.reset_mock()
with monitor_events(logger=mock):
m.sig.emit(1, 2)
mock.assert_called_once_with(EmissionInfo(m.sig, (1, 2)))
def test_monitor_all() -> None:
class M:
sig = Signal(int, int)
m1 = M()
m2 = M()
_logger = Mock()
with monitor_events(logger=_logger):
m1.sig.emit(1, 2)
m2.sig.emit(3, 4)
m1.sig.emit(5, 6)
m2.sig.emit(7, 8)
assert _logger.call_args_list == [
call(EmissionInfo(m1.sig, (1, 2))),
call(EmissionInfo(m2.sig, (3, 4))),
call(EmissionInfo(m1.sig, (5, 6))),
call(EmissionInfo(m2.sig, (7, 8))),
]
def test_monitor_group() -> None:
class MyGroup(SignalGroup):
sig1 = Signal(int, int)
sig2 = Signal(str, str)
m1 = MyGroup()
m2 = MyGroup()
_logger = Mock()
with monitor_events(logger=_logger):
m1.sig1.emit(1, 2)
m2.sig1.emit(3, 4)
m1.sig1.emit(5, 6)
m2.sig1.emit(7, 8)
m1.sig2.emit("9", "10")
m2.sig2.emit("11", "12")
assert _logger.call_args_list == [
call(EmissionInfo(m1.sig1, (1, 2))),
call(EmissionInfo(m2.sig1, (3, 4))),
call(EmissionInfo(m1.sig1, (5, 6))),
call(EmissionInfo(m2.sig1, (7, 8))),
call(EmissionInfo(m1.sig2, ("9", "10"))),
call(EmissionInfo(m2.sig2, ("11", "12"))),
]
@pytest.mark.skipif(os.name == "nt", reason="rewrite open files on Windows is buggy")
def test_decompile_recompile(monkeypatch):
import psygnal
was_compiled = psygnal._compiled
decompile()
monkeypatch.delitem(sys.modules, "psygnal")
monkeypatch.delitem(sys.modules, "psygnal._signal")
import psygnal
assert not psygnal._compiled
if was_compiled:
assert list(Path(psygnal.__file__).parent.rglob("**/*_BAK"))
recompile()
monkeypatch.delitem(sys.modules, "psygnal")
monkeypatch.delitem(sys.modules, "psygnal._signal")
import psygnal
assert psygnal._compiled
def test_debug_import(monkeypatch):
"""Test that PSYGNAL_UNCOMPILED gives a warning."""
monkeypatch.delitem(sys.modules, "psygnal")
monkeypatch.setenv("PSYGNAL_UNCOMPILED", "1")
with pytest.warns(UserWarning, match="PSYGNAL_UNCOMPILED no longer has any effect"):
import psygnal # noqa: F401
|