@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.
- package/bin/kgraph-launcher +15 -3
- package/lib/kgraph/scripts/build-bundle.sh +17 -4
- package/lib/site-packages/outcome/__init__.py +20 -0
- package/lib/site-packages/outcome/_impl.py +239 -0
- package/lib/site-packages/outcome/_util.py +33 -0
- package/lib/site-packages/outcome/_version.py +7 -0
- package/lib/site-packages/outcome/py.typed +0 -0
- package/lib/site-packages/outcome-1.3.0.post0.dist-info/INSTALLER +1 -0
- package/lib/site-packages/outcome-1.3.0.post0.dist-info/LICENSE +3 -0
- package/lib/site-packages/outcome-1.3.0.post0.dist-info/LICENSE.APACHE2 +202 -0
- package/lib/site-packages/outcome-1.3.0.post0.dist-info/LICENSE.MIT +20 -0
- package/lib/site-packages/outcome-1.3.0.post0.dist-info/METADATA +63 -0
- package/lib/site-packages/outcome-1.3.0.post0.dist-info/RECORD +13 -0
- package/lib/site-packages/outcome-1.3.0.post0.dist-info/WHEEL +6 -0
- package/lib/site-packages/outcome-1.3.0.post0.dist-info/top_level.txt +1 -0
- package/lib/site-packages/sniffio/__init__.py +17 -0
- package/lib/site-packages/sniffio/_impl.py +95 -0
- package/lib/site-packages/sniffio/_tests/__init__.py +0 -0
- package/lib/site-packages/sniffio/_tests/test_sniffio.py +84 -0
- package/lib/site-packages/sniffio/_version.py +3 -0
- package/lib/site-packages/sniffio/py.typed +0 -0
- package/lib/site-packages/sniffio-1.3.1.dist-info/INSTALLER +1 -0
- package/lib/site-packages/sniffio-1.3.1.dist-info/LICENSE +3 -0
- package/lib/site-packages/sniffio-1.3.1.dist-info/LICENSE.APACHE2 +202 -0
- package/lib/site-packages/sniffio-1.3.1.dist-info/LICENSE.MIT +20 -0
- package/lib/site-packages/sniffio-1.3.1.dist-info/METADATA +104 -0
- package/lib/site-packages/sniffio-1.3.1.dist-info/RECORD +14 -0
- package/lib/site-packages/sniffio-1.3.1.dist-info/WHEEL +5 -0
- package/lib/site-packages/sniffio-1.3.1.dist-info/top_level.txt +1 -0
- package/lib/site-packages/sortedcontainers/__init__.py +74 -0
- package/lib/site-packages/sortedcontainers/sorteddict.py +812 -0
- package/lib/site-packages/sortedcontainers/sortedlist.py +2646 -0
- package/lib/site-packages/sortedcontainers/sortedset.py +733 -0
- package/lib/site-packages/sortedcontainers-2.4.0.dist-info/INSTALLER +1 -0
- package/lib/site-packages/sortedcontainers-2.4.0.dist-info/LICENSE +13 -0
- package/lib/site-packages/sortedcontainers-2.4.0.dist-info/METADATA +264 -0
- package/lib/site-packages/sortedcontainers-2.4.0.dist-info/RECORD +10 -0
- package/lib/site-packages/sortedcontainers-2.4.0.dist-info/WHEEL +6 -0
- package/lib/site-packages/sortedcontainers-2.4.0.dist-info/top_level.txt +1 -0
- package/lib/site-packages/trio/__init__.py +133 -0
- package/lib/site-packages/trio/__main__.py +3 -0
- package/lib/site-packages/trio/_abc.py +714 -0
- package/lib/site-packages/trio/_channel.py +610 -0
- package/lib/site-packages/trio/_core/__init__.py +94 -0
- package/lib/site-packages/trio/_core/_asyncgens.py +243 -0
- package/lib/site-packages/trio/_core/_concat_tb.py +26 -0
- package/lib/site-packages/trio/_core/_entry_queue.py +223 -0
- package/lib/site-packages/trio/_core/_exceptions.py +169 -0
- package/lib/site-packages/trio/_core/_generated_instrumentation.py +50 -0
- package/lib/site-packages/trio/_core/_generated_io_epoll.py +98 -0
- package/lib/site-packages/trio/_core/_generated_io_kqueue.py +153 -0
- package/lib/site-packages/trio/_core/_generated_io_windows.py +204 -0
- package/lib/site-packages/trio/_core/_generated_run.py +269 -0
- package/lib/site-packages/trio/_core/_generated_windows_ffi.py +10 -0
- package/lib/site-packages/trio/_core/_instrumentation.py +117 -0
- package/lib/site-packages/trio/_core/_io_common.py +31 -0
- package/lib/site-packages/trio/_core/_io_epoll.py +385 -0
- package/lib/site-packages/trio/_core/_io_kqueue.py +292 -0
- package/lib/site-packages/trio/_core/_io_windows.py +1036 -0
- package/lib/site-packages/trio/_core/_ki.py +271 -0
- package/lib/site-packages/trio/_core/_local.py +104 -0
- package/lib/site-packages/trio/_core/_mock_clock.py +165 -0
- package/lib/site-packages/trio/_core/_parking_lot.py +317 -0
- package/lib/site-packages/trio/_core/_run.py +3148 -0
- package/lib/site-packages/trio/_core/_run_context.py +15 -0
- package/lib/site-packages/trio/_core/_tests/__init__.py +0 -0
- package/lib/site-packages/trio/_core/_tests/test_asyncgen.py +339 -0
- package/lib/site-packages/trio/_core/_tests/test_cancelled.py +222 -0
- package/lib/site-packages/trio/_core/_tests/test_exceptiongroup_gc.py +103 -0
- package/lib/site-packages/trio/_core/_tests/test_guest_mode.py +755 -0
- package/lib/site-packages/trio/_core/_tests/test_instrumentation.py +315 -0
- package/lib/site-packages/trio/_core/_tests/test_io.py +522 -0
- package/lib/site-packages/trio/_core/_tests/test_ki.py +703 -0
- package/lib/site-packages/trio/_core/_tests/test_local.py +118 -0
- package/lib/site-packages/trio/_core/_tests/test_mock_clock.py +193 -0
- package/lib/site-packages/trio/_core/_tests/test_parking_lot.py +389 -0
- package/lib/site-packages/trio/_core/_tests/test_run.py +3024 -0
- package/lib/site-packages/trio/_core/_tests/test_thread_cache.py +227 -0
- package/lib/site-packages/trio/_core/_tests/test_tutil.py +13 -0
- package/lib/site-packages/trio/_core/_tests/test_unbounded_queue.py +154 -0
- package/lib/site-packages/trio/_core/_tests/test_windows.py +305 -0
- package/lib/site-packages/trio/_core/_tests/tutil.py +117 -0
- package/lib/site-packages/trio/_core/_tests/type_tests/nursery_start.py +79 -0
- package/lib/site-packages/trio/_core/_tests/type_tests/run.py +51 -0
- package/lib/site-packages/trio/_core/_thread_cache.py +317 -0
- package/lib/site-packages/trio/_core/_traps.py +318 -0
- package/lib/site-packages/trio/_core/_unbounded_queue.py +163 -0
- package/lib/site-packages/trio/_core/_wakeup_socketpair.py +75 -0
- package/lib/site-packages/trio/_core/_windows_cffi.py +313 -0
- package/lib/site-packages/trio/_deprecate.py +171 -0
- package/lib/site-packages/trio/_dtls.py +1380 -0
- package/lib/site-packages/trio/_file_io.py +513 -0
- package/lib/site-packages/trio/_highlevel_generic.py +125 -0
- package/lib/site-packages/trio/_highlevel_open_tcp_listeners.py +251 -0
- package/lib/site-packages/trio/_highlevel_open_tcp_stream.py +397 -0
- package/lib/site-packages/trio/_highlevel_open_unix_stream.py +65 -0
- package/lib/site-packages/trio/_highlevel_serve_listeners.py +148 -0
- package/lib/site-packages/trio/_highlevel_socket.py +423 -0
- package/lib/site-packages/trio/_highlevel_ssl_helpers.py +180 -0
- package/lib/site-packages/trio/_path.py +289 -0
- package/lib/site-packages/trio/_repl.py +159 -0
- package/lib/site-packages/trio/_signals.py +185 -0
- package/lib/site-packages/trio/_socket.py +1326 -0
- package/lib/site-packages/trio/_ssl.py +964 -0
- package/lib/site-packages/trio/_subprocess.py +1178 -0
- package/lib/site-packages/trio/_subprocess_platform/__init__.py +123 -0
- package/lib/site-packages/trio/_subprocess_platform/kqueue.py +48 -0
- package/lib/site-packages/trio/_subprocess_platform/waitid.py +113 -0
- package/lib/site-packages/trio/_subprocess_platform/windows.py +11 -0
- package/lib/site-packages/trio/_sync.py +908 -0
- package/lib/site-packages/trio/_tests/__init__.py +0 -0
- package/lib/site-packages/trio/_tests/astrill-codesigning-cert.cer +0 -0
- package/lib/site-packages/trio/_tests/check_type_completeness.py +247 -0
- package/lib/site-packages/trio/_tests/module_with_deprecations.py +22 -0
- package/lib/site-packages/trio/_tests/pytest_plugin.py +54 -0
- package/lib/site-packages/trio/_tests/test_abc.py +72 -0
- package/lib/site-packages/trio/_tests/test_channel.py +750 -0
- package/lib/site-packages/trio/_tests/test_contextvars.py +56 -0
- package/lib/site-packages/trio/_tests/test_deprecate.py +277 -0
- package/lib/site-packages/trio/_tests/test_deprecate_strict_exception_groups_false.py +64 -0
- package/lib/site-packages/trio/_tests/test_dtls.py +950 -0
- package/lib/site-packages/trio/_tests/test_exports.py +626 -0
- package/lib/site-packages/trio/_tests/test_fakenet.py +317 -0
- package/lib/site-packages/trio/_tests/test_file_io.py +269 -0
- package/lib/site-packages/trio/_tests/test_highlevel_generic.py +98 -0
- package/lib/site-packages/trio/_tests/test_highlevel_open_tcp_listeners.py +419 -0
- package/lib/site-packages/trio/_tests/test_highlevel_open_tcp_stream.py +693 -0
- package/lib/site-packages/trio/_tests/test_highlevel_open_unix_stream.py +86 -0
- package/lib/site-packages/trio/_tests/test_highlevel_serve_listeners.py +186 -0
- package/lib/site-packages/trio/_tests/test_highlevel_socket.py +336 -0
- package/lib/site-packages/trio/_tests/test_highlevel_ssl_helpers.py +169 -0
- package/lib/site-packages/trio/_tests/test_path.py +279 -0
- package/lib/site-packages/trio/_tests/test_repl.py +428 -0
- package/lib/site-packages/trio/_tests/test_scheduler_determinism.py +47 -0
- package/lib/site-packages/trio/_tests/test_signals.py +186 -0
- package/lib/site-packages/trio/_tests/test_socket.py +1253 -0
- package/lib/site-packages/trio/_tests/test_ssl.py +1371 -0
- package/lib/site-packages/trio/_tests/test_subprocess.py +767 -0
- package/lib/site-packages/trio/_tests/test_sync.py +735 -0
- package/lib/site-packages/trio/_tests/test_testing.py +682 -0
- package/lib/site-packages/trio/_tests/test_testing_raisesgroup.py +1128 -0
- package/lib/site-packages/trio/_tests/test_threads.py +1173 -0
- package/lib/site-packages/trio/_tests/test_timeouts.py +281 -0
- package/lib/site-packages/trio/_tests/test_tracing.py +88 -0
- package/lib/site-packages/trio/_tests/test_trio.py +8 -0
- package/lib/site-packages/trio/_tests/test_unix_pipes.py +288 -0
- package/lib/site-packages/trio/_tests/test_util.py +349 -0
- package/lib/site-packages/trio/_tests/test_wait_for_object.py +225 -0
- package/lib/site-packages/trio/_tests/test_windows_pipes.py +112 -0
- package/lib/site-packages/trio/_tests/tools/__init__.py +0 -0
- package/lib/site-packages/trio/_tests/tools/test_gen_exports.py +179 -0
- package/lib/site-packages/trio/_tests/tools/test_mypy_annotate.py +140 -0
- package/lib/site-packages/trio/_tests/tools/test_sync_requirements.py +80 -0
- package/lib/site-packages/trio/_tests/type_tests/check_wraps.py +9 -0
- package/lib/site-packages/trio/_tests/type_tests/open_memory_channel.py +4 -0
- package/lib/site-packages/trio/_tests/type_tests/path.py +140 -0
- package/lib/site-packages/trio/_tests/type_tests/subprocesses.py +23 -0
- package/lib/site-packages/trio/_tests/type_tests/task_status.py +29 -0
- package/lib/site-packages/trio/_threads.py +610 -0
- package/lib/site-packages/trio/_timeouts.py +197 -0
- package/lib/site-packages/trio/_tools/__init__.py +0 -0
- package/lib/site-packages/trio/_tools/gen_exports.py +401 -0
- package/lib/site-packages/trio/_tools/mypy_annotate.py +126 -0
- package/lib/site-packages/trio/_tools/sync_requirements.py +98 -0
- package/lib/site-packages/trio/_tools/windows_ffi_build.py +220 -0
- package/lib/site-packages/trio/_unix_pipes.py +197 -0
- package/lib/site-packages/trio/_util.py +385 -0
- package/lib/site-packages/trio/_version.py +3 -0
- package/lib/site-packages/trio/_wait_for_object.py +67 -0
- package/lib/site-packages/trio/_windows_pipes.py +144 -0
- package/lib/site-packages/trio/abc.py +23 -0
- package/lib/site-packages/trio/from_thread.py +13 -0
- package/lib/site-packages/trio/lowlevel.py +95 -0
- package/lib/site-packages/trio/py.typed +0 -0
- package/lib/site-packages/trio/socket.py +602 -0
- package/lib/site-packages/trio/testing/__init__.py +58 -0
- package/lib/site-packages/trio/testing/_check_streams.py +570 -0
- package/lib/site-packages/trio/testing/_checkpoints.py +69 -0
- package/lib/site-packages/trio/testing/_fake_net.py +584 -0
- package/lib/site-packages/trio/testing/_memory_streams.py +633 -0
- package/lib/site-packages/trio/testing/_network.py +36 -0
- package/lib/site-packages/trio/testing/_raises_group.py +1015 -0
- package/lib/site-packages/trio/testing/_sequencer.py +87 -0
- package/lib/site-packages/trio/testing/_trio_test.py +50 -0
- package/lib/site-packages/trio/to_thread.py +4 -0
- package/lib/site-packages/trio-0.33.0.dist-info/INSTALLER +1 -0
- package/lib/site-packages/trio-0.33.0.dist-info/METADATA +186 -0
- package/lib/site-packages/trio-0.33.0.dist-info/RECORD +156 -0
- package/lib/site-packages/trio-0.33.0.dist-info/REQUESTED +0 -0
- package/lib/site-packages/trio-0.33.0.dist-info/WHEEL +5 -0
- package/lib/site-packages/trio-0.33.0.dist-info/entry_points.txt +2 -0
- package/lib/site-packages/trio-0.33.0.dist-info/licenses/LICENSE +3 -0
- package/lib/site-packages/trio-0.33.0.dist-info/licenses/LICENSE.APACHE2 +202 -0
- package/lib/site-packages/trio-0.33.0.dist-info/licenses/LICENSE.MIT +22 -0
- package/lib/site-packages/trio-0.33.0.dist-info/top_level.txt +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import math
|
|
4
|
+
import sys
|
|
5
|
+
from contextlib import contextmanager
|
|
6
|
+
from typing import TYPE_CHECKING, NoReturn
|
|
7
|
+
|
|
8
|
+
import trio
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from collections.abc import Generator
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def move_on_at(deadline: float, *, shield: bool = False) -> trio.CancelScope:
|
|
15
|
+
"""Use as a context manager to create a cancel scope with the given
|
|
16
|
+
absolute deadline.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
deadline (float): The deadline.
|
|
20
|
+
shield (bool): Initial value for the `~trio.CancelScope.shield` attribute
|
|
21
|
+
of the newly created cancel scope.
|
|
22
|
+
|
|
23
|
+
Raises:
|
|
24
|
+
ValueError: if deadline is NaN.
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
# CancelScope validates that deadline isn't math.nan
|
|
28
|
+
return trio.CancelScope(deadline=deadline, shield=shield)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def move_on_after(
|
|
32
|
+
seconds: float,
|
|
33
|
+
*,
|
|
34
|
+
shield: bool = False,
|
|
35
|
+
) -> trio.CancelScope:
|
|
36
|
+
"""Use as a context manager to create a cancel scope whose deadline is
|
|
37
|
+
set to now + *seconds*.
|
|
38
|
+
|
|
39
|
+
The deadline of the cancel scope is calculated upon entering.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
seconds (float): The timeout.
|
|
43
|
+
shield (bool): Initial value for the `~trio.CancelScope.shield` attribute
|
|
44
|
+
of the newly created cancel scope.
|
|
45
|
+
|
|
46
|
+
Raises:
|
|
47
|
+
ValueError: if ``seconds`` is less than zero or NaN.
|
|
48
|
+
|
|
49
|
+
"""
|
|
50
|
+
# duplicate validation logic to have the correct parameter name
|
|
51
|
+
if seconds < 0:
|
|
52
|
+
raise ValueError("`seconds` must be non-negative")
|
|
53
|
+
if math.isnan(seconds):
|
|
54
|
+
raise ValueError("`seconds` must not be NaN")
|
|
55
|
+
return trio.CancelScope(
|
|
56
|
+
shield=shield,
|
|
57
|
+
relative_deadline=seconds,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
async def sleep_forever() -> NoReturn:
|
|
62
|
+
"""Pause execution of the current task forever (or until cancelled).
|
|
63
|
+
|
|
64
|
+
Equivalent to calling ``await sleep(math.inf)``, except that if manually
|
|
65
|
+
rescheduled this will raise a `RuntimeError`.
|
|
66
|
+
|
|
67
|
+
Raises:
|
|
68
|
+
RuntimeError: if rescheduled
|
|
69
|
+
|
|
70
|
+
"""
|
|
71
|
+
await trio.lowlevel.wait_task_rescheduled(lambda _: trio.lowlevel.Abort.SUCCEEDED)
|
|
72
|
+
raise RuntimeError("Should never have been rescheduled!")
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
async def sleep_until(deadline: float) -> None:
|
|
76
|
+
"""Pause execution of the current task until the given time.
|
|
77
|
+
|
|
78
|
+
The difference between :func:`sleep` and :func:`sleep_until` is that the
|
|
79
|
+
former takes a relative time and the latter takes an absolute time
|
|
80
|
+
according to Trio's internal clock (as returned by :func:`current_time`).
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
deadline (float): The time at which we should wake up again. May be in
|
|
84
|
+
the past, in which case this function executes a checkpoint but
|
|
85
|
+
does not block.
|
|
86
|
+
|
|
87
|
+
Raises:
|
|
88
|
+
ValueError: if deadline is NaN.
|
|
89
|
+
|
|
90
|
+
"""
|
|
91
|
+
with move_on_at(deadline):
|
|
92
|
+
await sleep_forever()
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
async def sleep(seconds: float) -> None:
|
|
96
|
+
"""Pause execution of the current task for the given number of seconds.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
seconds (float): The number of seconds to sleep. May be zero to
|
|
100
|
+
insert a checkpoint without actually blocking.
|
|
101
|
+
|
|
102
|
+
Raises:
|
|
103
|
+
ValueError: if *seconds* is negative or NaN.
|
|
104
|
+
|
|
105
|
+
"""
|
|
106
|
+
if seconds < 0:
|
|
107
|
+
raise ValueError("`seconds` must be non-negative")
|
|
108
|
+
if seconds == 0:
|
|
109
|
+
await trio.lowlevel.checkpoint()
|
|
110
|
+
else:
|
|
111
|
+
await sleep_until(trio.current_time() + seconds)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class TooSlowError(Exception):
|
|
115
|
+
"""Raised by :func:`fail_after` and :func:`fail_at` if the timeout
|
|
116
|
+
expires.
|
|
117
|
+
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@contextmanager
|
|
122
|
+
def fail_at(
|
|
123
|
+
deadline: float,
|
|
124
|
+
*,
|
|
125
|
+
shield: bool = False,
|
|
126
|
+
) -> Generator[trio.CancelScope, None, None]:
|
|
127
|
+
"""Creates a cancel scope with the given deadline, and raises an error if it
|
|
128
|
+
is actually cancelled.
|
|
129
|
+
|
|
130
|
+
This function and :func:`move_on_at` are similar in that both create a
|
|
131
|
+
cancel scope with a given absolute deadline, and if the deadline expires
|
|
132
|
+
then both will cause :exc:`Cancelled` to be raised within the scope. The
|
|
133
|
+
difference is that when the :exc:`Cancelled` exception reaches
|
|
134
|
+
:func:`move_on_at`, it's caught and discarded. When it reaches
|
|
135
|
+
:func:`fail_at`, then it's caught and :exc:`TooSlowError` is raised in its
|
|
136
|
+
place.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
deadline (float): The deadline.
|
|
140
|
+
shield (bool): Initial value for the `~trio.CancelScope.shield` attribute
|
|
141
|
+
of the newly created cancel scope.
|
|
142
|
+
|
|
143
|
+
Raises:
|
|
144
|
+
TooSlowError: if a :exc:`Cancelled` exception is raised in this scope
|
|
145
|
+
and caught by the context manager.
|
|
146
|
+
ValueError: if deadline is NaN.
|
|
147
|
+
|
|
148
|
+
"""
|
|
149
|
+
with move_on_at(deadline, shield=shield) as scope:
|
|
150
|
+
yield scope
|
|
151
|
+
if scope.cancelled_caught:
|
|
152
|
+
raise TooSlowError
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
@contextmanager
|
|
156
|
+
def fail_after(
|
|
157
|
+
seconds: float,
|
|
158
|
+
*,
|
|
159
|
+
shield: bool = False,
|
|
160
|
+
) -> Generator[trio.CancelScope, None, None]:
|
|
161
|
+
"""Creates a cancel scope with the given timeout, and raises an error if
|
|
162
|
+
it is actually cancelled.
|
|
163
|
+
|
|
164
|
+
This function and :func:`move_on_after` are similar in that both create a
|
|
165
|
+
cancel scope with a given timeout, and if the timeout expires then both
|
|
166
|
+
will cause :exc:`Cancelled` to be raised within the scope. The difference
|
|
167
|
+
is that when the :exc:`Cancelled` exception reaches :func:`move_on_after`,
|
|
168
|
+
it's caught and discarded. When it reaches :func:`fail_after`, then it's
|
|
169
|
+
caught and :exc:`TooSlowError` is raised in its place.
|
|
170
|
+
|
|
171
|
+
The deadline of the cancel scope is calculated upon entering.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
seconds (float): The timeout.
|
|
175
|
+
shield (bool): Initial value for the `~trio.CancelScope.shield` attribute
|
|
176
|
+
of the newly created cancel scope.
|
|
177
|
+
|
|
178
|
+
Raises:
|
|
179
|
+
TooSlowError: if a :exc:`Cancelled` exception is raised in this scope
|
|
180
|
+
and caught by the context manager.
|
|
181
|
+
ValueError: if *seconds* is less than zero or NaN.
|
|
182
|
+
|
|
183
|
+
"""
|
|
184
|
+
with move_on_after(seconds, shield=shield) as scope:
|
|
185
|
+
yield scope
|
|
186
|
+
if scope.cancelled_caught:
|
|
187
|
+
raise TooSlowError
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
# Users don't need to know that fail_at & fail_after wraps move_on_at and move_on_after
|
|
191
|
+
# and there is no functional difference. So we replace the return value when generating
|
|
192
|
+
# documentation.
|
|
193
|
+
if "sphinx.ext.autodoc" in sys.modules:
|
|
194
|
+
import inspect
|
|
195
|
+
|
|
196
|
+
for c in (fail_at, fail_after):
|
|
197
|
+
c.__signature__ = inspect.Signature.from_callable(c).replace(return_annotation=trio.CancelScope) # type: ignore[union-attr]
|
|
File without changes
|
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
#! /usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Code generation script for class methods
|
|
4
|
+
to be exported as public API
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import argparse
|
|
10
|
+
import ast
|
|
11
|
+
import os
|
|
12
|
+
import subprocess
|
|
13
|
+
import sys
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from textwrap import indent
|
|
16
|
+
from typing import TYPE_CHECKING, TypeGuard
|
|
17
|
+
|
|
18
|
+
import attrs
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from collections.abc import Iterable, Iterator
|
|
22
|
+
|
|
23
|
+
# keep these imports up to date with conditional imports in test_gen_exports
|
|
24
|
+
# isort: split
|
|
25
|
+
import astor
|
|
26
|
+
|
|
27
|
+
PREFIX = "_generated"
|
|
28
|
+
|
|
29
|
+
HEADER = """# ***********************************************************
|
|
30
|
+
# ******* WARNING: AUTOGENERATED! ALL EDITS WILL BE LOST ******
|
|
31
|
+
# *************************************************************
|
|
32
|
+
from __future__ import annotations
|
|
33
|
+
|
|
34
|
+
import sys
|
|
35
|
+
|
|
36
|
+
from ._ki import enable_ki_protection
|
|
37
|
+
from ._run import GLOBAL_RUN_CONTEXT
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
TEMPLATE = """try:
|
|
41
|
+
return{}GLOBAL_RUN_CONTEXT.{}.{}
|
|
42
|
+
except AttributeError:
|
|
43
|
+
raise RuntimeError("must be called from async context") from None
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@attrs.define
|
|
48
|
+
class File:
|
|
49
|
+
path: Path
|
|
50
|
+
modname: str
|
|
51
|
+
platform: str = attrs.field(default="", kw_only=True)
|
|
52
|
+
imports: str = attrs.field(default="", kw_only=True)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def is_function(node: ast.AST) -> TypeGuard[ast.FunctionDef | ast.AsyncFunctionDef]:
|
|
56
|
+
"""Check if the AST node is either a function
|
|
57
|
+
or an async function
|
|
58
|
+
"""
|
|
59
|
+
return isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef))
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def is_public(node: ast.AST) -> TypeGuard[ast.FunctionDef | ast.AsyncFunctionDef]:
|
|
63
|
+
"""Check if the AST node has a _public decorator"""
|
|
64
|
+
if is_function(node):
|
|
65
|
+
for decorator in node.decorator_list:
|
|
66
|
+
if isinstance(decorator, ast.Name) and decorator.id == "_public":
|
|
67
|
+
return True
|
|
68
|
+
return False
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def get_public_methods(
|
|
72
|
+
tree: ast.AST,
|
|
73
|
+
) -> Iterator[ast.FunctionDef | ast.AsyncFunctionDef]:
|
|
74
|
+
"""Return a list of methods marked as public.
|
|
75
|
+
The function walks the given tree and extracts
|
|
76
|
+
all objects that are functions which are marked
|
|
77
|
+
public.
|
|
78
|
+
"""
|
|
79
|
+
for node in ast.walk(tree):
|
|
80
|
+
if is_public(node):
|
|
81
|
+
yield node
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def create_passthrough_args(funcdef: ast.FunctionDef | ast.AsyncFunctionDef) -> str:
|
|
85
|
+
"""Given a function definition, create a string that represents taking all
|
|
86
|
+
the arguments from the function, and passing them through to another
|
|
87
|
+
invocation of the same function.
|
|
88
|
+
|
|
89
|
+
Example input: ast.parse("def f(a, *, b): ...")
|
|
90
|
+
Example output: "(a, b=b)"
|
|
91
|
+
"""
|
|
92
|
+
call_args = [arg.arg for arg in funcdef.args.args]
|
|
93
|
+
if funcdef.args.vararg:
|
|
94
|
+
call_args.append("*" + funcdef.args.vararg.arg)
|
|
95
|
+
for arg in funcdef.args.kwonlyargs:
|
|
96
|
+
call_args.append(arg.arg + "=" + arg.arg) # noqa: PERF401 # clarity
|
|
97
|
+
if funcdef.args.kwarg:
|
|
98
|
+
call_args.append("**" + funcdef.args.kwarg.arg)
|
|
99
|
+
return "({})".format(", ".join(call_args))
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def run_black(file: File, source: str) -> tuple[bool, str]:
|
|
103
|
+
"""Run black on the specified file.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
Tuple of success and result string.
|
|
107
|
+
ex.:
|
|
108
|
+
(False, "Failed to run black!\nerror: cannot format ...")
|
|
109
|
+
(True, "<formatted source>")
|
|
110
|
+
|
|
111
|
+
Raises:
|
|
112
|
+
ImportError: If black is not installed.
|
|
113
|
+
"""
|
|
114
|
+
# imported to check that `subprocess` calls will succeed
|
|
115
|
+
import black # noqa: F401
|
|
116
|
+
|
|
117
|
+
# Black has an undocumented API, but it doesn't easily allow reading configuration from
|
|
118
|
+
# pyproject.toml, and simultaneously pass in / receive the code as a string.
|
|
119
|
+
# https://github.com/psf/black/issues/779
|
|
120
|
+
result = subprocess.run(
|
|
121
|
+
# "-" as a filename = use stdin, return on stdout.
|
|
122
|
+
[sys.executable, "-m", "black", "--stdin-filename", file.path, "-"],
|
|
123
|
+
input=source,
|
|
124
|
+
capture_output=True,
|
|
125
|
+
encoding="utf8",
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
if result.returncode != 0:
|
|
129
|
+
return False, f"Failed to run black!\n{result.stderr}"
|
|
130
|
+
return True, result.stdout
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def run_ruff(file: File, source: str) -> tuple[bool, str]:
|
|
134
|
+
"""Run ruff on the specified file.
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
Tuple of success and result string.
|
|
138
|
+
ex.:
|
|
139
|
+
(False, "Failed to run ruff!\nerror: Failed to parse ...")
|
|
140
|
+
(True, "<formatted source>")
|
|
141
|
+
|
|
142
|
+
Raises:
|
|
143
|
+
ImportError: If ruff is not installed.
|
|
144
|
+
"""
|
|
145
|
+
# imported to check that `subprocess` calls will succeed
|
|
146
|
+
import ruff # noqa: F401
|
|
147
|
+
|
|
148
|
+
result = subprocess.run(
|
|
149
|
+
# "-" as a filename = use stdin, return on stdout.
|
|
150
|
+
[
|
|
151
|
+
sys.executable,
|
|
152
|
+
"-m",
|
|
153
|
+
"ruff",
|
|
154
|
+
"check",
|
|
155
|
+
"--fix",
|
|
156
|
+
"--unsafe-fixes",
|
|
157
|
+
"--stdin-filename",
|
|
158
|
+
file.path,
|
|
159
|
+
"-",
|
|
160
|
+
],
|
|
161
|
+
input=source,
|
|
162
|
+
capture_output=True,
|
|
163
|
+
encoding="utf8",
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
if result.returncode != 0:
|
|
167
|
+
return False, f"Failed to run ruff!\n{result.stderr}"
|
|
168
|
+
return True, result.stdout
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def run_linters(file: File, source: str) -> str:
|
|
172
|
+
"""Format the specified file using black and ruff.
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
Formatted source code.
|
|
176
|
+
|
|
177
|
+
Raises:
|
|
178
|
+
ImportError: If either is not installed.
|
|
179
|
+
SystemExit: If either failed.
|
|
180
|
+
"""
|
|
181
|
+
|
|
182
|
+
for fn in (run_black, run_ruff):
|
|
183
|
+
success, source = fn(file, source)
|
|
184
|
+
if not success:
|
|
185
|
+
print(source)
|
|
186
|
+
sys.exit(1)
|
|
187
|
+
|
|
188
|
+
return source
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def gen_public_wrappers_source(file: File) -> str:
|
|
192
|
+
"""Scan the given .py file for @_public decorators, and generate wrapper
|
|
193
|
+
functions.
|
|
194
|
+
|
|
195
|
+
"""
|
|
196
|
+
header = [HEADER]
|
|
197
|
+
header.append(file.imports)
|
|
198
|
+
if file.platform:
|
|
199
|
+
# Simple checks to avoid repeating imports. If this messes up, type checkers/tests will
|
|
200
|
+
# just give errors.
|
|
201
|
+
if "TYPE_CHECKING" not in file.imports:
|
|
202
|
+
header.append("from typing import TYPE_CHECKING\n")
|
|
203
|
+
if "import sys" not in file.imports: # pragma: no cover
|
|
204
|
+
header.append("import sys\n")
|
|
205
|
+
header.append(
|
|
206
|
+
f'\nassert not TYPE_CHECKING or sys.platform=="{file.platform}"\n',
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
generated = ["".join(header)]
|
|
210
|
+
|
|
211
|
+
source = astor.code_to_ast.parse_file(file.path)
|
|
212
|
+
method_names = []
|
|
213
|
+
for method in get_public_methods(source):
|
|
214
|
+
# Remove self from arguments
|
|
215
|
+
assert method.args.args[0].arg == "self"
|
|
216
|
+
del method.args.args[0]
|
|
217
|
+
method_names.append(method.name)
|
|
218
|
+
|
|
219
|
+
for dec in method.decorator_list: # pragma: no cover
|
|
220
|
+
if isinstance(dec, ast.Name) and dec.id == "contextmanager":
|
|
221
|
+
is_cm = True
|
|
222
|
+
break
|
|
223
|
+
else:
|
|
224
|
+
is_cm = False
|
|
225
|
+
|
|
226
|
+
# Remove decorators
|
|
227
|
+
method.decorator_list = [ast.Name("enable_ki_protection")]
|
|
228
|
+
|
|
229
|
+
# Create pass through arguments
|
|
230
|
+
new_args = create_passthrough_args(method)
|
|
231
|
+
|
|
232
|
+
# Remove method body without the docstring
|
|
233
|
+
if ast.get_docstring(method) is None:
|
|
234
|
+
del method.body[:]
|
|
235
|
+
else:
|
|
236
|
+
# The first entry is always the docstring
|
|
237
|
+
del method.body[1:]
|
|
238
|
+
|
|
239
|
+
# Create the function definition including the body
|
|
240
|
+
func = astor.to_source(method, indent_with=" " * 4)
|
|
241
|
+
|
|
242
|
+
if is_cm: # pragma: no cover
|
|
243
|
+
func = func.replace("->Iterator", "->AbstractContextManager")
|
|
244
|
+
|
|
245
|
+
# Create export function body
|
|
246
|
+
template = TEMPLATE.format(
|
|
247
|
+
" await " if isinstance(method, ast.AsyncFunctionDef) else " ",
|
|
248
|
+
file.modname,
|
|
249
|
+
method.name + new_args,
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
# Assemble function definition arguments and body
|
|
253
|
+
snippet = func + indent(template, " " * 4)
|
|
254
|
+
|
|
255
|
+
# Append the snippet to the corresponding module
|
|
256
|
+
generated.append(snippet)
|
|
257
|
+
|
|
258
|
+
method_names.sort()
|
|
259
|
+
# Insert after the header, before function definitions
|
|
260
|
+
generated.insert(1, f"__all__ = {method_names!r}")
|
|
261
|
+
return "\n\n".join(generated)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def matches_disk_files(new_files: dict[str, str]) -> bool:
|
|
265
|
+
for new_path, new_source in new_files.items():
|
|
266
|
+
if not os.path.exists(new_path):
|
|
267
|
+
return False
|
|
268
|
+
old_source = Path(new_path).read_text(encoding="utf-8")
|
|
269
|
+
if old_source != new_source:
|
|
270
|
+
return False
|
|
271
|
+
return True
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def process(files: Iterable[File], *, do_test: bool) -> None:
|
|
275
|
+
new_files = {}
|
|
276
|
+
for file in files:
|
|
277
|
+
print("Scanning:", file.path)
|
|
278
|
+
new_source = gen_public_wrappers_source(file)
|
|
279
|
+
new_source = run_linters(file, new_source)
|
|
280
|
+
dirname, basename = os.path.split(file.path)
|
|
281
|
+
new_path = os.path.join(dirname, PREFIX + basename)
|
|
282
|
+
new_files[new_path] = new_source
|
|
283
|
+
matches_disk = matches_disk_files(new_files)
|
|
284
|
+
if do_test:
|
|
285
|
+
if not matches_disk:
|
|
286
|
+
print("Generated sources are outdated. Please regenerate.")
|
|
287
|
+
sys.exit(1)
|
|
288
|
+
else:
|
|
289
|
+
print("Generated sources are up to date.")
|
|
290
|
+
else:
|
|
291
|
+
for new_path, new_source in new_files.items():
|
|
292
|
+
Path(new_path).write_text(new_source, encoding="utf-8", newline="\n")
|
|
293
|
+
print("Regenerated sources successfully.")
|
|
294
|
+
if not matches_disk: # TODO: test this branch
|
|
295
|
+
# With pre-commit integration, show that we edited files.
|
|
296
|
+
sys.exit(1)
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
# This is in fact run in CI, but only in the formatting check job, which
|
|
300
|
+
# doesn't collect coverage.
|
|
301
|
+
def main() -> None: # pragma: no cover
|
|
302
|
+
parser = argparse.ArgumentParser(
|
|
303
|
+
description="Generate python code for public api wrappers",
|
|
304
|
+
)
|
|
305
|
+
parser.add_argument(
|
|
306
|
+
"--test",
|
|
307
|
+
"-t",
|
|
308
|
+
action="store_true",
|
|
309
|
+
help="test if code is still up to date",
|
|
310
|
+
)
|
|
311
|
+
parsed_args = parser.parse_args()
|
|
312
|
+
|
|
313
|
+
source_root = Path.cwd()
|
|
314
|
+
# Double-check we found the right directory
|
|
315
|
+
assert (source_root / "LICENSE").exists()
|
|
316
|
+
core = source_root / "src/trio/_core"
|
|
317
|
+
to_wrap = [
|
|
318
|
+
File(core / "_run.py", "runner", imports=IMPORTS_RUN),
|
|
319
|
+
File(
|
|
320
|
+
core / "_instrumentation.py",
|
|
321
|
+
"runner.instruments",
|
|
322
|
+
imports=IMPORTS_INSTRUMENT,
|
|
323
|
+
),
|
|
324
|
+
File(
|
|
325
|
+
core / "_io_windows.py",
|
|
326
|
+
"runner.io_manager",
|
|
327
|
+
platform="win32",
|
|
328
|
+
imports=IMPORTS_WINDOWS,
|
|
329
|
+
),
|
|
330
|
+
File(
|
|
331
|
+
core / "_io_epoll.py",
|
|
332
|
+
"runner.io_manager",
|
|
333
|
+
platform="linux",
|
|
334
|
+
imports=IMPORTS_EPOLL,
|
|
335
|
+
),
|
|
336
|
+
File(
|
|
337
|
+
core / "_io_kqueue.py",
|
|
338
|
+
"runner.io_manager",
|
|
339
|
+
platform="darwin",
|
|
340
|
+
imports=IMPORTS_KQUEUE,
|
|
341
|
+
),
|
|
342
|
+
]
|
|
343
|
+
|
|
344
|
+
process(to_wrap, do_test=parsed_args.test)
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
IMPORTS_RUN = """\
|
|
348
|
+
from collections.abc import Awaitable, Callable
|
|
349
|
+
from typing import Any, TYPE_CHECKING
|
|
350
|
+
|
|
351
|
+
import outcome
|
|
352
|
+
import contextvars
|
|
353
|
+
|
|
354
|
+
from ._run import _NO_SEND, RunStatistics, Task
|
|
355
|
+
from ._entry_queue import TrioToken
|
|
356
|
+
from .._abc import Clock
|
|
357
|
+
|
|
358
|
+
if TYPE_CHECKING:
|
|
359
|
+
from typing_extensions import Unpack
|
|
360
|
+
from ._run import PosArgT
|
|
361
|
+
"""
|
|
362
|
+
IMPORTS_INSTRUMENT = """\
|
|
363
|
+
from ._instrumentation import Instrument
|
|
364
|
+
"""
|
|
365
|
+
|
|
366
|
+
IMPORTS_EPOLL = """\
|
|
367
|
+
from typing import TYPE_CHECKING
|
|
368
|
+
|
|
369
|
+
if TYPE_CHECKING:
|
|
370
|
+
from .._file_io import _HasFileNo
|
|
371
|
+
"""
|
|
372
|
+
|
|
373
|
+
IMPORTS_KQUEUE = """\
|
|
374
|
+
from typing import TYPE_CHECKING
|
|
375
|
+
|
|
376
|
+
if TYPE_CHECKING:
|
|
377
|
+
import select
|
|
378
|
+
from collections.abc import Callable
|
|
379
|
+
from contextlib import AbstractContextManager
|
|
380
|
+
|
|
381
|
+
from .. import _core
|
|
382
|
+
from .._file_io import _HasFileNo
|
|
383
|
+
from ._traps import Abort, RaiseCancelT
|
|
384
|
+
"""
|
|
385
|
+
|
|
386
|
+
IMPORTS_WINDOWS = """\
|
|
387
|
+
from typing import TYPE_CHECKING
|
|
388
|
+
|
|
389
|
+
if TYPE_CHECKING:
|
|
390
|
+
from contextlib import AbstractContextManager
|
|
391
|
+
|
|
392
|
+
from typing_extensions import Buffer
|
|
393
|
+
|
|
394
|
+
from .._file_io import _HasFileNo
|
|
395
|
+
from ._unbounded_queue import UnboundedQueue
|
|
396
|
+
from ._windows_cffi import Handle, CData
|
|
397
|
+
"""
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
if __name__ == "__main__":
|
|
401
|
+
main()
|