@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,271 @@
1
+ from __future__ import annotations
2
+
3
+ import signal
4
+ import sys
5
+ import weakref
6
+ from typing import TYPE_CHECKING, Generic, Protocol, TypeGuard, TypeVar
7
+
8
+ import attrs
9
+
10
+ from .._util import is_main_thread
11
+ from ._run_context import GLOBAL_RUN_CONTEXT
12
+
13
+ if TYPE_CHECKING:
14
+ import types
15
+ from collections.abc import Callable
16
+
17
+ from typing_extensions import Self
18
+ # In ordinary single-threaded Python code, when you hit control-C, it raises
19
+ # an exception and automatically does all the regular unwinding stuff.
20
+ #
21
+ # In Trio code, we would like hitting control-C to raise an exception and
22
+ # automatically do all the regular unwinding stuff. In particular, we would
23
+ # like to maintain our invariant that all tasks always run to completion (one
24
+ # way or another), by unwinding all of them.
25
+ #
26
+ # But it's basically impossible to write the core task running code in such a
27
+ # way that it can maintain this invariant in the face of KeyboardInterrupt
28
+ # exceptions arising at arbitrary bytecode positions. Similarly, if a
29
+ # KeyboardInterrupt happened at the wrong moment inside pretty much any of our
30
+ # inter-task synchronization or I/O primitives, then the system state could
31
+ # get corrupted and prevent our being able to clean up properly.
32
+ #
33
+ # So, we need a way to defer KeyboardInterrupt processing from these critical
34
+ # sections.
35
+ #
36
+ # Things that don't work:
37
+ #
38
+ # - Listen for SIGINT and process it in a system task: works fine for
39
+ # well-behaved programs that regularly pass through the event loop, but if
40
+ # user-code goes into an infinite loop then it can't be interrupted. Which
41
+ # is unfortunate, since dealing with infinite loops is what
42
+ # KeyboardInterrupt is for!
43
+ #
44
+ # - Use pthread_sigmask to disable signal delivery during critical section:
45
+ # (a) windows has no pthread_sigmask, (b) python threads start with all
46
+ # signals unblocked, so if there are any threads around they'll receive the
47
+ # signal and then tell the main thread to run the handler, even if the main
48
+ # thread has that signal blocked.
49
+ #
50
+ # - Install a signal handler which checks a global variable to decide whether
51
+ # to raise the exception immediately (if we're in a non-critical section),
52
+ # or to schedule it on the event loop (if we're in a critical section). The
53
+ # problem here is that it's impossible to transition safely out of user code:
54
+ #
55
+ # with keyboard_interrupt_enabled:
56
+ # msg = coro.send(value)
57
+ #
58
+ # If this raises a KeyboardInterrupt, it might be because the coroutine got
59
+ # interrupted and has unwound... or it might be the KeyboardInterrupt
60
+ # arrived just *after* 'send' returned, so the coroutine is still running,
61
+ # but we just lost the message it sent. (And worse, in our actual task
62
+ # runner, the send is hidden inside a utility function etc.)
63
+ #
64
+ # Solution:
65
+ #
66
+ # Mark *stack frames* as being interrupt-safe or interrupt-unsafe, and from
67
+ # the signal handler check which kind of frame we're currently in when
68
+ # deciding whether to raise or schedule the exception.
69
+ #
70
+ # There are still some cases where this can fail, like if someone hits
71
+ # control-C while the process is in the event loop, and then it immediately
72
+ # enters an infinite loop in user code. In this case the user has to hit
73
+ # control-C a second time. And of course if the user code is written so that
74
+ # it doesn't actually exit after a task crashes and everything gets cancelled,
75
+ # then there's not much to be done. (Hitting control-C repeatedly might help,
76
+ # but in general the solution is to kill the process some other way, just like
77
+ # for any Python program that's written to catch and ignore
78
+ # KeyboardInterrupt.)
79
+
80
+ _T = TypeVar("_T")
81
+
82
+
83
+ class _IdRef(weakref.ref[_T]):
84
+ __slots__ = ("_hash",)
85
+ _hash: int
86
+
87
+ def __new__(
88
+ cls,
89
+ ob: _T,
90
+ callback: Callable[[Self], object] | None = None,
91
+ /,
92
+ ) -> Self:
93
+ self: Self = weakref.ref.__new__(cls, ob, callback)
94
+ self._hash = object.__hash__(ob)
95
+ return self
96
+
97
+ def __eq__(self, other: object) -> bool:
98
+ if self is other:
99
+ return True
100
+
101
+ if not isinstance(other, _IdRef):
102
+ return NotImplemented
103
+
104
+ my_obj = None
105
+ try:
106
+ my_obj = self()
107
+ return my_obj is not None and my_obj is other()
108
+ finally:
109
+ del my_obj
110
+
111
+ # we're overriding a builtin so we do need this
112
+ def __ne__(self, other: object) -> bool:
113
+ return not self == other
114
+
115
+ def __hash__(self) -> int:
116
+ return self._hash
117
+
118
+
119
+ _KT = TypeVar("_KT")
120
+ _VT = TypeVar("_VT")
121
+
122
+
123
+ # see also: https://github.com/python/cpython/issues/88306
124
+ class WeakKeyIdentityDictionary(Generic[_KT, _VT]):
125
+ def __init__(self) -> None:
126
+ self._data: dict[_IdRef[_KT], _VT] = {}
127
+
128
+ def remove(
129
+ k: _IdRef[_KT],
130
+ selfref: weakref.ref[
131
+ WeakKeyIdentityDictionary[_KT, _VT]
132
+ ] = weakref.ref( # noqa: B008 # function-call-in-default-argument
133
+ self,
134
+ ),
135
+ ) -> None:
136
+ self = selfref()
137
+ if self is not None:
138
+ try: # noqa: SIM105 # suppressible-exception
139
+ del self._data[k]
140
+ except KeyError:
141
+ pass
142
+
143
+ self._remove = remove
144
+
145
+ def __getitem__(self, k: _KT) -> _VT:
146
+ return self._data[_IdRef(k)]
147
+
148
+ def __setitem__(self, k: _KT, v: _VT) -> None:
149
+ self._data[_IdRef(k, self._remove)] = v
150
+
151
+
152
+ _CODE_KI_PROTECTION_STATUS_WMAP: WeakKeyIdentityDictionary[
153
+ types.CodeType,
154
+ bool,
155
+ ] = WeakKeyIdentityDictionary()
156
+
157
+
158
+ # This is to support the async_generator package necessary for aclosing on <3.10
159
+ # functions decorated @async_generator are given this magic property that's a
160
+ # reference to the object itself
161
+ # see python-trio/async_generator/async_generator/_impl.py
162
+ def legacy_isasyncgenfunction(
163
+ obj: object,
164
+ ) -> TypeGuard[Callable[..., types.AsyncGeneratorType[object, object]]]:
165
+ return getattr(obj, "_async_gen_function", None) == id(obj)
166
+
167
+
168
+ # NB: according to the signal.signal docs, 'frame' can be None on entry to
169
+ # this function:
170
+ def ki_protection_enabled(frame: types.FrameType | None) -> bool:
171
+ try:
172
+ task = GLOBAL_RUN_CONTEXT.task
173
+ except AttributeError:
174
+ task_ki_protected = False
175
+ task_frame = None
176
+ else:
177
+ task_ki_protected = task._ki_protected
178
+ task_frame = task.coro.cr_frame
179
+
180
+ while frame is not None:
181
+ try:
182
+ v = _CODE_KI_PROTECTION_STATUS_WMAP[frame.f_code]
183
+ except KeyError:
184
+ pass
185
+ else:
186
+ return bool(v)
187
+ if frame.f_code.co_name == "__del__":
188
+ return True
189
+ if frame is task_frame:
190
+ return task_ki_protected
191
+ frame = frame.f_back
192
+ return True
193
+
194
+
195
+ def currently_ki_protected() -> bool:
196
+ r"""Check whether the calling code has :exc:`KeyboardInterrupt` protection
197
+ enabled.
198
+
199
+ It's surprisingly easy to think that one's :exc:`KeyboardInterrupt`
200
+ protection is enabled when it isn't, or vice-versa. This function tells
201
+ you what Trio thinks of the matter, which makes it useful for ``assert``\s
202
+ and unit tests.
203
+
204
+ Returns:
205
+ bool: True if protection is enabled, and False otherwise.
206
+
207
+ """
208
+ return ki_protection_enabled(sys._getframe())
209
+
210
+
211
+ class _SupportsCode(Protocol):
212
+ __code__: types.CodeType
213
+
214
+
215
+ _T_supports_code = TypeVar("_T_supports_code", bound=_SupportsCode)
216
+
217
+
218
+ def enable_ki_protection(f: _T_supports_code, /) -> _T_supports_code:
219
+ """Decorator to enable KI protection."""
220
+ orig = f
221
+
222
+ if legacy_isasyncgenfunction(f):
223
+ f = f.__wrapped__ # type: ignore
224
+
225
+ _CODE_KI_PROTECTION_STATUS_WMAP[f.__code__] = True
226
+ return orig
227
+
228
+
229
+ def disable_ki_protection(f: _T_supports_code, /) -> _T_supports_code:
230
+ """Decorator to disable KI protection."""
231
+ orig = f
232
+
233
+ if legacy_isasyncgenfunction(f):
234
+ f = f.__wrapped__ # type: ignore
235
+
236
+ _CODE_KI_PROTECTION_STATUS_WMAP[f.__code__] = False
237
+ return orig
238
+
239
+
240
+ @attrs.define(slots=False)
241
+ class KIManager:
242
+ handler: Callable[[int, types.FrameType | None], None] | None = None
243
+
244
+ def install(
245
+ self,
246
+ deliver_cb: Callable[[], object],
247
+ restrict_keyboard_interrupt_to_checkpoints: bool,
248
+ ) -> None:
249
+ assert self.handler is None
250
+ if (
251
+ not is_main_thread()
252
+ or signal.getsignal(signal.SIGINT) != signal.default_int_handler
253
+ ):
254
+ return
255
+
256
+ def handler(signum: int, frame: types.FrameType | None) -> None:
257
+ assert signum == signal.SIGINT
258
+ protection_enabled = ki_protection_enabled(frame)
259
+ if protection_enabled or restrict_keyboard_interrupt_to_checkpoints:
260
+ deliver_cb()
261
+ else:
262
+ raise KeyboardInterrupt
263
+
264
+ self.handler = handler
265
+ signal.signal(signal.SIGINT, handler)
266
+
267
+ def close(self) -> None:
268
+ if self.handler is not None:
269
+ if signal.getsignal(signal.SIGINT) is self.handler:
270
+ signal.signal(signal.SIGINT, signal.default_int_handler)
271
+ self.handler = None
@@ -0,0 +1,104 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Generic, TypeVar, cast
4
+
5
+ # Runvar implementations
6
+ import attrs
7
+
8
+ from .._util import NoPublicConstructor, final
9
+ from . import _run
10
+
11
+ T = TypeVar("T")
12
+
13
+
14
+ @final
15
+ class _NoValue: ...
16
+
17
+
18
+ @final
19
+ @attrs.define(eq=False)
20
+ class RunVarToken(Generic[T], metaclass=NoPublicConstructor):
21
+ _var: RunVar[T]
22
+ previous_value: T | type[_NoValue] = _NoValue
23
+ redeemed: bool = attrs.field(default=False, init=False)
24
+
25
+ @classmethod
26
+ def _empty(cls, var: RunVar[T]) -> RunVarToken[T]:
27
+ return cls._create(var)
28
+
29
+
30
+ @final
31
+ @attrs.define(eq=False, repr=False)
32
+ class RunVar(Generic[T]):
33
+ """The run-local variant of a context variable.
34
+
35
+ :class:`RunVar` objects are similar to context variable objects,
36
+ except that they are shared across a single call to :func:`trio.run`
37
+ rather than a single task.
38
+
39
+ """
40
+
41
+ _name: str = attrs.field(alias="name")
42
+ _default: T | type[_NoValue] = attrs.field(default=_NoValue, alias="default")
43
+
44
+ def get(self, default: T | type[_NoValue] = _NoValue) -> T:
45
+ """Gets the value of this :class:`RunVar` for the current run call."""
46
+ try:
47
+ return cast("T", _run.GLOBAL_RUN_CONTEXT.runner._locals[self])
48
+ except AttributeError:
49
+ raise RuntimeError("Cannot be used outside of a run context") from None
50
+ except KeyError:
51
+ # contextvars consistency
52
+ # `type: ignore` awaiting https://github.com/python/mypy/issues/15553 to be fixed & released
53
+ if default is not _NoValue:
54
+ return default # type: ignore[return-value]
55
+
56
+ if self._default is not _NoValue:
57
+ return self._default # type: ignore[return-value]
58
+
59
+ raise LookupError(self) from None
60
+
61
+ def set(self, value: T) -> RunVarToken[T]:
62
+ """Sets the value of this :class:`RunVar` for this current run
63
+ call.
64
+
65
+ """
66
+ try:
67
+ old_value = self.get()
68
+ except LookupError:
69
+ token = RunVarToken._empty(self)
70
+ else:
71
+ token = RunVarToken[T]._create(self, old_value)
72
+
73
+ # This can't fail, because if we weren't in Trio context then the
74
+ # get() above would have failed.
75
+ _run.GLOBAL_RUN_CONTEXT.runner._locals[self] = value
76
+ return token
77
+
78
+ def reset(self, token: RunVarToken[T]) -> None:
79
+ """Resets the value of this :class:`RunVar` to what it was
80
+ previously specified by the token.
81
+
82
+ """
83
+ if token is None:
84
+ raise TypeError("token must not be none")
85
+
86
+ if token.redeemed:
87
+ raise ValueError("token has already been used")
88
+
89
+ if token._var is not self:
90
+ raise ValueError("token is not for us")
91
+
92
+ previous = token.previous_value
93
+ try:
94
+ if previous is _NoValue:
95
+ _run.GLOBAL_RUN_CONTEXT.runner._locals.pop(self)
96
+ else:
97
+ _run.GLOBAL_RUN_CONTEXT.runner._locals[self] = previous
98
+ except AttributeError:
99
+ raise RuntimeError("Cannot be used outside of a run context") from None
100
+
101
+ token.redeemed = True
102
+
103
+ def __repr__(self) -> str:
104
+ return f"<RunVar name={self._name!r}>"
@@ -0,0 +1,165 @@
1
+ import time
2
+ from math import inf
3
+
4
+ from .. import _core
5
+ from .._abc import Clock
6
+ from .._util import final
7
+ from ._run import GLOBAL_RUN_CONTEXT
8
+
9
+ ################################################################
10
+ # The glorious MockClock
11
+ ################################################################
12
+
13
+
14
+ # Prior art:
15
+ # https://twistedmatrix.com/documents/current/api/twisted.internet.task.Clock.html
16
+ # https://github.com/ztellman/manifold/issues/57
17
+ @final
18
+ class MockClock(Clock):
19
+ """A user-controllable clock suitable for writing tests.
20
+
21
+ Args:
22
+ rate (float): the initial :attr:`rate`.
23
+ autojump_threshold (float): the initial :attr:`autojump_threshold`.
24
+
25
+ .. attribute:: rate
26
+
27
+ How many seconds of clock time pass per second of real time. Default is
28
+ 0.0, i.e. the clock only advances through manuals calls to :meth:`jump`
29
+ or when the :attr:`autojump_threshold` is triggered. You can assign to
30
+ this attribute to change it.
31
+
32
+ .. attribute:: autojump_threshold
33
+
34
+ The clock keeps an eye on the run loop, and if at any point it detects
35
+ that all tasks have been blocked for this many real seconds (i.e.,
36
+ according to the actual clock, not this clock), then the clock
37
+ automatically jumps ahead to the run loop's next scheduled
38
+ timeout. Default is :data:`math.inf`, i.e., to never autojump. You can
39
+ assign to this attribute to change it.
40
+
41
+ Basically the idea is that if you have code or tests that use sleeps
42
+ and timeouts, you can use this to make it run much faster, totally
43
+ automatically. (At least, as long as those sleeps/timeouts are
44
+ happening inside Trio; if your test involves talking to external
45
+ service and waiting for it to timeout then obviously we can't help you
46
+ there.)
47
+
48
+ You should set this to the smallest value that lets you reliably avoid
49
+ "false alarms" where some I/O is in flight (e.g. between two halves of
50
+ a socketpair) but the threshold gets triggered and time gets advanced
51
+ anyway. This will depend on the details of your tests and test
52
+ environment. If you aren't doing any I/O (like in our sleeping example
53
+ above) then just set it to zero, and the clock will jump whenever all
54
+ tasks are blocked.
55
+
56
+ .. note:: If you use ``autojump_threshold`` and
57
+ `wait_all_tasks_blocked` at the same time, then you might wonder how
58
+ they interact, since they both cause things to happen after the run
59
+ loop goes idle for some time. The answer is:
60
+ `wait_all_tasks_blocked` takes priority. If there's a task blocked
61
+ in `wait_all_tasks_blocked`, then the autojump feature treats that
62
+ as active task and does *not* jump the clock.
63
+
64
+ """
65
+
66
+ def __init__(self, rate: float = 0.0, autojump_threshold: float = inf) -> None:
67
+ # when the real clock said 'real_base', the virtual time was
68
+ # 'virtual_base', and since then it's advanced at 'rate' virtual
69
+ # seconds per real second.
70
+ self._real_base = 0.0
71
+ self._virtual_base = 0.0
72
+ self._rate = 0.0
73
+
74
+ # kept as an attribute so that our tests can monkeypatch it
75
+ self._real_clock = time.perf_counter
76
+
77
+ # use the property update logic to set initial values
78
+ self.rate = rate
79
+ self.autojump_threshold = autojump_threshold
80
+
81
+ def __repr__(self) -> str:
82
+ return f"<MockClock, time={self.current_time():.7f}, rate={self._rate} @ {id(self):#x}>"
83
+
84
+ @property
85
+ def rate(self) -> float:
86
+ return self._rate
87
+
88
+ @rate.setter
89
+ def rate(self, new_rate: float) -> None:
90
+ if new_rate < 0:
91
+ raise ValueError("rate must be >= 0")
92
+ else:
93
+ real = self._real_clock()
94
+ virtual = self._real_to_virtual(real)
95
+ self._virtual_base = virtual
96
+ self._real_base = real
97
+ self._rate = float(new_rate)
98
+
99
+ @property
100
+ def autojump_threshold(self) -> float:
101
+ return self._autojump_threshold
102
+
103
+ @autojump_threshold.setter
104
+ def autojump_threshold(self, new_autojump_threshold: float) -> None:
105
+ self._autojump_threshold = float(new_autojump_threshold)
106
+ self._try_resync_autojump_threshold()
107
+
108
+ # runner.clock_autojump_threshold is an internal API that isn't easily
109
+ # usable by custom third-party Clock objects. If you need access to this
110
+ # functionality, let us know, and we'll figure out how to make a public
111
+ # API. Discussion:
112
+ #
113
+ # https://github.com/python-trio/trio/issues/1587
114
+ def _try_resync_autojump_threshold(self) -> None:
115
+ try:
116
+ runner = GLOBAL_RUN_CONTEXT.runner
117
+ if runner.is_guest:
118
+ runner.force_guest_tick_asap()
119
+ except AttributeError:
120
+ pass
121
+ else:
122
+ if runner.clock is self:
123
+ runner.clock_autojump_threshold = self._autojump_threshold
124
+
125
+ # Invoked by the run loop when runner.clock_autojump_threshold is
126
+ # exceeded.
127
+ def _autojump(self) -> None:
128
+ statistics = _core.current_statistics()
129
+ jump = statistics.seconds_to_next_deadline
130
+ if 0 < jump < inf:
131
+ self.jump(jump)
132
+
133
+ def _real_to_virtual(self, real: float) -> float:
134
+ real_offset = real - self._real_base
135
+ virtual_offset = self._rate * real_offset
136
+ return self._virtual_base + virtual_offset
137
+
138
+ def start_clock(self) -> None:
139
+ self._try_resync_autojump_threshold()
140
+
141
+ def current_time(self) -> float:
142
+ return self._real_to_virtual(self._real_clock())
143
+
144
+ def deadline_to_sleep_time(self, deadline: float) -> float:
145
+ virtual_timeout = deadline - self.current_time()
146
+ if virtual_timeout <= 0:
147
+ return 0
148
+ elif self._rate > 0:
149
+ return virtual_timeout / self._rate
150
+ else:
151
+ return 999999999
152
+
153
+ def jump(self, seconds: float) -> None:
154
+ """Manually advance the clock by the given number of seconds.
155
+
156
+ Args:
157
+ seconds (float): the number of seconds to jump the clock forward.
158
+
159
+ Raises:
160
+ ValueError: if you try to pass a negative value for ``seconds``.
161
+
162
+ """
163
+ if seconds < 0:
164
+ raise ValueError("time can't go backwards")
165
+ self._virtual_base += seconds