@ajksunkang-aios/kgraph-linux-x64 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (196) hide show
  1. package/bin/kgraph-launcher +15 -3
  2. package/lib/kgraph/scripts/build-bundle.sh +17 -4
  3. package/lib/site-packages/outcome/__init__.py +20 -0
  4. package/lib/site-packages/outcome/_impl.py +239 -0
  5. package/lib/site-packages/outcome/_util.py +33 -0
  6. package/lib/site-packages/outcome/_version.py +7 -0
  7. package/lib/site-packages/outcome/py.typed +0 -0
  8. package/lib/site-packages/outcome-1.3.0.post0.dist-info/INSTALLER +1 -0
  9. package/lib/site-packages/outcome-1.3.0.post0.dist-info/LICENSE +3 -0
  10. package/lib/site-packages/outcome-1.3.0.post0.dist-info/LICENSE.APACHE2 +202 -0
  11. package/lib/site-packages/outcome-1.3.0.post0.dist-info/LICENSE.MIT +20 -0
  12. package/lib/site-packages/outcome-1.3.0.post0.dist-info/METADATA +63 -0
  13. package/lib/site-packages/outcome-1.3.0.post0.dist-info/RECORD +13 -0
  14. package/lib/site-packages/outcome-1.3.0.post0.dist-info/WHEEL +6 -0
  15. package/lib/site-packages/outcome-1.3.0.post0.dist-info/top_level.txt +1 -0
  16. package/lib/site-packages/sniffio/__init__.py +17 -0
  17. package/lib/site-packages/sniffio/_impl.py +95 -0
  18. package/lib/site-packages/sniffio/_tests/__init__.py +0 -0
  19. package/lib/site-packages/sniffio/_tests/test_sniffio.py +84 -0
  20. package/lib/site-packages/sniffio/_version.py +3 -0
  21. package/lib/site-packages/sniffio/py.typed +0 -0
  22. package/lib/site-packages/sniffio-1.3.1.dist-info/INSTALLER +1 -0
  23. package/lib/site-packages/sniffio-1.3.1.dist-info/LICENSE +3 -0
  24. package/lib/site-packages/sniffio-1.3.1.dist-info/LICENSE.APACHE2 +202 -0
  25. package/lib/site-packages/sniffio-1.3.1.dist-info/LICENSE.MIT +20 -0
  26. package/lib/site-packages/sniffio-1.3.1.dist-info/METADATA +104 -0
  27. package/lib/site-packages/sniffio-1.3.1.dist-info/RECORD +14 -0
  28. package/lib/site-packages/sniffio-1.3.1.dist-info/WHEEL +5 -0
  29. package/lib/site-packages/sniffio-1.3.1.dist-info/top_level.txt +1 -0
  30. package/lib/site-packages/sortedcontainers/__init__.py +74 -0
  31. package/lib/site-packages/sortedcontainers/sorteddict.py +812 -0
  32. package/lib/site-packages/sortedcontainers/sortedlist.py +2646 -0
  33. package/lib/site-packages/sortedcontainers/sortedset.py +733 -0
  34. package/lib/site-packages/sortedcontainers-2.4.0.dist-info/INSTALLER +1 -0
  35. package/lib/site-packages/sortedcontainers-2.4.0.dist-info/LICENSE +13 -0
  36. package/lib/site-packages/sortedcontainers-2.4.0.dist-info/METADATA +264 -0
  37. package/lib/site-packages/sortedcontainers-2.4.0.dist-info/RECORD +10 -0
  38. package/lib/site-packages/sortedcontainers-2.4.0.dist-info/WHEEL +6 -0
  39. package/lib/site-packages/sortedcontainers-2.4.0.dist-info/top_level.txt +1 -0
  40. package/lib/site-packages/trio/__init__.py +133 -0
  41. package/lib/site-packages/trio/__main__.py +3 -0
  42. package/lib/site-packages/trio/_abc.py +714 -0
  43. package/lib/site-packages/trio/_channel.py +610 -0
  44. package/lib/site-packages/trio/_core/__init__.py +94 -0
  45. package/lib/site-packages/trio/_core/_asyncgens.py +243 -0
  46. package/lib/site-packages/trio/_core/_concat_tb.py +26 -0
  47. package/lib/site-packages/trio/_core/_entry_queue.py +223 -0
  48. package/lib/site-packages/trio/_core/_exceptions.py +169 -0
  49. package/lib/site-packages/trio/_core/_generated_instrumentation.py +50 -0
  50. package/lib/site-packages/trio/_core/_generated_io_epoll.py +98 -0
  51. package/lib/site-packages/trio/_core/_generated_io_kqueue.py +153 -0
  52. package/lib/site-packages/trio/_core/_generated_io_windows.py +204 -0
  53. package/lib/site-packages/trio/_core/_generated_run.py +269 -0
  54. package/lib/site-packages/trio/_core/_generated_windows_ffi.py +10 -0
  55. package/lib/site-packages/trio/_core/_instrumentation.py +117 -0
  56. package/lib/site-packages/trio/_core/_io_common.py +31 -0
  57. package/lib/site-packages/trio/_core/_io_epoll.py +385 -0
  58. package/lib/site-packages/trio/_core/_io_kqueue.py +292 -0
  59. package/lib/site-packages/trio/_core/_io_windows.py +1036 -0
  60. package/lib/site-packages/trio/_core/_ki.py +271 -0
  61. package/lib/site-packages/trio/_core/_local.py +104 -0
  62. package/lib/site-packages/trio/_core/_mock_clock.py +165 -0
  63. package/lib/site-packages/trio/_core/_parking_lot.py +317 -0
  64. package/lib/site-packages/trio/_core/_run.py +3148 -0
  65. package/lib/site-packages/trio/_core/_run_context.py +15 -0
  66. package/lib/site-packages/trio/_core/_tests/__init__.py +0 -0
  67. package/lib/site-packages/trio/_core/_tests/test_asyncgen.py +339 -0
  68. package/lib/site-packages/trio/_core/_tests/test_cancelled.py +222 -0
  69. package/lib/site-packages/trio/_core/_tests/test_exceptiongroup_gc.py +103 -0
  70. package/lib/site-packages/trio/_core/_tests/test_guest_mode.py +755 -0
  71. package/lib/site-packages/trio/_core/_tests/test_instrumentation.py +315 -0
  72. package/lib/site-packages/trio/_core/_tests/test_io.py +522 -0
  73. package/lib/site-packages/trio/_core/_tests/test_ki.py +703 -0
  74. package/lib/site-packages/trio/_core/_tests/test_local.py +118 -0
  75. package/lib/site-packages/trio/_core/_tests/test_mock_clock.py +193 -0
  76. package/lib/site-packages/trio/_core/_tests/test_parking_lot.py +389 -0
  77. package/lib/site-packages/trio/_core/_tests/test_run.py +3024 -0
  78. package/lib/site-packages/trio/_core/_tests/test_thread_cache.py +227 -0
  79. package/lib/site-packages/trio/_core/_tests/test_tutil.py +13 -0
  80. package/lib/site-packages/trio/_core/_tests/test_unbounded_queue.py +154 -0
  81. package/lib/site-packages/trio/_core/_tests/test_windows.py +305 -0
  82. package/lib/site-packages/trio/_core/_tests/tutil.py +117 -0
  83. package/lib/site-packages/trio/_core/_tests/type_tests/nursery_start.py +79 -0
  84. package/lib/site-packages/trio/_core/_tests/type_tests/run.py +51 -0
  85. package/lib/site-packages/trio/_core/_thread_cache.py +317 -0
  86. package/lib/site-packages/trio/_core/_traps.py +318 -0
  87. package/lib/site-packages/trio/_core/_unbounded_queue.py +163 -0
  88. package/lib/site-packages/trio/_core/_wakeup_socketpair.py +75 -0
  89. package/lib/site-packages/trio/_core/_windows_cffi.py +313 -0
  90. package/lib/site-packages/trio/_deprecate.py +171 -0
  91. package/lib/site-packages/trio/_dtls.py +1380 -0
  92. package/lib/site-packages/trio/_file_io.py +513 -0
  93. package/lib/site-packages/trio/_highlevel_generic.py +125 -0
  94. package/lib/site-packages/trio/_highlevel_open_tcp_listeners.py +251 -0
  95. package/lib/site-packages/trio/_highlevel_open_tcp_stream.py +397 -0
  96. package/lib/site-packages/trio/_highlevel_open_unix_stream.py +65 -0
  97. package/lib/site-packages/trio/_highlevel_serve_listeners.py +148 -0
  98. package/lib/site-packages/trio/_highlevel_socket.py +423 -0
  99. package/lib/site-packages/trio/_highlevel_ssl_helpers.py +180 -0
  100. package/lib/site-packages/trio/_path.py +289 -0
  101. package/lib/site-packages/trio/_repl.py +159 -0
  102. package/lib/site-packages/trio/_signals.py +185 -0
  103. package/lib/site-packages/trio/_socket.py +1326 -0
  104. package/lib/site-packages/trio/_ssl.py +964 -0
  105. package/lib/site-packages/trio/_subprocess.py +1178 -0
  106. package/lib/site-packages/trio/_subprocess_platform/__init__.py +123 -0
  107. package/lib/site-packages/trio/_subprocess_platform/kqueue.py +48 -0
  108. package/lib/site-packages/trio/_subprocess_platform/waitid.py +113 -0
  109. package/lib/site-packages/trio/_subprocess_platform/windows.py +11 -0
  110. package/lib/site-packages/trio/_sync.py +908 -0
  111. package/lib/site-packages/trio/_tests/__init__.py +0 -0
  112. package/lib/site-packages/trio/_tests/astrill-codesigning-cert.cer +0 -0
  113. package/lib/site-packages/trio/_tests/check_type_completeness.py +247 -0
  114. package/lib/site-packages/trio/_tests/module_with_deprecations.py +22 -0
  115. package/lib/site-packages/trio/_tests/pytest_plugin.py +54 -0
  116. package/lib/site-packages/trio/_tests/test_abc.py +72 -0
  117. package/lib/site-packages/trio/_tests/test_channel.py +750 -0
  118. package/lib/site-packages/trio/_tests/test_contextvars.py +56 -0
  119. package/lib/site-packages/trio/_tests/test_deprecate.py +277 -0
  120. package/lib/site-packages/trio/_tests/test_deprecate_strict_exception_groups_false.py +64 -0
  121. package/lib/site-packages/trio/_tests/test_dtls.py +950 -0
  122. package/lib/site-packages/trio/_tests/test_exports.py +626 -0
  123. package/lib/site-packages/trio/_tests/test_fakenet.py +317 -0
  124. package/lib/site-packages/trio/_tests/test_file_io.py +269 -0
  125. package/lib/site-packages/trio/_tests/test_highlevel_generic.py +98 -0
  126. package/lib/site-packages/trio/_tests/test_highlevel_open_tcp_listeners.py +419 -0
  127. package/lib/site-packages/trio/_tests/test_highlevel_open_tcp_stream.py +693 -0
  128. package/lib/site-packages/trio/_tests/test_highlevel_open_unix_stream.py +86 -0
  129. package/lib/site-packages/trio/_tests/test_highlevel_serve_listeners.py +186 -0
  130. package/lib/site-packages/trio/_tests/test_highlevel_socket.py +336 -0
  131. package/lib/site-packages/trio/_tests/test_highlevel_ssl_helpers.py +169 -0
  132. package/lib/site-packages/trio/_tests/test_path.py +279 -0
  133. package/lib/site-packages/trio/_tests/test_repl.py +428 -0
  134. package/lib/site-packages/trio/_tests/test_scheduler_determinism.py +47 -0
  135. package/lib/site-packages/trio/_tests/test_signals.py +186 -0
  136. package/lib/site-packages/trio/_tests/test_socket.py +1253 -0
  137. package/lib/site-packages/trio/_tests/test_ssl.py +1371 -0
  138. package/lib/site-packages/trio/_tests/test_subprocess.py +767 -0
  139. package/lib/site-packages/trio/_tests/test_sync.py +735 -0
  140. package/lib/site-packages/trio/_tests/test_testing.py +682 -0
  141. package/lib/site-packages/trio/_tests/test_testing_raisesgroup.py +1128 -0
  142. package/lib/site-packages/trio/_tests/test_threads.py +1173 -0
  143. package/lib/site-packages/trio/_tests/test_timeouts.py +281 -0
  144. package/lib/site-packages/trio/_tests/test_tracing.py +88 -0
  145. package/lib/site-packages/trio/_tests/test_trio.py +8 -0
  146. package/lib/site-packages/trio/_tests/test_unix_pipes.py +288 -0
  147. package/lib/site-packages/trio/_tests/test_util.py +349 -0
  148. package/lib/site-packages/trio/_tests/test_wait_for_object.py +225 -0
  149. package/lib/site-packages/trio/_tests/test_windows_pipes.py +112 -0
  150. package/lib/site-packages/trio/_tests/tools/__init__.py +0 -0
  151. package/lib/site-packages/trio/_tests/tools/test_gen_exports.py +179 -0
  152. package/lib/site-packages/trio/_tests/tools/test_mypy_annotate.py +140 -0
  153. package/lib/site-packages/trio/_tests/tools/test_sync_requirements.py +80 -0
  154. package/lib/site-packages/trio/_tests/type_tests/check_wraps.py +9 -0
  155. package/lib/site-packages/trio/_tests/type_tests/open_memory_channel.py +4 -0
  156. package/lib/site-packages/trio/_tests/type_tests/path.py +140 -0
  157. package/lib/site-packages/trio/_tests/type_tests/subprocesses.py +23 -0
  158. package/lib/site-packages/trio/_tests/type_tests/task_status.py +29 -0
  159. package/lib/site-packages/trio/_threads.py +610 -0
  160. package/lib/site-packages/trio/_timeouts.py +197 -0
  161. package/lib/site-packages/trio/_tools/__init__.py +0 -0
  162. package/lib/site-packages/trio/_tools/gen_exports.py +401 -0
  163. package/lib/site-packages/trio/_tools/mypy_annotate.py +126 -0
  164. package/lib/site-packages/trio/_tools/sync_requirements.py +98 -0
  165. package/lib/site-packages/trio/_tools/windows_ffi_build.py +220 -0
  166. package/lib/site-packages/trio/_unix_pipes.py +197 -0
  167. package/lib/site-packages/trio/_util.py +385 -0
  168. package/lib/site-packages/trio/_version.py +3 -0
  169. package/lib/site-packages/trio/_wait_for_object.py +67 -0
  170. package/lib/site-packages/trio/_windows_pipes.py +144 -0
  171. package/lib/site-packages/trio/abc.py +23 -0
  172. package/lib/site-packages/trio/from_thread.py +13 -0
  173. package/lib/site-packages/trio/lowlevel.py +95 -0
  174. package/lib/site-packages/trio/py.typed +0 -0
  175. package/lib/site-packages/trio/socket.py +602 -0
  176. package/lib/site-packages/trio/testing/__init__.py +58 -0
  177. package/lib/site-packages/trio/testing/_check_streams.py +570 -0
  178. package/lib/site-packages/trio/testing/_checkpoints.py +69 -0
  179. package/lib/site-packages/trio/testing/_fake_net.py +584 -0
  180. package/lib/site-packages/trio/testing/_memory_streams.py +633 -0
  181. package/lib/site-packages/trio/testing/_network.py +36 -0
  182. package/lib/site-packages/trio/testing/_raises_group.py +1015 -0
  183. package/lib/site-packages/trio/testing/_sequencer.py +87 -0
  184. package/lib/site-packages/trio/testing/_trio_test.py +50 -0
  185. package/lib/site-packages/trio/to_thread.py +4 -0
  186. package/lib/site-packages/trio-0.33.0.dist-info/INSTALLER +1 -0
  187. package/lib/site-packages/trio-0.33.0.dist-info/METADATA +186 -0
  188. package/lib/site-packages/trio-0.33.0.dist-info/RECORD +156 -0
  189. package/lib/site-packages/trio-0.33.0.dist-info/REQUESTED +0 -0
  190. package/lib/site-packages/trio-0.33.0.dist-info/WHEEL +5 -0
  191. package/lib/site-packages/trio-0.33.0.dist-info/entry_points.txt +2 -0
  192. package/lib/site-packages/trio-0.33.0.dist-info/licenses/LICENSE +3 -0
  193. package/lib/site-packages/trio-0.33.0.dist-info/licenses/LICENSE.APACHE2 +202 -0
  194. package/lib/site-packages/trio-0.33.0.dist-info/licenses/LICENSE.MIT +22 -0
  195. package/lib/site-packages/trio-0.33.0.dist-info/top_level.txt +1 -0
  196. package/package.json +1 -1
