@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,118 @@
1
+ import pytest
2
+
3
+ from trio import run
4
+ from trio.lowlevel import RunVar, RunVarToken
5
+
6
+ from ... import _core
7
+
8
+
9
+ # scary runvar tests
10
+ def test_runvar_smoketest() -> None:
11
+ t1 = RunVar[str]("test1")
12
+ t2 = RunVar[str]("test2", default="catfish")
13
+
14
+ assert repr(t1) == "<RunVar name='test1'>"
15
+
16
+ async def first_check() -> None:
17
+ with pytest.raises(LookupError):
18
+ t1.get()
19
+
20
+ t1.set("swordfish")
21
+ assert t1.get() == "swordfish"
22
+ assert t2.get() == "catfish"
23
+ assert t2.get(default="eel") == "eel"
24
+
25
+ t2.set("goldfish")
26
+ assert t2.get() == "goldfish"
27
+ assert t2.get(default="tuna") == "goldfish"
28
+
29
+ async def second_check() -> None:
30
+ with pytest.raises(LookupError):
31
+ t1.get()
32
+
33
+ assert t2.get() == "catfish"
34
+
35
+ run(first_check)
36
+ run(second_check)
37
+
38
+
39
+ def test_runvar_resetting() -> None:
40
+ t1 = RunVar[str]("test1")
41
+ t2 = RunVar[str]("test2", default="dogfish")
42
+ t3 = RunVar[str]("test3")
43
+
44
+ async def reset_check() -> None:
45
+ token = t1.set("moonfish")
46
+ assert t1.get() == "moonfish"
47
+ t1.reset(token)
48
+
49
+ with pytest.raises(TypeError):
50
+ t1.reset(None) # type: ignore[arg-type]
51
+
52
+ with pytest.raises(LookupError):
53
+ t1.get()
54
+
55
+ token2 = t2.set("catdogfish")
56
+ assert t2.get() == "catdogfish"
57
+ t2.reset(token2)
58
+ assert t2.get() == "dogfish"
59
+
60
+ with pytest.raises(ValueError, match=r"^token has already been used$"):
61
+ t2.reset(token2)
62
+
63
+ token3 = t3.set("basculin")
64
+ assert t3.get() == "basculin"
65
+
66
+ with pytest.raises(ValueError, match=r"^token is not for us$"):
67
+ t1.reset(token3)
68
+
69
+ run(reset_check)
70
+
71
+
72
+ def test_runvar_sync() -> None:
73
+ t1 = RunVar[str]("test1")
74
+
75
+ async def sync_check() -> None:
76
+ async def task1() -> None:
77
+ t1.set("plaice")
78
+ assert t1.get() == "plaice"
79
+
80
+ async def task2(tok: RunVarToken[str]) -> None:
81
+ t1.reset(tok)
82
+
83
+ with pytest.raises(LookupError):
84
+ t1.get()
85
+
86
+ t1.set("haddock")
87
+
88
+ async with _core.open_nursery() as n:
89
+ token = t1.set("cod")
90
+ assert t1.get() == "cod"
91
+
92
+ n.start_soon(task1)
93
+ await _core.wait_all_tasks_blocked()
94
+ assert t1.get() == "plaice"
95
+
96
+ n.start_soon(task2, token)
97
+ await _core.wait_all_tasks_blocked()
98
+ assert t1.get() == "haddock"
99
+
100
+ run(sync_check)
101
+
102
+
103
+ def test_accessing_runvar_outside_run_call_fails() -> None:
104
+ t1 = RunVar[str]("test1")
105
+
106
+ with pytest.raises(RuntimeError):
107
+ t1.set("asdf")
108
+
109
+ with pytest.raises(RuntimeError):
110
+ t1.get()
111
+
112
+ async def get_token() -> RunVarToken[str]:
113
+ return t1.set("ok")
114
+
115
+ token = run(get_token)
116
+
117
+ with pytest.raises(RuntimeError):
118
+ t1.reset(token)
@@ -0,0 +1,193 @@
1
+ import time
2
+ from math import inf
3
+
4
+ import pytest
5
+
6
+ from trio import sleep
7
+
8
+ from ... import _core
9
+ from .. import wait_all_tasks_blocked
10
+ from .._mock_clock import MockClock
11
+ from .._run import GLOBAL_RUN_CONTEXT
12
+ from .tutil import slow
13
+
14
+
15
+ def test_mock_clock() -> None:
16
+ REAL_NOW = 123.0
17
+ c = MockClock()
18
+ c._real_clock = lambda: REAL_NOW
19
+ repr(c) # smoke test
20
+ assert c.rate == 0
21
+ assert c.current_time() == 0
22
+ c.jump(1.2)
23
+ assert c.current_time() == 1.2
24
+ with pytest.raises(ValueError, match=r"^time can't go backwards$"):
25
+ c.jump(-1)
26
+ assert c.current_time() == 1.2
27
+ assert c.deadline_to_sleep_time(1.1) == 0
28
+ assert c.deadline_to_sleep_time(1.2) == 0
29
+ assert c.deadline_to_sleep_time(1.3) > 999999
30
+
31
+ with pytest.raises(ValueError, match=r"^rate must be >= 0$"):
32
+ c.rate = -1
33
+ assert c.rate == 0
34
+
35
+ c.rate = 2
36
+ assert c.current_time() == 1.2
37
+ REAL_NOW += 1
38
+ assert c.current_time() == 3.2
39
+ assert c.deadline_to_sleep_time(3.1) == 0
40
+ assert c.deadline_to_sleep_time(3.2) == 0
41
+ assert c.deadline_to_sleep_time(4.2) == 0.5
42
+
43
+ c.rate = 0.5
44
+ assert c.current_time() == 3.2
45
+ assert c.deadline_to_sleep_time(3.1) == 0
46
+ assert c.deadline_to_sleep_time(3.2) == 0
47
+ assert c.deadline_to_sleep_time(4.2) == 2.0
48
+
49
+ c.jump(0.8)
50
+ assert c.current_time() == 4.0
51
+ REAL_NOW += 1
52
+ assert c.current_time() == 4.5
53
+
54
+ c2 = MockClock(rate=3)
55
+ assert c2.rate == 3
56
+ assert c2.current_time() < 10
57
+
58
+
59
+ async def test_mock_clock_autojump(mock_clock: MockClock) -> None:
60
+ assert mock_clock.autojump_threshold == inf
61
+
62
+ mock_clock.autojump_threshold = 0
63
+ assert mock_clock.autojump_threshold == 0
64
+
65
+ real_start = time.perf_counter()
66
+
67
+ virtual_start = _core.current_time()
68
+ for i in range(10):
69
+ print(f"sleeping {10 * i} seconds")
70
+ await sleep(10 * i)
71
+ print("woke up!")
72
+ assert virtual_start + 10 * i == _core.current_time()
73
+ virtual_start = _core.current_time()
74
+
75
+ real_duration = time.perf_counter() - real_start
76
+ print(f"Slept {10 * sum(range(10))} seconds in {real_duration} seconds")
77
+ assert real_duration < 1
78
+
79
+ mock_clock.autojump_threshold = 0.02
80
+ t = _core.current_time()
81
+ # this should wake up before the autojump threshold triggers, so time
82
+ # shouldn't change
83
+ await wait_all_tasks_blocked()
84
+ assert t == _core.current_time()
85
+ # this should too
86
+ await wait_all_tasks_blocked(0.01)
87
+ assert t == _core.current_time()
88
+
89
+ # set up a situation where the autojump task is blocked for a long long
90
+ # time, to make sure that cancel-and-adjust-threshold logic is working
91
+ mock_clock.autojump_threshold = 10000
92
+ await wait_all_tasks_blocked()
93
+ mock_clock.autojump_threshold = 0
94
+ # if the above line didn't take affect immediately, then this would be
95
+ # bad:
96
+ # ignore ASYNC116, not sleep_forever, trying to test a large but finite sleep
97
+ await sleep(100000) # noqa: ASYNC116
98
+
99
+
100
+ async def test_mock_clock_autojump_interference(mock_clock: MockClock) -> None:
101
+ mock_clock.autojump_threshold = 0.02
102
+
103
+ mock_clock2 = MockClock()
104
+ # messing with the autojump threshold of a clock that isn't actually
105
+ # installed in the run loop shouldn't do anything.
106
+ mock_clock2.autojump_threshold = 0.01
107
+
108
+ # if the autojump_threshold of 0.01 were in effect, then the next line
109
+ # would block forever, as the autojump task kept waking up to try to
110
+ # jump the clock.
111
+ await wait_all_tasks_blocked(0.015)
112
+
113
+ # but the 0.02 limit does apply
114
+ # ignore ASYNC116, not sleep_forever, trying to test a large but finite sleep
115
+ await sleep(100000) # noqa: ASYNC116
116
+
117
+
118
+ def test_mock_clock_autojump_preset() -> None:
119
+ # Check that we can set the autojump_threshold before the clock is
120
+ # actually in use, and it gets picked up
121
+ mock_clock = MockClock(autojump_threshold=0.1)
122
+ mock_clock.autojump_threshold = 0.01
123
+ real_start = time.perf_counter()
124
+ _core.run(sleep, 10000, clock=mock_clock)
125
+ assert time.perf_counter() - real_start < 1
126
+
127
+
128
+ async def test_mock_clock_autojump_0_and_wait_all_tasks_blocked_0(
129
+ mock_clock: MockClock,
130
+ ) -> None:
131
+ # Checks that autojump_threshold=0 doesn't interfere with
132
+ # calling wait_all_tasks_blocked with the default cushion=0.
133
+
134
+ mock_clock.autojump_threshold = 0
135
+
136
+ record = []
137
+
138
+ async def sleeper() -> None:
139
+ await sleep(100)
140
+ record.append("yawn")
141
+
142
+ async def waiter() -> None:
143
+ await wait_all_tasks_blocked()
144
+ record.append("waiter woke")
145
+ await sleep(1000)
146
+ record.append("waiter done")
147
+
148
+ async with _core.open_nursery() as nursery:
149
+ nursery.start_soon(sleeper)
150
+ nursery.start_soon(waiter)
151
+
152
+ assert record == ["waiter woke", "yawn", "waiter done"]
153
+
154
+
155
+ @slow
156
+ async def test_mock_clock_autojump_0_and_wait_all_tasks_blocked_nonzero(
157
+ mock_clock: MockClock,
158
+ ) -> None:
159
+ # Checks that autojump_threshold=0 doesn't interfere with
160
+ # calling wait_all_tasks_blocked with a non-zero cushion.
161
+
162
+ mock_clock.autojump_threshold = 0
163
+
164
+ record = []
165
+
166
+ async def sleeper() -> None:
167
+ await sleep(100)
168
+ record.append("yawn")
169
+
170
+ async def waiter() -> None:
171
+ await wait_all_tasks_blocked(1)
172
+ record.append("waiter done")
173
+
174
+ async with _core.open_nursery() as nursery:
175
+ nursery.start_soon(sleeper)
176
+ nursery.start_soon(waiter)
177
+
178
+ assert record == ["waiter done", "yawn"]
179
+
180
+
181
+ async def test_initialization_doesnt_mutate_runner() -> None:
182
+ before = (
183
+ GLOBAL_RUN_CONTEXT.runner.clock,
184
+ GLOBAL_RUN_CONTEXT.runner.clock_autojump_threshold,
185
+ )
186
+
187
+ MockClock(autojump_threshold=2, rate=3)
188
+
189
+ after = (
190
+ GLOBAL_RUN_CONTEXT.runner.clock,
191
+ GLOBAL_RUN_CONTEXT.runner.clock_autojump_threshold,
192
+ )
193
+ assert before == after
@@ -0,0 +1,389 @@
1
+ from __future__ import annotations
2
+
3
+ import re
4
+ from typing import TypeVar
5
+
6
+ import pytest
7
+
8
+ import trio
9
+ from trio.lowlevel import (
10
+ add_parking_lot_breaker,
11
+ current_task,
12
+ remove_parking_lot_breaker,
13
+ )
14
+
15
+ from ... import _core
16
+ from ...testing import wait_all_tasks_blocked
17
+ from .._parking_lot import ParkingLot
18
+ from .tutil import check_sequence_matches
19
+
20
+ T = TypeVar("T")
21
+
22
+
23
+ async def test_parking_lot_basic() -> None:
24
+ record = []
25
+
26
+ async def waiter(i: int, lot: ParkingLot) -> None:
27
+ record.append(f"sleep {i}")
28
+ await lot.park()
29
+ record.append(f"wake {i}")
30
+
31
+ async with _core.open_nursery() as nursery:
32
+ lot = ParkingLot()
33
+ assert not lot
34
+ assert len(lot) == 0
35
+ assert lot.statistics().tasks_waiting == 0
36
+ for i in range(3):
37
+ nursery.start_soon(waiter, i, lot)
38
+ await wait_all_tasks_blocked()
39
+ assert len(record) == 3
40
+ assert bool(lot)
41
+ assert len(lot) == 3
42
+ assert lot.statistics().tasks_waiting == 3
43
+ lot.unpark_all()
44
+ assert lot.statistics().tasks_waiting == 0
45
+ await wait_all_tasks_blocked()
46
+ assert len(record) == 6
47
+
48
+ check_sequence_matches(
49
+ record,
50
+ [{"sleep 0", "sleep 1", "sleep 2"}, {"wake 0", "wake 1", "wake 2"}],
51
+ )
52
+
53
+ async with _core.open_nursery() as nursery:
54
+ record = []
55
+ for i in range(3):
56
+ nursery.start_soon(waiter, i, lot)
57
+ await wait_all_tasks_blocked()
58
+ assert len(record) == 3
59
+ for _ in range(3):
60
+ lot.unpark()
61
+ await wait_all_tasks_blocked()
62
+ # 1-by-1 wakeups are strict FIFO
63
+ assert record == [
64
+ "sleep 0",
65
+ "sleep 1",
66
+ "sleep 2",
67
+ "wake 0",
68
+ "wake 1",
69
+ "wake 2",
70
+ ]
71
+
72
+ # It's legal (but a no-op) to try and unpark while there's nothing parked
73
+ lot.unpark()
74
+ lot.unpark(count=1)
75
+ lot.unpark(count=100)
76
+
77
+ # Check unpark with count
78
+ async with _core.open_nursery() as nursery:
79
+ record = []
80
+ for i in range(3):
81
+ nursery.start_soon(waiter, i, lot)
82
+ await wait_all_tasks_blocked()
83
+ lot.unpark(count=2)
84
+ await wait_all_tasks_blocked()
85
+ check_sequence_matches(
86
+ record,
87
+ ["sleep 0", "sleep 1", "sleep 2", {"wake 0", "wake 1"}],
88
+ )
89
+ lot.unpark_all()
90
+
91
+ with pytest.raises(
92
+ ValueError,
93
+ match=r"^Cannot pop a non-integer number of tasks\.$",
94
+ ):
95
+ lot.unpark(count=1.5)
96
+
97
+
98
+ async def cancellable_waiter(
99
+ name: T,
100
+ lot: ParkingLot,
101
+ scopes: dict[T, _core.CancelScope],
102
+ record: list[str],
103
+ ) -> None:
104
+ with _core.CancelScope() as scope:
105
+ scopes[name] = scope
106
+ record.append(f"sleep {name}")
107
+ try:
108
+ await lot.park()
109
+ except _core.Cancelled:
110
+ record.append(f"cancelled {name}")
111
+ else:
112
+ record.append(f"wake {name}")
113
+
114
+
115
+ async def test_parking_lot_cancel() -> None:
116
+ record: list[str] = []
117
+ scopes: dict[int, _core.CancelScope] = {}
118
+
119
+ async with _core.open_nursery() as nursery:
120
+ lot = ParkingLot()
121
+ nursery.start_soon(cancellable_waiter, 1, lot, scopes, record)
122
+ await wait_all_tasks_blocked()
123
+ nursery.start_soon(cancellable_waiter, 2, lot, scopes, record)
124
+ await wait_all_tasks_blocked()
125
+ nursery.start_soon(cancellable_waiter, 3, lot, scopes, record)
126
+ await wait_all_tasks_blocked()
127
+ assert len(record) == 3
128
+
129
+ scopes[2].cancel()
130
+ await wait_all_tasks_blocked()
131
+ assert len(record) == 4
132
+ lot.unpark_all()
133
+ await wait_all_tasks_blocked()
134
+ assert len(record) == 6
135
+
136
+ check_sequence_matches(
137
+ record,
138
+ ["sleep 1", "sleep 2", "sleep 3", "cancelled 2", {"wake 1", "wake 3"}],
139
+ )
140
+
141
+
142
+ async def test_parking_lot_repark() -> None:
143
+ record: list[str] = []
144
+ scopes: dict[int, _core.CancelScope] = {}
145
+ lot1 = ParkingLot()
146
+ lot2 = ParkingLot()
147
+
148
+ with pytest.raises(TypeError):
149
+ lot1.repark([]) # type: ignore[arg-type]
150
+
151
+ async with _core.open_nursery() as nursery:
152
+ nursery.start_soon(cancellable_waiter, 1, lot1, scopes, record)
153
+ await wait_all_tasks_blocked()
154
+ nursery.start_soon(cancellable_waiter, 2, lot1, scopes, record)
155
+ await wait_all_tasks_blocked()
156
+ nursery.start_soon(cancellable_waiter, 3, lot1, scopes, record)
157
+ await wait_all_tasks_blocked()
158
+ assert len(record) == 3
159
+
160
+ assert len(lot1) == 3
161
+ lot1.repark(lot2)
162
+ assert len(lot1) == 2
163
+ assert len(lot2) == 1
164
+ lot2.unpark_all()
165
+ await wait_all_tasks_blocked()
166
+ assert len(record) == 4
167
+ assert record == ["sleep 1", "sleep 2", "sleep 3", "wake 1"]
168
+
169
+ lot1.repark_all(lot2)
170
+ assert len(lot1) == 0
171
+ assert len(lot2) == 2
172
+
173
+ scopes[2].cancel()
174
+ await wait_all_tasks_blocked()
175
+ assert len(lot2) == 1
176
+ assert record == [
177
+ "sleep 1",
178
+ "sleep 2",
179
+ "sleep 3",
180
+ "wake 1",
181
+ "cancelled 2",
182
+ ]
183
+
184
+ lot2.unpark_all()
185
+ await wait_all_tasks_blocked()
186
+ assert record == [
187
+ "sleep 1",
188
+ "sleep 2",
189
+ "sleep 3",
190
+ "wake 1",
191
+ "cancelled 2",
192
+ "wake 3",
193
+ ]
194
+
195
+
196
+ async def test_parking_lot_repark_with_count() -> None:
197
+ record: list[str] = []
198
+ scopes: dict[int, _core.CancelScope] = {}
199
+ lot1 = ParkingLot()
200
+ lot2 = ParkingLot()
201
+ async with _core.open_nursery() as nursery:
202
+ nursery.start_soon(cancellable_waiter, 1, lot1, scopes, record)
203
+ await wait_all_tasks_blocked()
204
+ nursery.start_soon(cancellable_waiter, 2, lot1, scopes, record)
205
+ await wait_all_tasks_blocked()
206
+ nursery.start_soon(cancellable_waiter, 3, lot1, scopes, record)
207
+ await wait_all_tasks_blocked()
208
+ assert len(record) == 3
209
+
210
+ assert len(lot1) == 3
211
+ assert len(lot2) == 0
212
+ lot1.repark(lot2, count=2)
213
+ assert len(lot1) == 1
214
+ assert len(lot2) == 2
215
+ while lot2:
216
+ lot2.unpark()
217
+ await wait_all_tasks_blocked()
218
+ assert record == [
219
+ "sleep 1",
220
+ "sleep 2",
221
+ "sleep 3",
222
+ "wake 1",
223
+ "wake 2",
224
+ ]
225
+ lot1.unpark_all()
226
+
227
+
228
+ async def dummy_task(
229
+ task_status: _core.TaskStatus[_core.Task] = trio.TASK_STATUS_IGNORED,
230
+ ) -> None:
231
+ task_status.started(_core.current_task())
232
+ await trio.sleep_forever()
233
+
234
+
235
+ async def test_parking_lot_breaker_basic() -> None:
236
+ """Test basic functionality for breaking lots."""
237
+ lot = ParkingLot()
238
+ task = current_task()
239
+
240
+ # defaults to current task
241
+ lot.break_lot()
242
+ assert lot.broken_by == [task]
243
+
244
+ # breaking the lot again with the same task appends another copy in `broken_by`
245
+ lot.break_lot()
246
+ assert lot.broken_by == [task, task]
247
+
248
+ # trying to park in broken lot errors
249
+ broken_by_str = re.escape(str([task, task]))
250
+ with pytest.raises(
251
+ _core.BrokenResourceError,
252
+ match=f"^Attempted to park in parking lot broken by {broken_by_str}$",
253
+ ):
254
+ await lot.park()
255
+
256
+
257
+ async def test_parking_lot_break_parking_tasks() -> None:
258
+ """Checks that tasks currently waiting to park raise an error when the breaker exits."""
259
+
260
+ async def bad_parker(lot: ParkingLot, scope: _core.CancelScope) -> None:
261
+ add_parking_lot_breaker(current_task(), lot)
262
+ with scope:
263
+ await trio.sleep_forever()
264
+
265
+ lot = ParkingLot()
266
+ cs = _core.CancelScope()
267
+
268
+ # check that parked task errors
269
+ with pytest.RaisesGroup(
270
+ pytest.RaisesExc(_core.BrokenResourceError, match="^Parking lot broken by"),
271
+ ):
272
+ async with _core.open_nursery() as nursery:
273
+ nursery.start_soon(bad_parker, lot, cs)
274
+ await wait_all_tasks_blocked()
275
+
276
+ nursery.start_soon(lot.park)
277
+ await wait_all_tasks_blocked()
278
+
279
+ cs.cancel()
280
+
281
+
282
+ async def test_parking_lot_breaker_registration() -> None:
283
+ lot = ParkingLot()
284
+ task = current_task()
285
+
286
+ with pytest.raises(
287
+ RuntimeError,
288
+ match="Attempted to remove task as breaker for a lot it is not registered for",
289
+ ):
290
+ remove_parking_lot_breaker(task, lot)
291
+
292
+ # check that a task can be registered as breaker for the same lot multiple times
293
+ add_parking_lot_breaker(task, lot)
294
+ add_parking_lot_breaker(task, lot)
295
+ remove_parking_lot_breaker(task, lot)
296
+ remove_parking_lot_breaker(task, lot)
297
+
298
+ with pytest.raises(
299
+ RuntimeError,
300
+ match="Attempted to remove task as breaker for a lot it is not registered for",
301
+ ):
302
+ remove_parking_lot_breaker(task, lot)
303
+
304
+ # registering a task as breaker on an already broken lot is fine
305
+ lot.break_lot()
306
+ child_task: _core.Task | None = None
307
+ async with trio.open_nursery() as nursery:
308
+ child_task = await nursery.start(dummy_task)
309
+ assert isinstance(child_task, _core.Task)
310
+ add_parking_lot_breaker(child_task, lot)
311
+ nursery.cancel_scope.cancel()
312
+ assert lot.broken_by == [task, child_task]
313
+
314
+ # manually breaking a lot with an already exited task is fine
315
+ lot = ParkingLot()
316
+ lot.break_lot(child_task)
317
+ assert lot.broken_by == [child_task]
318
+
319
+
320
+ async def test_parking_lot_breaker_rebreak() -> None:
321
+ lot = ParkingLot()
322
+ task = current_task()
323
+ lot.break_lot()
324
+
325
+ # breaking an already broken lot with a different task is allowed
326
+ # The nursery is only to create a task we can pass to lot.break_lot
327
+ async with trio.open_nursery() as nursery:
328
+ child_task = await nursery.start(dummy_task)
329
+ lot.break_lot(child_task)
330
+ nursery.cancel_scope.cancel()
331
+
332
+ assert lot.broken_by == [task, child_task]
333
+
334
+
335
+ async def test_parking_lot_multiple_breakers_exit() -> None:
336
+ # register multiple tasks as lot breakers, then have them all exit
337
+ lot = ParkingLot()
338
+ async with trio.open_nursery() as nursery:
339
+ child_task1 = await nursery.start(dummy_task)
340
+ child_task2 = await nursery.start(dummy_task)
341
+ child_task3 = await nursery.start(dummy_task)
342
+ assert isinstance(child_task1, _core.Task)
343
+ assert isinstance(child_task2, _core.Task)
344
+ assert isinstance(child_task3, _core.Task)
345
+ add_parking_lot_breaker(child_task1, lot)
346
+ add_parking_lot_breaker(child_task2, lot)
347
+ add_parking_lot_breaker(child_task3, lot)
348
+ nursery.cancel_scope.cancel()
349
+
350
+ # I think the order is guaranteed currently, but doesn't hurt to be safe.
351
+ assert set(lot.broken_by) == {child_task1, child_task2, child_task3}
352
+
353
+
354
+ async def test_parking_lot_breaker_register_exited_task() -> None:
355
+ lot = ParkingLot()
356
+ child_task: _core.Task | None = None
357
+ async with trio.open_nursery() as nursery:
358
+ value = await nursery.start(dummy_task)
359
+ assert isinstance(value, _core.Task)
360
+ child_task = value
361
+ nursery.cancel_scope.cancel()
362
+ # trying to register an exited task as lot breaker errors
363
+ with pytest.raises(
364
+ trio.BrokenResourceError,
365
+ match=r"^Attempted to add already exited task as lot breaker.$",
366
+ ):
367
+ add_parking_lot_breaker(child_task, lot)
368
+
369
+
370
+ async def test_parking_lot_break_itself() -> None:
371
+ """Break a parking lot, where the breakee is parked.
372
+ Doing this is weird, but should probably be supported.
373
+ """
374
+
375
+ async def return_me_and_park(
376
+ lot: ParkingLot,
377
+ *,
378
+ task_status: _core.TaskStatus[_core.Task] = trio.TASK_STATUS_IGNORED,
379
+ ) -> None:
380
+ task_status.started(_core.current_task())
381
+ await lot.park()
382
+
383
+ lot = ParkingLot()
384
+ with pytest.RaisesGroup(
385
+ pytest.RaisesExc(_core.BrokenResourceError, match="^Parking lot broken by"),
386
+ ):
387
+ async with _core.open_nursery() as nursery:
388
+ child_task = await nursery.start(return_me_and_park, lot)
389
+ lot.break_lot(child_task)