@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,513 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import io
|
|
4
|
+
from collections.abc import Callable, Iterable
|
|
5
|
+
from functools import partial
|
|
6
|
+
from typing import (
|
|
7
|
+
IO,
|
|
8
|
+
TYPE_CHECKING,
|
|
9
|
+
Any,
|
|
10
|
+
AnyStr,
|
|
11
|
+
BinaryIO,
|
|
12
|
+
Generic,
|
|
13
|
+
Literal,
|
|
14
|
+
TypeVar,
|
|
15
|
+
Union,
|
|
16
|
+
overload,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
import trio
|
|
20
|
+
|
|
21
|
+
from ._util import async_wraps
|
|
22
|
+
from .abc import AsyncResource
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from _typeshed import (
|
|
26
|
+
OpenBinaryMode,
|
|
27
|
+
OpenBinaryModeReading,
|
|
28
|
+
OpenBinaryModeUpdating,
|
|
29
|
+
OpenBinaryModeWriting,
|
|
30
|
+
OpenTextMode,
|
|
31
|
+
StrOrBytesPath,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
from ._sync import CapacityLimiter
|
|
35
|
+
|
|
36
|
+
# This list is also in the docs, make sure to keep them in sync
|
|
37
|
+
_FILE_SYNC_ATTRS: set[str] = {
|
|
38
|
+
"closed",
|
|
39
|
+
"encoding",
|
|
40
|
+
"errors",
|
|
41
|
+
"fileno",
|
|
42
|
+
"isatty",
|
|
43
|
+
"newlines",
|
|
44
|
+
"readable",
|
|
45
|
+
"seekable",
|
|
46
|
+
"writable",
|
|
47
|
+
# not defined in *IOBase:
|
|
48
|
+
"buffer",
|
|
49
|
+
"raw",
|
|
50
|
+
"line_buffering",
|
|
51
|
+
"closefd",
|
|
52
|
+
"name",
|
|
53
|
+
"mode",
|
|
54
|
+
"getvalue",
|
|
55
|
+
"getbuffer",
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
# This list is also in the docs, make sure to keep them in sync
|
|
59
|
+
_FILE_ASYNC_METHODS: set[str] = {
|
|
60
|
+
"flush",
|
|
61
|
+
"read",
|
|
62
|
+
"read1",
|
|
63
|
+
"readall",
|
|
64
|
+
"readinto",
|
|
65
|
+
"readline",
|
|
66
|
+
"readlines",
|
|
67
|
+
"seek",
|
|
68
|
+
"tell",
|
|
69
|
+
"truncate",
|
|
70
|
+
"write",
|
|
71
|
+
"writelines",
|
|
72
|
+
# not defined in *IOBase:
|
|
73
|
+
"readinto1",
|
|
74
|
+
"peek",
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
FileT = TypeVar("FileT")
|
|
79
|
+
FileT_co = TypeVar("FileT_co", covariant=True)
|
|
80
|
+
T = TypeVar("T")
|
|
81
|
+
T_co = TypeVar("T_co", covariant=True)
|
|
82
|
+
T_contra = TypeVar("T_contra", contravariant=True)
|
|
83
|
+
AnyStr_co = TypeVar("AnyStr_co", str, bytes, covariant=True)
|
|
84
|
+
AnyStr_contra = TypeVar("AnyStr_contra", str, bytes, contravariant=True)
|
|
85
|
+
|
|
86
|
+
# This is a little complicated. IO objects have a lot of methods, and which are available on
|
|
87
|
+
# different types varies wildly. We want to match the interface of whatever file we're wrapping.
|
|
88
|
+
# This pile of protocols each has one sync method/property, meaning they're going to be compatible
|
|
89
|
+
# with a file class that supports that method/property. The ones parameterized with AnyStr take
|
|
90
|
+
# either str or bytes depending.
|
|
91
|
+
|
|
92
|
+
# The wrapper is then a generic class, where the typevar is set to the type of the sync file we're
|
|
93
|
+
# wrapping. For generics, adding a type to self has a special meaning - properties/methods can be
|
|
94
|
+
# conditional - it's only valid to call them if the object you're accessing them on is compatible
|
|
95
|
+
# with that type hint. By using the protocols, the type checker will be checking to see if the
|
|
96
|
+
# wrapped type has that method, and only allow the methods that do to be called. We can then alter
|
|
97
|
+
# the signature however it needs to match runtime behaviour.
|
|
98
|
+
# More info: https://mypy.readthedocs.io/en/stable/more_types.html#advanced-uses-of-self-types
|
|
99
|
+
if TYPE_CHECKING:
|
|
100
|
+
from typing_extensions import Buffer, Protocol
|
|
101
|
+
|
|
102
|
+
# fmt: off
|
|
103
|
+
|
|
104
|
+
class _HasClosed(Protocol):
|
|
105
|
+
@property
|
|
106
|
+
def closed(self) -> bool: ...
|
|
107
|
+
|
|
108
|
+
class _HasEncoding(Protocol):
|
|
109
|
+
@property
|
|
110
|
+
def encoding(self) -> str: ...
|
|
111
|
+
|
|
112
|
+
class _HasErrors(Protocol):
|
|
113
|
+
@property
|
|
114
|
+
def errors(self) -> str | None: ...
|
|
115
|
+
|
|
116
|
+
class _HasFileNo(Protocol):
|
|
117
|
+
def fileno(self) -> int: ...
|
|
118
|
+
|
|
119
|
+
class _HasIsATTY(Protocol):
|
|
120
|
+
def isatty(self) -> bool: ...
|
|
121
|
+
|
|
122
|
+
class _HasNewlines(Protocol[T_co]):
|
|
123
|
+
# Type varies here - documented to be None, tuple of strings, strings. Typeshed uses Any.
|
|
124
|
+
@property
|
|
125
|
+
def newlines(self) -> T_co: ...
|
|
126
|
+
|
|
127
|
+
class _HasReadable(Protocol):
|
|
128
|
+
def readable(self) -> bool: ...
|
|
129
|
+
|
|
130
|
+
class _HasSeekable(Protocol):
|
|
131
|
+
def seekable(self) -> bool: ...
|
|
132
|
+
|
|
133
|
+
class _HasWritable(Protocol):
|
|
134
|
+
def writable(self) -> bool: ...
|
|
135
|
+
|
|
136
|
+
class _HasBuffer(Protocol):
|
|
137
|
+
@property
|
|
138
|
+
def buffer(self) -> BinaryIO: ...
|
|
139
|
+
|
|
140
|
+
class _HasRaw(Protocol):
|
|
141
|
+
@property
|
|
142
|
+
def raw(self) -> io.RawIOBase: ...
|
|
143
|
+
|
|
144
|
+
class _HasLineBuffering(Protocol):
|
|
145
|
+
@property
|
|
146
|
+
def line_buffering(self) -> bool: ...
|
|
147
|
+
|
|
148
|
+
class _HasCloseFD(Protocol):
|
|
149
|
+
@property
|
|
150
|
+
def closefd(self) -> bool: ...
|
|
151
|
+
|
|
152
|
+
class _HasName(Protocol):
|
|
153
|
+
@property
|
|
154
|
+
def name(self) -> str: ...
|
|
155
|
+
|
|
156
|
+
class _HasMode(Protocol):
|
|
157
|
+
@property
|
|
158
|
+
def mode(self) -> str: ...
|
|
159
|
+
|
|
160
|
+
class _CanGetValue(Protocol[AnyStr_co]):
|
|
161
|
+
def getvalue(self) -> AnyStr_co: ...
|
|
162
|
+
|
|
163
|
+
class _CanGetBuffer(Protocol):
|
|
164
|
+
def getbuffer(self) -> memoryview: ...
|
|
165
|
+
|
|
166
|
+
class _CanFlush(Protocol):
|
|
167
|
+
def flush(self) -> None: ...
|
|
168
|
+
|
|
169
|
+
class _CanRead(Protocol[AnyStr_co]):
|
|
170
|
+
def read(self, size: int | None = ..., /) -> AnyStr_co: ...
|
|
171
|
+
|
|
172
|
+
class _CanRead1(Protocol):
|
|
173
|
+
def read1(self, size: int | None = ..., /) -> bytes: ...
|
|
174
|
+
|
|
175
|
+
class _CanReadAll(Protocol[AnyStr_co]):
|
|
176
|
+
def readall(self) -> AnyStr_co: ...
|
|
177
|
+
|
|
178
|
+
class _CanReadInto(Protocol):
|
|
179
|
+
def readinto(self, buf: Buffer, /) -> int | None: ...
|
|
180
|
+
|
|
181
|
+
class _CanReadInto1(Protocol):
|
|
182
|
+
def readinto1(self, buffer: Buffer, /) -> int: ...
|
|
183
|
+
|
|
184
|
+
class _CanReadLine(Protocol[AnyStr_co]):
|
|
185
|
+
def readline(self, size: int = ..., /) -> AnyStr_co: ...
|
|
186
|
+
|
|
187
|
+
class _CanReadLines(Protocol[AnyStr]):
|
|
188
|
+
def readlines(self, hint: int = ..., /) -> list[AnyStr]: ...
|
|
189
|
+
|
|
190
|
+
class _CanSeek(Protocol):
|
|
191
|
+
def seek(self, target: int, whence: int = 0, /) -> int: ...
|
|
192
|
+
|
|
193
|
+
class _CanTell(Protocol):
|
|
194
|
+
def tell(self) -> int: ...
|
|
195
|
+
|
|
196
|
+
class _CanTruncate(Protocol):
|
|
197
|
+
def truncate(self, size: int | None = ..., /) -> int: ...
|
|
198
|
+
|
|
199
|
+
class _CanWrite(Protocol[T_contra]):
|
|
200
|
+
def write(self, data: T_contra, /) -> int: ...
|
|
201
|
+
|
|
202
|
+
class _CanWriteLines(Protocol[T_contra]):
|
|
203
|
+
# The lines parameter varies for bytes/str, so use a typevar to make the async match.
|
|
204
|
+
def writelines(self, lines: Iterable[T_contra], /) -> None: ...
|
|
205
|
+
|
|
206
|
+
class _CanPeek(Protocol[AnyStr_co]):
|
|
207
|
+
def peek(self, size: int = 0, /) -> AnyStr_co: ...
|
|
208
|
+
|
|
209
|
+
class _CanDetach(Protocol[T_co]):
|
|
210
|
+
# The T typevar will be the unbuffered/binary file this file wraps.
|
|
211
|
+
def detach(self) -> T_co: ...
|
|
212
|
+
|
|
213
|
+
class _CanClose(Protocol):
|
|
214
|
+
def close(self) -> None: ...
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
# FileT needs to be covariant for the protocol trick to work - the real IO types are effectively a
|
|
218
|
+
# subtype of the protocols.
|
|
219
|
+
class AsyncIOWrapper(AsyncResource, Generic[FileT_co]):
|
|
220
|
+
"""A generic :class:`~io.IOBase` wrapper that implements the :term:`asynchronous
|
|
221
|
+
file object` interface. Wrapped methods that could block are executed in
|
|
222
|
+
:meth:`trio.to_thread.run_sync`.
|
|
223
|
+
|
|
224
|
+
All properties and methods defined in :mod:`~io` are exposed by this
|
|
225
|
+
wrapper, if they exist in the wrapped file object.
|
|
226
|
+
"""
|
|
227
|
+
|
|
228
|
+
def __init__(self, file: FileT_co) -> None:
|
|
229
|
+
self._wrapped = file
|
|
230
|
+
|
|
231
|
+
@property
|
|
232
|
+
def wrapped(self) -> FileT_co:
|
|
233
|
+
"""object: A reference to the wrapped file object"""
|
|
234
|
+
|
|
235
|
+
return self._wrapped
|
|
236
|
+
|
|
237
|
+
if not TYPE_CHECKING:
|
|
238
|
+
|
|
239
|
+
def __getattr__(self, name: str) -> object:
|
|
240
|
+
if name in _FILE_SYNC_ATTRS:
|
|
241
|
+
return getattr(self._wrapped, name)
|
|
242
|
+
if name in _FILE_ASYNC_METHODS:
|
|
243
|
+
meth = getattr(self._wrapped, name)
|
|
244
|
+
|
|
245
|
+
@async_wraps(self.__class__, self._wrapped.__class__, name)
|
|
246
|
+
async def wrapper(
|
|
247
|
+
*args: Callable[..., T],
|
|
248
|
+
**kwargs: object | str | bool | CapacityLimiter | None,
|
|
249
|
+
) -> T:
|
|
250
|
+
func = partial(meth, *args, **kwargs)
|
|
251
|
+
return await trio.to_thread.run_sync(func)
|
|
252
|
+
|
|
253
|
+
# cache the generated method
|
|
254
|
+
setattr(self, name, wrapper)
|
|
255
|
+
return wrapper
|
|
256
|
+
|
|
257
|
+
raise AttributeError(name)
|
|
258
|
+
|
|
259
|
+
def __dir__(self) -> Iterable[str]:
|
|
260
|
+
attrs = set(super().__dir__())
|
|
261
|
+
attrs.update(a for a in _FILE_SYNC_ATTRS if hasattr(self.wrapped, a))
|
|
262
|
+
attrs.update(a for a in _FILE_ASYNC_METHODS if hasattr(self.wrapped, a))
|
|
263
|
+
return attrs
|
|
264
|
+
|
|
265
|
+
def __aiter__(self) -> AsyncIOWrapper[FileT_co]:
|
|
266
|
+
return self
|
|
267
|
+
|
|
268
|
+
async def __anext__(self: AsyncIOWrapper[_CanReadLine[AnyStr]]) -> AnyStr:
|
|
269
|
+
line = await self.readline()
|
|
270
|
+
if line:
|
|
271
|
+
return line
|
|
272
|
+
else:
|
|
273
|
+
raise StopAsyncIteration
|
|
274
|
+
|
|
275
|
+
async def detach(self: AsyncIOWrapper[_CanDetach[T]]) -> AsyncIOWrapper[T]:
|
|
276
|
+
"""Like :meth:`io.BufferedIOBase.detach`, but async.
|
|
277
|
+
|
|
278
|
+
This also re-wraps the result in a new :term:`asynchronous file object`
|
|
279
|
+
wrapper.
|
|
280
|
+
|
|
281
|
+
"""
|
|
282
|
+
|
|
283
|
+
raw = await trio.to_thread.run_sync(self._wrapped.detach)
|
|
284
|
+
return wrap_file(raw)
|
|
285
|
+
|
|
286
|
+
async def aclose(self: AsyncIOWrapper[_CanClose]) -> None:
|
|
287
|
+
"""Like :meth:`io.IOBase.close`, but async.
|
|
288
|
+
|
|
289
|
+
This is also shielded from cancellation; if a cancellation scope is
|
|
290
|
+
cancelled, the wrapped file object will still be safely closed.
|
|
291
|
+
|
|
292
|
+
"""
|
|
293
|
+
|
|
294
|
+
# ensure the underling file is closed during cancellation
|
|
295
|
+
with trio.CancelScope(shield=True):
|
|
296
|
+
await trio.to_thread.run_sync(self._wrapped.close)
|
|
297
|
+
|
|
298
|
+
await trio.lowlevel.checkpoint_if_cancelled()
|
|
299
|
+
|
|
300
|
+
if TYPE_CHECKING:
|
|
301
|
+
# fmt: off
|
|
302
|
+
# Based on typing.IO and io stubs.
|
|
303
|
+
@property
|
|
304
|
+
def closed(self: AsyncIOWrapper[_HasClosed]) -> bool: ...
|
|
305
|
+
@property
|
|
306
|
+
def encoding(self: AsyncIOWrapper[_HasEncoding]) -> str: ...
|
|
307
|
+
@property
|
|
308
|
+
def errors(self: AsyncIOWrapper[_HasErrors]) -> str | None: ...
|
|
309
|
+
@property
|
|
310
|
+
def newlines(self: AsyncIOWrapper[_HasNewlines[T]]) -> T: ...
|
|
311
|
+
@property
|
|
312
|
+
def buffer(self: AsyncIOWrapper[_HasBuffer]) -> BinaryIO: ...
|
|
313
|
+
@property
|
|
314
|
+
def raw(self: AsyncIOWrapper[_HasRaw]) -> io.RawIOBase: ...
|
|
315
|
+
@property
|
|
316
|
+
def line_buffering(self: AsyncIOWrapper[_HasLineBuffering]) -> int: ...
|
|
317
|
+
@property
|
|
318
|
+
def closefd(self: AsyncIOWrapper[_HasCloseFD]) -> bool: ...
|
|
319
|
+
@property
|
|
320
|
+
def name(self: AsyncIOWrapper[_HasName]) -> str: ...
|
|
321
|
+
@property
|
|
322
|
+
def mode(self: AsyncIOWrapper[_HasMode]) -> str: ...
|
|
323
|
+
|
|
324
|
+
def fileno(self: AsyncIOWrapper[_HasFileNo]) -> int: ...
|
|
325
|
+
def isatty(self: AsyncIOWrapper[_HasIsATTY]) -> bool: ...
|
|
326
|
+
def readable(self: AsyncIOWrapper[_HasReadable]) -> bool: ...
|
|
327
|
+
def seekable(self: AsyncIOWrapper[_HasSeekable]) -> bool: ...
|
|
328
|
+
def writable(self: AsyncIOWrapper[_HasWritable]) -> bool: ...
|
|
329
|
+
def getvalue(self: AsyncIOWrapper[_CanGetValue[AnyStr]]) -> AnyStr: ...
|
|
330
|
+
def getbuffer(self: AsyncIOWrapper[_CanGetBuffer]) -> memoryview: ...
|
|
331
|
+
async def flush(self: AsyncIOWrapper[_CanFlush]) -> None: ...
|
|
332
|
+
async def read(self: AsyncIOWrapper[_CanRead[AnyStr]], size: int | None = -1, /) -> AnyStr: ...
|
|
333
|
+
async def read1(self: AsyncIOWrapper[_CanRead1], size: int | None = -1, /) -> bytes: ...
|
|
334
|
+
async def readall(self: AsyncIOWrapper[_CanReadAll[AnyStr]]) -> AnyStr: ...
|
|
335
|
+
async def readinto(self: AsyncIOWrapper[_CanReadInto], buf: Buffer, /) -> int | None: ...
|
|
336
|
+
async def readline(self: AsyncIOWrapper[_CanReadLine[AnyStr]], size: int = -1, /) -> AnyStr: ...
|
|
337
|
+
async def readlines(self: AsyncIOWrapper[_CanReadLines[AnyStr]]) -> list[AnyStr]: ...
|
|
338
|
+
async def seek(self: AsyncIOWrapper[_CanSeek], target: int, whence: int = 0, /) -> int: ...
|
|
339
|
+
async def tell(self: AsyncIOWrapper[_CanTell]) -> int: ...
|
|
340
|
+
async def truncate(self: AsyncIOWrapper[_CanTruncate], size: int | None = None, /) -> int: ...
|
|
341
|
+
async def write(self: AsyncIOWrapper[_CanWrite[T]], data: T, /) -> int: ...
|
|
342
|
+
async def writelines(self: AsyncIOWrapper[_CanWriteLines[T]], lines: Iterable[T], /) -> None: ...
|
|
343
|
+
async def readinto1(self: AsyncIOWrapper[_CanReadInto1], buffer: Buffer, /) -> int: ...
|
|
344
|
+
async def peek(self: AsyncIOWrapper[_CanPeek[AnyStr]], size: int = 0, /) -> AnyStr: ...
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
# Type hints are copied from builtin open.
|
|
348
|
+
_OpenFile = Union["StrOrBytesPath", int]
|
|
349
|
+
_Opener = Callable[[str, int], int]
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
@overload
|
|
353
|
+
async def open_file(
|
|
354
|
+
file: _OpenFile,
|
|
355
|
+
mode: OpenTextMode = "r",
|
|
356
|
+
buffering: int = -1,
|
|
357
|
+
encoding: str | None = None,
|
|
358
|
+
errors: str | None = None,
|
|
359
|
+
newline: str | None = None,
|
|
360
|
+
closefd: bool = True,
|
|
361
|
+
opener: _Opener | None = None,
|
|
362
|
+
) -> AsyncIOWrapper[io.TextIOWrapper]: ...
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
@overload
|
|
366
|
+
async def open_file(
|
|
367
|
+
file: _OpenFile,
|
|
368
|
+
mode: OpenBinaryMode,
|
|
369
|
+
buffering: Literal[0],
|
|
370
|
+
encoding: None = None,
|
|
371
|
+
errors: None = None,
|
|
372
|
+
newline: None = None,
|
|
373
|
+
closefd: bool = True,
|
|
374
|
+
opener: _Opener | None = None,
|
|
375
|
+
) -> AsyncIOWrapper[io.FileIO]: ...
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
@overload
|
|
379
|
+
async def open_file(
|
|
380
|
+
file: _OpenFile,
|
|
381
|
+
mode: OpenBinaryModeUpdating,
|
|
382
|
+
buffering: Literal[-1, 1] = -1,
|
|
383
|
+
encoding: None = None,
|
|
384
|
+
errors: None = None,
|
|
385
|
+
newline: None = None,
|
|
386
|
+
closefd: bool = True,
|
|
387
|
+
opener: _Opener | None = None,
|
|
388
|
+
) -> AsyncIOWrapper[io.BufferedRandom]: ...
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
@overload
|
|
392
|
+
async def open_file(
|
|
393
|
+
file: _OpenFile,
|
|
394
|
+
mode: OpenBinaryModeWriting,
|
|
395
|
+
buffering: Literal[-1, 1] = -1,
|
|
396
|
+
encoding: None = None,
|
|
397
|
+
errors: None = None,
|
|
398
|
+
newline: None = None,
|
|
399
|
+
closefd: bool = True,
|
|
400
|
+
opener: _Opener | None = None,
|
|
401
|
+
) -> AsyncIOWrapper[io.BufferedWriter]: ...
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
@overload
|
|
405
|
+
async def open_file(
|
|
406
|
+
file: _OpenFile,
|
|
407
|
+
mode: OpenBinaryModeReading,
|
|
408
|
+
buffering: Literal[-1, 1] = -1,
|
|
409
|
+
encoding: None = None,
|
|
410
|
+
errors: None = None,
|
|
411
|
+
newline: None = None,
|
|
412
|
+
closefd: bool = True,
|
|
413
|
+
opener: _Opener | None = None,
|
|
414
|
+
) -> AsyncIOWrapper[io.BufferedReader]: ...
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
@overload
|
|
418
|
+
async def open_file(
|
|
419
|
+
file: _OpenFile,
|
|
420
|
+
mode: OpenBinaryMode,
|
|
421
|
+
buffering: int,
|
|
422
|
+
encoding: None = None,
|
|
423
|
+
errors: None = None,
|
|
424
|
+
newline: None = None,
|
|
425
|
+
closefd: bool = True,
|
|
426
|
+
opener: _Opener | None = None,
|
|
427
|
+
) -> AsyncIOWrapper[BinaryIO]: ...
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
@overload
|
|
431
|
+
async def open_file( # type: ignore[explicit-any] # Any usage matches builtins.open().
|
|
432
|
+
file: _OpenFile,
|
|
433
|
+
mode: str,
|
|
434
|
+
buffering: int = -1,
|
|
435
|
+
encoding: str | None = None,
|
|
436
|
+
errors: str | None = None,
|
|
437
|
+
newline: str | None = None,
|
|
438
|
+
closefd: bool = True,
|
|
439
|
+
opener: _Opener | None = None,
|
|
440
|
+
) -> AsyncIOWrapper[IO[Any]]: ...
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
async def open_file(
|
|
444
|
+
file: _OpenFile,
|
|
445
|
+
mode: str = "r",
|
|
446
|
+
buffering: int = -1,
|
|
447
|
+
encoding: str | None = None,
|
|
448
|
+
errors: str | None = None,
|
|
449
|
+
newline: str | None = None,
|
|
450
|
+
closefd: bool = True,
|
|
451
|
+
opener: _Opener | None = None,
|
|
452
|
+
) -> AsyncIOWrapper[object]:
|
|
453
|
+
"""Asynchronous version of :func:`open`.
|
|
454
|
+
|
|
455
|
+
Returns:
|
|
456
|
+
An :term:`asynchronous file object`
|
|
457
|
+
|
|
458
|
+
Example::
|
|
459
|
+
|
|
460
|
+
async with await trio.open_file(filename) as f:
|
|
461
|
+
async for line in f:
|
|
462
|
+
pass
|
|
463
|
+
|
|
464
|
+
assert f.closed
|
|
465
|
+
|
|
466
|
+
See also:
|
|
467
|
+
:func:`trio.Path.open`
|
|
468
|
+
|
|
469
|
+
"""
|
|
470
|
+
file_ = wrap_file(
|
|
471
|
+
await trio.to_thread.run_sync(
|
|
472
|
+
io.open,
|
|
473
|
+
file,
|
|
474
|
+
mode,
|
|
475
|
+
buffering,
|
|
476
|
+
encoding,
|
|
477
|
+
errors,
|
|
478
|
+
newline,
|
|
479
|
+
closefd,
|
|
480
|
+
opener,
|
|
481
|
+
),
|
|
482
|
+
)
|
|
483
|
+
return file_
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
def wrap_file(file: FileT) -> AsyncIOWrapper[FileT]:
|
|
487
|
+
"""This wraps any file object in a wrapper that provides an asynchronous
|
|
488
|
+
file object interface.
|
|
489
|
+
|
|
490
|
+
Args:
|
|
491
|
+
file: a :term:`file object`
|
|
492
|
+
|
|
493
|
+
Returns:
|
|
494
|
+
An :term:`asynchronous file object` that wraps ``file``
|
|
495
|
+
|
|
496
|
+
Example::
|
|
497
|
+
|
|
498
|
+
async_file = trio.wrap_file(StringIO('asdf'))
|
|
499
|
+
|
|
500
|
+
assert await async_file.read() == 'asdf'
|
|
501
|
+
|
|
502
|
+
"""
|
|
503
|
+
|
|
504
|
+
def has(attr: str) -> bool:
|
|
505
|
+
return hasattr(file, attr) and callable(getattr(file, attr))
|
|
506
|
+
|
|
507
|
+
if not (has("close") and (has("read") or has("write"))):
|
|
508
|
+
raise TypeError(
|
|
509
|
+
f"{file} does not implement required duck-file methods: "
|
|
510
|
+
"close and (read or write)",
|
|
511
|
+
)
|
|
512
|
+
|
|
513
|
+
return AsyncIOWrapper(file)
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Generic, TypeGuard, TypeVar
|
|
4
|
+
|
|
5
|
+
import attrs
|
|
6
|
+
|
|
7
|
+
import trio
|
|
8
|
+
from trio._util import final
|
|
9
|
+
|
|
10
|
+
from .abc import AsyncResource, HalfCloseableStream, ReceiveStream, SendStream
|
|
11
|
+
|
|
12
|
+
SendStreamT = TypeVar("SendStreamT", bound=SendStream)
|
|
13
|
+
ReceiveStreamT = TypeVar("ReceiveStreamT", bound=ReceiveStream)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
async def aclose_forcefully(resource: AsyncResource) -> None:
|
|
17
|
+
"""Close an async resource or async generator immediately, without
|
|
18
|
+
blocking to do any graceful cleanup.
|
|
19
|
+
|
|
20
|
+
:class:`~trio.abc.AsyncResource` objects guarantee that if their
|
|
21
|
+
:meth:`~trio.abc.AsyncResource.aclose` method is cancelled, then they will
|
|
22
|
+
still close the resource (albeit in a potentially ungraceful
|
|
23
|
+
fashion). :func:`aclose_forcefully` is a convenience function that
|
|
24
|
+
exploits this behavior to let you force a resource to be closed without
|
|
25
|
+
blocking: it works by calling ``await resource.aclose()`` and then
|
|
26
|
+
cancelling it immediately.
|
|
27
|
+
|
|
28
|
+
Most users won't need this, but it may be useful on cleanup paths where
|
|
29
|
+
you can't afford to block, or if you want to close a resource and don't
|
|
30
|
+
care about handling it gracefully. For example, if
|
|
31
|
+
:class:`~trio.SSLStream` encounters an error and cannot perform its
|
|
32
|
+
own graceful close, then there's no point in waiting to gracefully shut
|
|
33
|
+
down the underlying transport either, so it calls ``await
|
|
34
|
+
aclose_forcefully(self.transport_stream)``.
|
|
35
|
+
|
|
36
|
+
Note that this function is async, and that it acts as a checkpoint, but
|
|
37
|
+
unlike most async functions it cannot block indefinitely (at least,
|
|
38
|
+
assuming the underlying resource object is correctly implemented).
|
|
39
|
+
|
|
40
|
+
"""
|
|
41
|
+
with trio.CancelScope() as cs:
|
|
42
|
+
cs.cancel(reason="cancelled during aclose_forcefully")
|
|
43
|
+
await resource.aclose()
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _is_halfclosable(stream: SendStream) -> TypeGuard[HalfCloseableStream]:
|
|
47
|
+
"""Check if the stream has a send_eof() method."""
|
|
48
|
+
return hasattr(stream, "send_eof")
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@final
|
|
52
|
+
@attrs.define(eq=False, slots=False)
|
|
53
|
+
class StapledStream(
|
|
54
|
+
HalfCloseableStream,
|
|
55
|
+
Generic[SendStreamT, ReceiveStreamT],
|
|
56
|
+
):
|
|
57
|
+
"""This class `staples <https://en.wikipedia.org/wiki/Staple_(fastener)>`__
|
|
58
|
+
together two unidirectional streams to make single bidirectional stream.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
send_stream (~trio.abc.SendStream): The stream to use for sending.
|
|
62
|
+
receive_stream (~trio.abc.ReceiveStream): The stream to use for
|
|
63
|
+
receiving.
|
|
64
|
+
|
|
65
|
+
Example:
|
|
66
|
+
|
|
67
|
+
A silly way to make a stream that echoes back whatever you write to
|
|
68
|
+
it::
|
|
69
|
+
|
|
70
|
+
left, right = trio.testing.memory_stream_pair()
|
|
71
|
+
echo_stream = StapledStream(SocketStream(left), SocketStream(right))
|
|
72
|
+
await echo_stream.send_all(b"x")
|
|
73
|
+
assert await echo_stream.receive_some() == b"x"
|
|
74
|
+
|
|
75
|
+
:class:`StapledStream` objects implement the methods in the
|
|
76
|
+
:class:`~trio.abc.HalfCloseableStream` interface. They also have two
|
|
77
|
+
additional public attributes:
|
|
78
|
+
|
|
79
|
+
.. attribute:: send_stream
|
|
80
|
+
|
|
81
|
+
The underlying :class:`~trio.abc.SendStream`. :meth:`send_all` and
|
|
82
|
+
:meth:`wait_send_all_might_not_block` are delegated to this object.
|
|
83
|
+
|
|
84
|
+
.. attribute:: receive_stream
|
|
85
|
+
|
|
86
|
+
The underlying :class:`~trio.abc.ReceiveStream`. :meth:`receive_some`
|
|
87
|
+
is delegated to this object.
|
|
88
|
+
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
send_stream: SendStreamT
|
|
92
|
+
receive_stream: ReceiveStreamT
|
|
93
|
+
|
|
94
|
+
async def send_all(self, data: bytes | bytearray | memoryview) -> None:
|
|
95
|
+
"""Calls ``self.send_stream.send_all``."""
|
|
96
|
+
return await self.send_stream.send_all(data)
|
|
97
|
+
|
|
98
|
+
async def wait_send_all_might_not_block(self) -> None:
|
|
99
|
+
"""Calls ``self.send_stream.wait_send_all_might_not_block``."""
|
|
100
|
+
return await self.send_stream.wait_send_all_might_not_block()
|
|
101
|
+
|
|
102
|
+
async def send_eof(self) -> None:
|
|
103
|
+
"""Shuts down the send side of the stream.
|
|
104
|
+
|
|
105
|
+
If :meth:`self.send_stream.send_eof() <trio.abc.HalfCloseableStream.send_eof>` exists,
|
|
106
|
+
then this calls it. Otherwise, this calls
|
|
107
|
+
:meth:`self.send_stream.aclose() <trio.abc.AsyncResource.aclose>`.
|
|
108
|
+
"""
|
|
109
|
+
stream = self.send_stream
|
|
110
|
+
if _is_halfclosable(stream):
|
|
111
|
+
return await stream.send_eof()
|
|
112
|
+
else:
|
|
113
|
+
return await stream.aclose()
|
|
114
|
+
|
|
115
|
+
# we intentionally accept more types from the caller than we support returning
|
|
116
|
+
async def receive_some(self, max_bytes: int | None = None) -> bytes:
|
|
117
|
+
"""Calls ``self.receive_stream.receive_some``."""
|
|
118
|
+
return await self.receive_stream.receive_some(max_bytes)
|
|
119
|
+
|
|
120
|
+
async def aclose(self) -> None:
|
|
121
|
+
"""Calls ``aclose`` on both underlying streams."""
|
|
122
|
+
try:
|
|
123
|
+
await self.send_stream.aclose()
|
|
124
|
+
finally:
|
|
125
|
+
await self.receive_stream.aclose()
|