@@ -0,0 +1,315 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, NoReturn
4
+
5
+ import attrs
6
+ import pytest
7
+
8
+ from ... import _abc, _core
9
+ from .tutil import check_sequence_matches
10
+
11
+ if TYPE_CHECKING:
12
+ from collections.abc import Container, Iterable
13
+
14
+ from ...lowlevel import Task
15
+
16
+
17
+ @attrs.define(eq=False, slots=False)
18
+ class TaskRecorder(_abc.Instrument):
19
+ record: list[tuple[str, Task | None]] = attrs.Factory(list)
20
+
21
+ def before_run(self) -> None:
22
+ self.record.append(("before_run", None))
23
+
24
+ def task_scheduled(self, task: Task) -> None:
25
+ self.record.append(("schedule", task))
26
+
27
+ def before_task_step(self, task: Task) -> None:
28
+ assert task is _core.current_task()
29
+ self.record.append(("before", task))
30
+
31
+ def after_task_step(self, task: Task) -> None:
32
+ assert task is _core.current_task()
33
+ self.record.append(("after", task))
34
+
35
+ def after_run(self) -> None:
36
+ self.record.append(("after_run", None))
37
+
38
+ def filter_tasks(self, tasks: Container[Task]) -> Iterable[tuple[str, Task | None]]:
39
+ for item in self.record:
40
+ if item[0] in ("schedule", "before", "after") and item[1] in tasks:
41
+ yield item
42
+ if item[0] in ("before_run", "after_run"):
43
+ yield item
44
+
45
+
46
+ def test_instruments(recwarn: object) -> None:
47
+ r1 = TaskRecorder()
48
+ r2 = TaskRecorder()
49
+ r3 = TaskRecorder()
50
+
51
+ task = None
52
+
53
+ # We use a child task for this, because the main task does some extra
54
+ # bookkeeping stuff that can leak into the instrument results, and we
55
+ # don't want to deal with it.
56
+ async def task_fn() -> None:
57
+ nonlocal task
58
+ task = _core.current_task()
59
+
60
+ for _ in range(4):
61
+ await _core.checkpoint()
62
+ # replace r2 with r3, to test that we can manipulate them as we go
63
+ _core.remove_instrument(r2)
64
+ with pytest.raises(KeyError):
65
+ _core.remove_instrument(r2)
66
+ # add is idempotent
67
+ _core.add_instrument(r3)
68
+ _core.add_instrument(r3)
69
+ for _ in range(1):
70
+ await _core.checkpoint()
71
+
72
+ async def main() -> None:
73
+ async with _core.open_nursery() as nursery:
74
+ nursery.start_soon(task_fn)
75
+
76
+ _core.run(main, instruments=[r1, r2])
77
+
78
+ # It sleeps 5 times, so it runs 6 times. Note that checkpoint()
79
+ # reschedules the task immediately upon yielding, before the
80
+ # after_task_step event fires.
81
+ expected = (
82
+ [("before_run", None), ("schedule", task)]
83
+ + [("before", task), ("schedule", task), ("after", task)] * 5
84
+ + [("before", task), ("after", task), ("after_run", None)]
85
+ )
86
+ assert r1.record == r2.record + r3.record
87
+ assert task is not None
88
+ assert list(r1.filter_tasks([task])) == expected
89
+
90
+
91
+ def test_instruments_interleave() -> None:
92
+ tasks = {}
93
+
94
+ async def two_step1() -> None:
95
+ tasks["t1"] = _core.current_task()
96
+ await _core.checkpoint()
97
+
98
+ async def two_step2() -> None:
99
+ tasks["t2"] = _core.current_task()
100
+ await _core.checkpoint()
101
+
102
+ async def main() -> None:
103
+ async with _core.open_nursery() as nursery:
104
+ nursery.start_soon(two_step1)
105
+ nursery.start_soon(two_step2)
106
+
107
+ r = TaskRecorder()
108
+ _core.run(main, instruments=[r])
109
+
110
+ expected = [
111
+ ("before_run", None),
112
+ ("schedule", tasks["t1"]),
113
+ ("schedule", tasks["t2"]),
114
+ {
115
+ ("before", tasks["t1"]),
116
+ ("schedule", tasks["t1"]),
117
+ ("after", tasks["t1"]),
118
+ ("before", tasks["t2"]),
119
+ ("schedule", tasks["t2"]),
120
+ ("after", tasks["t2"]),
121
+ },
122
+ {
123
+ ("before", tasks["t1"]),
124
+ ("after", tasks["t1"]),
125
+ ("before", tasks["t2"]),
126
+ ("after", tasks["t2"]),
127
+ },
128
+ ("after_run", None),
129
+ ]
130
+ print(list(r.filter_tasks(tasks.values())))
131
+ check_sequence_matches(list(r.filter_tasks(tasks.values())), expected)
132
+
133
+
134
+ def test_null_instrument() -> None:
135
+ # undefined instrument methods are skipped
136
+ class NullInstrument(_abc.Instrument):
137
+ def something_unrelated(self) -> None:
138
+ pass # pragma: no cover
139
+
140
+ async def main() -> None:
141
+ await _core.checkpoint()
142
+
143
+ _core.run(main, instruments=[NullInstrument()])
144
+
145
+
146
+ def test_instrument_before_after_run() -> None:
147
+ record = []
148
+
149
+ class BeforeAfterRun(_abc.Instrument):
150
+ def before_run(self) -> None:
151
+ record.append("before_run")
152
+
153
+ def after_run(self) -> None:
154
+ record.append("after_run")
155
+
156
+ async def main() -> None:
157
+ pass
158
+
159
+ _core.run(main, instruments=[BeforeAfterRun()])
160
+ assert record == ["before_run", "after_run"]
161
+
162
+
163
+ def test_instrument_task_spawn_exit() -> None:
164
+ record = []
165
+
166
+ class SpawnExitRecorder(_abc.Instrument):
167
+ def task_spawned(self, task: Task) -> None:
168
+ record.append(("spawned", task))
169
+
170
+ def task_exited(self, task: Task) -> None:
171
+ record.append(("exited", task))
172
+
173
+ async def main() -> Task:
174
+ return _core.current_task()
175
+
176
+ main_task = _core.run(main, instruments=[SpawnExitRecorder()])
177
+ assert ("spawned", main_task) in record
178
+ assert ("exited", main_task) in record
179
+
180
+
181
+ # This test also tests having a crash before the initial task is even spawned,
182
+ # which is very difficult to handle.
183
+ def test_instruments_crash(caplog: pytest.LogCaptureFixture) -> None:
184
+ record = []
185
+
186
+ class BrokenInstrument(_abc.Instrument):
187
+ def task_scheduled(self, task: Task) -> NoReturn:
188
+ record.append("scheduled")
189
+ raise ValueError("oops")
190
+
191
+ def close(self) -> None:
192
+ # Shouldn't be called -- tests that the instrument disabling logic
193
+ # works right.
194
+ record.append("closed") # pragma: no cover
195
+
196
+ async def main() -> Task:
197
+ record.append("main ran")
198
+ return _core.current_task()
199
+
200
+ r = TaskRecorder()
201
+ main_task = _core.run(main, instruments=[r, BrokenInstrument()])
202
+ assert record == ["scheduled", "main ran"]
203
+ # the TaskRecorder kept going throughout, even though the BrokenInstrument
204
+ # was disabled
205
+ assert ("after", main_task) in r.record
206
+ assert ("after_run", None) in r.record
207
+ # And we got a log message
208
+ assert caplog.records[0].exc_info is not None
209
+ exc_type, exc_value, _exc_traceback = caplog.records[0].exc_info
210
+ assert exc_type is ValueError
211
+ assert str(exc_value) == "oops"
212
+ assert "Instrument has been disabled" in caplog.records[0].message
213
+
214
+
215
+ def test_instruments_monkeypatch() -> None:
216
+ class NullInstrument(_abc.Instrument):
217
+ pass
218
+
219
+ instrument = NullInstrument()
220
+
221
+ async def main() -> None:
222
+ record: list[Task] = []
223
+
224
+ # Changing the set of hooks implemented by an instrument after
225
+ # it's installed doesn't make them start being called right away
226
+ instrument.before_task_step = ( # type: ignore[method-assign]
227
+ record.append # type: ignore[assignment] # append is pos-only
228
+ )
229
+
230
+ await _core.checkpoint()
231
+ await _core.checkpoint()
232
+ assert len(record) == 0
233
+
234
+ # But if we remove and re-add the instrument, the new hooks are
235
+ # picked up
236
+ _core.remove_instrument(instrument)
237
+ _core.add_instrument(instrument)
238
+ await _core.checkpoint()
239
+ await _core.checkpoint()
240
+ assert record.count(_core.current_task()) == 2
241
+
242
+ _core.remove_instrument(instrument)
243
+ await _core.checkpoint()
244
+ await _core.checkpoint()
245
+ assert record.count(_core.current_task()) == 2
246
+
247
+ _core.run(main, instruments=[instrument])
248
+
249
+
250
+ def test_instrument_that_raises_on_getattr() -> None:
251
+ class EvilInstrument(_abc.Instrument):
252
+ def task_exited(self, task: Task) -> NoReturn:
253
+ raise AssertionError("this should never happen") # pragma: no cover
254
+
255
+ @property
256
+ def after_run(self) -> NoReturn:
257
+ raise ValueError("oops")
258
+
259
+ async def main() -> None:
260
+ with pytest.raises(ValueError, match=r"^oops$"):
261
+ _core.add_instrument(EvilInstrument())
262
+
263
+ # Make sure the instrument is fully removed from the per-method lists
264
+ runner = _core.current_task()._runner
265
+ assert "after_run" not in runner.instruments
266
+ assert "task_exited" not in runner.instruments
267
+
268
+ _core.run(main)
269
+
270
+
271
+ def test_instrument_call_trio_context() -> None:
272
+ called = set()
273
+
274
+ class Instrument(_abc.Instrument):
275
+ pass
276
+
277
+ hooks = {
278
+ # not run in task context
279
+ "after_io_wait": (True, False),
280
+ "before_io_wait": (True, False),
281
+ "before_run": (True, False),
282
+ "after_run": (True, False),
283
+ # run in task context
284
+ "before_task_step": (True, True),
285
+ "after_task_step": (True, True),
286
+ "task_exited": (True, True),
287
+ # depends
288
+ "task_scheduled": (True, None),
289
+ "task_spawned": (True, None),
290
+ }
291
+ for hook, val in hooks.items():
292
+
293
+ def h(
294
+ self: Instrument,
295
+ *args: object,
296
+ hook: str = hook,
297
+ val: tuple[bool, bool | None] = val,
298
+ ) -> None:
299
+ fail_str = f"failed in {hook}"
300
+
301
+ assert _core.in_trio_run() == val[0], fail_str
302
+ if val[1] is not None:
303
+ assert _core.in_trio_task() == val[1], fail_str
304
+ called.add(hook)
305
+
306
+ setattr(Instrument, hook, h)
307
+
308
+ async def main() -> None:
309
+ await _core.checkpoint()
310
+
311
+ async with _core.open_nursery() as nursery:
312
+ nursery.start_soon(_core.checkpoint)
313
+
314
+ _core.run(main, instruments=[Instrument()])
315
+ assert called == set(hooks)