@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,1326 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import select
5
+ import socket as _stdlib_socket
6
+ import sys
7
+ from operator import index
8
+ from socket import AddressFamily, SocketKind
9
+ from typing import (
10
+ TYPE_CHECKING,
11
+ Any,
12
+ Concatenate,
13
+ SupportsIndex,
14
+ TypeAlias,
15
+ TypeVar,
16
+ overload,
17
+ )
18
+
19
+ import idna as _idna
20
+
21
+ import trio
22
+ from trio._util import wraps as _wraps
23
+
24
+ from . import _core
25
+
26
+ if TYPE_CHECKING:
27
+ from collections.abc import Awaitable, Callable, Iterable
28
+ from types import TracebackType
29
+
30
+ from typing_extensions import Buffer, ParamSpec, Self
31
+
32
+ from ._abc import HostnameResolver, SocketFactory
33
+
34
+ P = ParamSpec("P")
35
+
36
+
37
+ T = TypeVar("T")
38
+
39
+ # _stdlib_socket.socket supports 13 different socket families, see
40
+ # https://docs.python.org/3/library/socket.html#socket-families
41
+ # and the return type of several methods in SocketType will depend on those. Typeshed
42
+ # has ended up typing those return types as `Any` in most cases, but for users that
43
+ # know which family/families they're working in we could make SocketType a generic type,
44
+ # where you specify the return values you expect from those methods depending on the
45
+ # protocol the socket will be handling.
46
+ # But without the ability to default the value to `Any` it will be overly cumbersome for
47
+ # most users, so currently we just specify it as `Any`. Otherwise we would write:
48
+ # `AddressFormat = TypeVar("AddressFormat")`
49
+ # but instead we simply do:
50
+ AddressFormat: TypeAlias = Any # type: ignore[explicit-any]
51
+
52
+
53
+ # Usage:
54
+ #
55
+ # async with _try_sync():
56
+ # return sync_call_that_might_fail_with_exception()
57
+ # # we only get here if the sync call in fact did fail with a
58
+ # # BlockingIOError
59
+ # return await do_it_properly_with_a_check_point()
60
+ #
61
+ class _try_sync:
62
+ def __init__(
63
+ self,
64
+ blocking_exc_override: Callable[[BaseException], bool] | None = None,
65
+ ) -> None:
66
+ self._blocking_exc_override = blocking_exc_override
67
+
68
+ def _is_blocking_io_error(self, exc: BaseException) -> bool:
69
+ if self._blocking_exc_override is None:
70
+ return isinstance(exc, BlockingIOError)
71
+ else:
72
+ return self._blocking_exc_override(exc)
73
+
74
+ async def __aenter__(self) -> None:
75
+ await trio.lowlevel.checkpoint_if_cancelled()
76
+
77
+ async def __aexit__(
78
+ self,
79
+ exc_type: type[BaseException] | None,
80
+ exc_value: BaseException | None,
81
+ traceback: TracebackType | None,
82
+ ) -> bool:
83
+ if exc_value is not None and self._is_blocking_io_error(exc_value):
84
+ # Discard the exception and fall through to the code below the
85
+ # block
86
+ return True
87
+ else:
88
+ await trio.lowlevel.cancel_shielded_checkpoint()
89
+ # Let the return or exception propagate
90
+ return False
91
+
92
+
93
+ ################################################################
94
+ # Overrides
95
+ ################################################################
96
+
97
+ _resolver: _core.RunVar[HostnameResolver | None] = _core.RunVar("hostname_resolver")
98
+ _socket_factory: _core.RunVar[SocketFactory | None] = _core.RunVar("socket_factory")
99
+
100
+
101
+ def set_custom_hostname_resolver(
102
+ hostname_resolver: HostnameResolver | None,
103
+ ) -> HostnameResolver | None:
104
+ """Set a custom hostname resolver.
105
+
106
+ By default, Trio's :func:`getaddrinfo` and :func:`getnameinfo` functions
107
+ use the standard system resolver functions. This function allows you to
108
+ customize that behavior. The main intended use case is for testing, but it
109
+ might also be useful for using third-party resolvers like `c-ares
110
+ <https://c-ares.haxx.se/>`__ (though be warned that these rarely make
111
+ perfect drop-in replacements for the system resolver). See
112
+ :class:`trio.abc.HostnameResolver` for more details.
113
+
114
+ Setting a custom hostname resolver affects all future calls to
115
+ :func:`getaddrinfo` and :func:`getnameinfo` within the enclosing call to
116
+ :func:`trio.run`. All other hostname resolution in Trio is implemented in
117
+ terms of these functions.
118
+
119
+ Generally you should call this function just once, right at the beginning
120
+ of your program.
121
+
122
+ Args:
123
+ hostname_resolver (trio.abc.HostnameResolver or None): The new custom
124
+ hostname resolver, or None to restore the default behavior.
125
+
126
+ Returns:
127
+ The previous hostname resolver (which may be None).
128
+
129
+ """
130
+ old = _resolver.get(None)
131
+ _resolver.set(hostname_resolver)
132
+ return old
133
+
134
+
135
+ def set_custom_socket_factory(
136
+ socket_factory: SocketFactory | None,
137
+ ) -> SocketFactory | None:
138
+ """Set a custom socket object factory.
139
+
140
+ This function allows you to replace Trio's normal socket class with a
141
+ custom class. This is very useful for testing, and probably a bad idea in
142
+ any other circumstance. See :class:`trio.abc.HostnameResolver` for more
143
+ details.
144
+
145
+ Setting a custom socket factory affects all future calls to :func:`socket`
146
+ within the enclosing call to :func:`trio.run`.
147
+
148
+ Generally you should call this function just once, right at the beginning
149
+ of your program.
150
+
151
+ Args:
152
+ socket_factory (trio.abc.SocketFactory or None): The new custom
153
+ socket factory, or None to restore the default behavior.
154
+
155
+ Returns:
156
+ The previous socket factory (which may be None).
157
+
158
+ """
159
+ old = _socket_factory.get(None)
160
+ _socket_factory.set(socket_factory)
161
+ return old
162
+
163
+
164
+ ################################################################
165
+ # getaddrinfo and friends
166
+ ################################################################
167
+
168
+ # AI_NUMERICSERV may be missing on some older platforms, so use it when available.
169
+ # See: https://github.com/python-trio/trio/issues/3133
170
+ _NUMERIC_ONLY = _stdlib_socket.AI_NUMERICHOST
171
+ _NUMERIC_ONLY |= getattr(_stdlib_socket, "AI_NUMERICSERV", 0)
172
+
173
+
174
+ # It would be possible to @overload the return value depending on Literal[AddressFamily.INET/6], but should probably be added in typeshed first
175
+ async def getaddrinfo(
176
+ host: bytes | str | None,
177
+ port: bytes | str | int | None,
178
+ family: int = 0,
179
+ type: int = 0,
180
+ proto: int = 0,
181
+ flags: int = 0,
182
+ ) -> list[
183
+ tuple[
184
+ AddressFamily,
185
+ SocketKind,
186
+ int,
187
+ str,
188
+ tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes],
189
+ ]
190
+ ]:
191
+ """Look up a numeric address given a name.
192
+
193
+ Arguments and return values are identical to :func:`socket.getaddrinfo`,
194
+ except that this version is async.
195
+
196
+ Also, :func:`trio.socket.getaddrinfo` correctly uses IDNA 2008 to process
197
+ non-ASCII domain names. (:func:`socket.getaddrinfo` uses IDNA 2003, which
198
+ can give the wrong result in some cases and cause you to connect to a
199
+ different host than the one you intended; see `bpo-17305
200
+ <https://bugs.python.org/issue17305>`__.)
201
+
202
+ This function's behavior can be customized using
203
+ :func:`set_custom_hostname_resolver`.
204
+
205
+ """
206
+
207
+ # If host and port are numeric, then getaddrinfo doesn't block and we can
208
+ # skip the whole thread thing, which seems worthwhile. So we try first
209
+ # with the _NUMERIC_ONLY flags set, and then only spawn a thread if that
210
+ # fails with EAI_NONAME:
211
+ def numeric_only_failure(exc: BaseException) -> bool:
212
+ return (
213
+ isinstance(exc, _stdlib_socket.gaierror)
214
+ and exc.errno == _stdlib_socket.EAI_NONAME
215
+ )
216
+
217
+ async with _try_sync(numeric_only_failure):
218
+ return _stdlib_socket.getaddrinfo(
219
+ host,
220
+ port,
221
+ family,
222
+ type,
223
+ proto,
224
+ flags | _NUMERIC_ONLY,
225
+ )
226
+ # That failed; it's a real hostname. We better use a thread.
227
+ #
228
+ # Also, it might be a unicode hostname, in which case we want to do our
229
+ # own encoding using the idna module, rather than letting Python do
230
+ # it. (Python will use the old IDNA 2003 standard, and possibly get the
231
+ # wrong answer - see bpo-17305). However, the idna module is picky, and
232
+ # will refuse to process some valid hostname strings, like "::1". So if
233
+ # it's already ascii, we pass it through; otherwise, we encode it to.
234
+ if isinstance(host, str):
235
+ try:
236
+ host = host.encode("ascii")
237
+ except UnicodeEncodeError:
238
+ # UTS-46 defines various normalizations; in particular, by default
239
+ # idna.encode will error out if the hostname has Capital Letters
240
+ # in it; with uts46=True it will lowercase them instead.
241
+ host = _idna.encode(host, uts46=True)
242
+ hr = _resolver.get(None)
243
+ if hr is not None:
244
+ return await hr.getaddrinfo(host, port, family, type, proto, flags)
245
+ else:
246
+ return await trio.to_thread.run_sync(
247
+ _stdlib_socket.getaddrinfo,
248
+ host,
249
+ port,
250
+ family,
251
+ type,
252
+ proto,
253
+ flags,
254
+ abandon_on_cancel=True,
255
+ )
256
+
257
+
258
+ async def getnameinfo(
259
+ sockaddr: tuple[str, int] | tuple[str, int, int, int],
260
+ flags: int,
261
+ ) -> tuple[str, str]:
262
+ """Look up a name given a numeric address.
263
+
264
+ Arguments and return values are identical to :func:`socket.getnameinfo`,
265
+ except that this version is async.
266
+
267
+ This function's behavior can be customized using
268
+ :func:`set_custom_hostname_resolver`.
269
+
270
+ """
271
+ hr = _resolver.get(None)
272
+ if hr is not None:
273
+ return await hr.getnameinfo(sockaddr, flags)
274
+ else:
275
+ return await trio.to_thread.run_sync(
276
+ _stdlib_socket.getnameinfo,
277
+ sockaddr,
278
+ flags,
279
+ abandon_on_cancel=True,
280
+ )
281
+
282
+
283
+ async def getprotobyname(name: str) -> int:
284
+ """Look up a protocol number by name. (Rarely used.)
285
+
286
+ Like :func:`socket.getprotobyname`, but async.
287
+
288
+ """
289
+ return await trio.to_thread.run_sync(
290
+ _stdlib_socket.getprotobyname,
291
+ name,
292
+ abandon_on_cancel=True,
293
+ )
294
+
295
+
296
+ # obsolete gethostbyname etc. intentionally omitted
297
+ # likewise for create_connection (use open_tcp_stream instead)
298
+
299
+ ################################################################
300
+ # Socket "constructors"
301
+ ################################################################
302
+
303
+
304
+ def from_stdlib_socket(sock: _stdlib_socket.socket) -> SocketType:
305
+ """Convert a standard library :class:`socket.socket` object into a Trio
306
+ socket object.
307
+
308
+ """
309
+ return _SocketType(sock)
310
+
311
+
312
+ @_wraps(_stdlib_socket.fromfd, assigned=(), updated=())
313
+ def fromfd(
314
+ fd: SupportsIndex,
315
+ family: AddressFamily | int = _stdlib_socket.AF_INET,
316
+ type: SocketKind | int = _stdlib_socket.SOCK_STREAM,
317
+ proto: int = 0,
318
+ ) -> SocketType:
319
+ """Like :func:`socket.fromfd`, but returns a Trio socket object."""
320
+ family, type_, proto = _sniff_sockopts_for_fileno(family, type, proto, index(fd))
321
+ return from_stdlib_socket(_stdlib_socket.fromfd(fd, family, type_, proto))
322
+
323
+
324
+ if sys.platform == "win32" or (
325
+ not TYPE_CHECKING and hasattr(_stdlib_socket, "fromshare")
326
+ ):
327
+
328
+ @_wraps(_stdlib_socket.fromshare, assigned=(), updated=())
329
+ def fromshare(info: bytes) -> SocketType:
330
+ """Like :func:`socket.fromshare`, but returns a Trio socket object."""
331
+ return from_stdlib_socket(_stdlib_socket.fromshare(info))
332
+
333
+
334
+ if sys.platform == "win32":
335
+ FamilyT: TypeAlias = int
336
+ TypeT: TypeAlias = int
337
+ FamilyDefault = _stdlib_socket.AF_INET
338
+ else:
339
+ FamilyDefault: None = None
340
+ FamilyT: TypeAlias = int | AddressFamily | None
341
+ TypeT: TypeAlias = _stdlib_socket.socket | int
342
+
343
+
344
+ @_wraps(_stdlib_socket.socketpair, assigned=(), updated=())
345
+ def socketpair(
346
+ family: FamilyT = FamilyDefault,
347
+ type: TypeT = SocketKind.SOCK_STREAM,
348
+ proto: int = 0,
349
+ ) -> tuple[SocketType, SocketType]:
350
+ """Like :func:`socket.socketpair`, but returns a pair of Trio socket
351
+ objects.
352
+
353
+ """
354
+ left, right = _stdlib_socket.socketpair(family, type, proto)
355
+ return (from_stdlib_socket(left), from_stdlib_socket(right))
356
+
357
+
358
+ @_wraps(_stdlib_socket.socket, assigned=(), updated=())
359
+ def socket(
360
+ family: AddressFamily | int = _stdlib_socket.AF_INET,
361
+ type: SocketKind | int = _stdlib_socket.SOCK_STREAM,
362
+ proto: int = 0,
363
+ fileno: int | None = None,
364
+ ) -> SocketType:
365
+ """Create a new Trio socket, like :class:`socket.socket`.
366
+
367
+ This function's behavior can be customized using
368
+ :func:`set_custom_socket_factory`.
369
+
370
+ """
371
+ if fileno is None:
372
+ sf = _socket_factory.get(None)
373
+ if sf is not None:
374
+ return sf.socket(family, type, proto)
375
+ else:
376
+ family, type, proto = _sniff_sockopts_for_fileno( # noqa: A001
377
+ family,
378
+ type,
379
+ proto,
380
+ fileno,
381
+ )
382
+ stdlib_socket = _stdlib_socket.socket(family, type, proto, fileno)
383
+ return from_stdlib_socket(stdlib_socket)
384
+
385
+
386
+ def _sniff_sockopts_for_fileno(
387
+ family: AddressFamily | int,
388
+ type_: SocketKind | int,
389
+ proto: int,
390
+ fileno: int | None,
391
+ ) -> tuple[AddressFamily | int, SocketKind | int, int]:
392
+ """Correct SOCKOPTS for given fileno, falling back to provided values."""
393
+ # Wrap the raw fileno into a Python socket object
394
+ # This object might have the wrong metadata, but it lets us easily call getsockopt
395
+ # and then we'll throw it away and construct a new one with the correct metadata.
396
+ if sys.platform != "linux":
397
+ return family, type_, proto
398
+ from socket import ( # type: ignore[attr-defined,unused-ignore]
399
+ SO_DOMAIN,
400
+ SO_PROTOCOL,
401
+ SO_TYPE,
402
+ SOL_SOCKET,
403
+ )
404
+
405
+ sockobj = _stdlib_socket.socket(family, type_, proto, fileno=fileno)
406
+ try:
407
+ family = sockobj.getsockopt(SOL_SOCKET, SO_DOMAIN)
408
+ proto = sockobj.getsockopt(SOL_SOCKET, SO_PROTOCOL)
409
+ type_ = sockobj.getsockopt(SOL_SOCKET, SO_TYPE)
410
+ finally:
411
+ # Unwrap it again, so that sockobj.__del__ doesn't try to close our socket
412
+ sockobj.detach()
413
+ return family, type_, proto
414
+
415
+
416
+ ################################################################
417
+ # SocketType
418
+ ################################################################
419
+
420
+ # sock.type gets weird stuff set in it, in particular on Linux:
421
+ #
422
+ # https://bugs.python.org/issue21327
423
+ #
424
+ # But on other platforms (e.g. Windows) SOCK_NONBLOCK and SOCK_CLOEXEC aren't
425
+ # even defined. To recover the actual socket type (e.g. SOCK_STREAM) from a
426
+ # socket.type attribute, mask with this:
427
+ _SOCK_TYPE_MASK = ~(
428
+ getattr(_stdlib_socket, "SOCK_NONBLOCK", 0)
429
+ | getattr(_stdlib_socket, "SOCK_CLOEXEC", 0)
430
+ )
431
+
432
+
433
+ def _make_simple_sock_method_wrapper(
434
+ fn: Callable[Concatenate[_stdlib_socket.socket, P], T],
435
+ wait_fn: Callable[[_stdlib_socket.socket], Awaitable[None]],
436
+ maybe_avail: bool = False,
437
+ ) -> Callable[Concatenate[_SocketType, P], Awaitable[T]]:
438
+ @_wraps(fn, assigned=("__name__",), updated=())
439
+ async def wrapper(self: _SocketType, *args: P.args, **kwargs: P.kwargs) -> T:
440
+ return await self._nonblocking_helper(wait_fn, fn, *args, **kwargs)
441
+
442
+ wrapper.__doc__ = f"""Like :meth:`socket.socket.{fn.__name__}`, but async.
443
+
444
+ """
445
+ if maybe_avail:
446
+ wrapper.__doc__ += (
447
+ f"Only available on platforms where :meth:`socket.socket.{fn.__name__}` is "
448
+ "available."
449
+ )
450
+ return wrapper
451
+
452
+
453
+ # Helpers to work with the (hostname, port) language that Python uses for socket
454
+ # addresses everywhere. Split out into a standalone function so it can be reused by
455
+ # FakeNet.
456
+
457
+
458
+ # Take an address in Python's representation, and returns a new address in
459
+ # the same representation, but with names resolved to numbers,
460
+ # etc.
461
+ #
462
+ # local=True means that the address is being used with bind() or similar
463
+ # local=False means that the address is being used with connect() or sendto() or
464
+ # similar.
465
+ #
466
+
467
+
468
+ # Using a TypeVar to indicate we return the same type of address appears to give errors
469
+ # when passed a union of address types.
470
+ # @overload likely works, but is extremely verbose.
471
+ # NOTE: this function does not always checkpoint
472
+ async def _resolve_address_nocp(
473
+ type_: int,
474
+ family: AddressFamily,
475
+ proto: int,
476
+ *,
477
+ ipv6_v6only: bool | int,
478
+ address: AddressFormat,
479
+ local: bool,
480
+ ) -> AddressFormat:
481
+ # Do some pre-checking (or exit early for non-IP sockets)
482
+ if family == _stdlib_socket.AF_INET:
483
+ if not isinstance(address, tuple) or not len(address) == 2:
484
+ raise ValueError("address should be a (host, port) tuple")
485
+ elif family == _stdlib_socket.AF_INET6:
486
+ if not isinstance(address, tuple) or not 2 <= len(address) <= 4:
487
+ raise ValueError(
488
+ "address should be a (host, port, [flowinfo, [scopeid]]) tuple",
489
+ )
490
+ elif hasattr(_stdlib_socket, "AF_UNIX") and family == _stdlib_socket.AF_UNIX:
491
+ # unwrap path-likes
492
+ assert isinstance(address, (str, bytes, os.PathLike))
493
+ return os.fspath(address)
494
+ else:
495
+ return address
496
+
497
+ # -- From here on we know we have IPv4 or IPV6 --
498
+ host: str | None
499
+ host, port, *_ = address
500
+ # Fast path for the simple case: already-resolved IP address,
501
+ # already-resolved port. This is particularly important for UDP, since
502
+ # every sendto call goes through here.
503
+ if isinstance(port, int) and host is not None:
504
+ try:
505
+ _stdlib_socket.inet_pton(family, host)
506
+ except (OSError, TypeError):
507
+ pass
508
+ else:
509
+ return address
510
+ # Special cases to match the stdlib, see gh-277
511
+ if host == "":
512
+ host = None
513
+ if host == "<broadcast>":
514
+ host = "255.255.255.255"
515
+ flags = 0
516
+ if local:
517
+ flags |= _stdlib_socket.AI_PASSIVE
518
+ # Since we always pass in an explicit family here, AI_ADDRCONFIG
519
+ # doesn't add any value -- if we have no ipv6 connectivity and are
520
+ # working with an ipv6 socket, then things will break soon enough! And
521
+ # if we do enable it, then it makes it impossible to even run tests
522
+ # for ipv6 address resolution on travis-ci, which as of 2017-03-07 has
523
+ # no ipv6.
524
+ # flags |= AI_ADDRCONFIG
525
+ if family == _stdlib_socket.AF_INET6 and not ipv6_v6only:
526
+ flags |= _stdlib_socket.AI_V4MAPPED
527
+ gai_res = await getaddrinfo(host, port, family, type_, proto, flags)
528
+ # AFAICT from the spec it's not possible for getaddrinfo to return an
529
+ # empty list.
530
+ assert len(gai_res) >= 1
531
+ # Address is the last item in the first entry
532
+ (*_, normed), *_ = gai_res
533
+ # The above ignored any flowid and scopeid in the passed-in address,
534
+ # so restore them if present:
535
+ if family == _stdlib_socket.AF_INET6:
536
+ list_normed = list(normed)
537
+ assert len(normed) == 4
538
+ if len(address) >= 3:
539
+ list_normed[2] = address[2]
540
+ if len(address) >= 4:
541
+ list_normed[3] = address[3]
542
+ return tuple(list_normed)
543
+ return normed
544
+
545
+
546
+ class SocketType:
547
+ def __init__(self) -> None:
548
+ # make sure this __init__ works with multiple inheritance
549
+ super().__init__()
550
+ # and only raises error if it's directly constructed
551
+ if type(self) is SocketType:
552
+ raise TypeError(
553
+ "SocketType is an abstract class; use trio.socket.socket if you "
554
+ "want to construct a socket object",
555
+ )
556
+
557
+ def detach(self) -> int:
558
+ raise NotImplementedError
559
+
560
+ def fileno(self) -> int:
561
+ raise NotImplementedError
562
+
563
+ def getpeername(self) -> AddressFormat:
564
+ raise NotImplementedError
565
+
566
+ def getsockname(self) -> AddressFormat:
567
+ raise NotImplementedError
568
+
569
+ @overload
570
+ def getsockopt(self, level: int, optname: int) -> int: ...
571
+
572
+ @overload
573
+ def getsockopt(self, level: int, optname: int, buflen: int) -> bytes: ...
574
+
575
+ def getsockopt(
576
+ self,
577
+ level: int,
578
+ optname: int,
579
+ buflen: int | None = None,
580
+ ) -> int | bytes:
581
+ raise NotImplementedError
582
+
583
+ @overload
584
+ def setsockopt(self, level: int, optname: int, value: int | Buffer) -> None: ...
585
+
586
+ @overload
587
+ def setsockopt(
588
+ self,
589
+ level: int,
590
+ optname: int,
591
+ value: None,
592
+ optlen: int,
593
+ ) -> None: ...
594
+
595
+ def setsockopt(
596
+ self,
597
+ level: int,
598
+ optname: int,
599
+ value: int | Buffer | None,
600
+ optlen: int | None = None,
601
+ ) -> None:
602
+ raise NotImplementedError
603
+
604
+ def listen(self, backlog: int = min(_stdlib_socket.SOMAXCONN, 128)) -> None:
605
+ raise NotImplementedError
606
+
607
+ def get_inheritable(self) -> bool:
608
+ raise NotImplementedError
609
+
610
+ def set_inheritable(self, inheritable: bool) -> None:
611
+ raise NotImplementedError
612
+
613
+ if sys.platform == "win32" or (
614
+ not TYPE_CHECKING and hasattr(_stdlib_socket.socket, "share")
615
+ ):
616
+
617
+ def share(self, process_id: int) -> bytes:
618
+ raise NotImplementedError
619
+
620
+ def __enter__(self) -> Self:
621
+ raise NotImplementedError
622
+
623
+ def __exit__(
624
+ self,
625
+ exc_type: type[BaseException] | None,
626
+ exc_value: BaseException | None,
627
+ traceback: TracebackType | None,
628
+ ) -> None:
629
+ raise NotImplementedError
630
+
631
+ @property
632
+ def family(self) -> AddressFamily:
633
+ raise NotImplementedError
634
+
635
+ @property
636
+ def type(self) -> SocketKind:
637
+ raise NotImplementedError
638
+
639
+ @property
640
+ def proto(self) -> int:
641
+ raise NotImplementedError
642
+
643
+ @property
644
+ def did_shutdown_SHUT_WR(self) -> bool:
645
+ """Return True if the socket has been shut down with the SHUT_WR flag"""
646
+ raise NotImplementedError
647
+
648
+ def __repr__(self) -> str:
649
+ raise NotImplementedError
650
+
651
+ def dup(self) -> SocketType:
652
+ raise NotImplementedError
653
+
654
+ def close(self) -> None:
655
+ raise NotImplementedError
656
+
657
+ async def bind(self, address: AddressFormat) -> None:
658
+ raise NotImplementedError
659
+
660
+ def shutdown(self, flag: int) -> None:
661
+ raise NotImplementedError
662
+
663
+ def is_readable(self) -> bool:
664
+ """Return True if the socket is readable. This is checked with `select.select` on Windows, otherwise `select.poll`."""
665
+ raise NotImplementedError
666
+
667
+ async def wait_writable(self) -> None:
668
+ """Convenience method that calls trio.lowlevel.wait_writable for the object."""
669
+ raise NotImplementedError
670
+
671
+ async def accept(self) -> tuple[SocketType, AddressFormat]:
672
+ raise NotImplementedError
673
+
674
+ async def connect(self, address: AddressFormat) -> None:
675
+ raise NotImplementedError
676
+
677
+ def recv(self, buflen: int, flags: int = 0, /) -> Awaitable[bytes]:
678
+ raise NotImplementedError
679
+
680
+ def recv_into(
681
+ self,
682
+ buffer: Buffer,
683
+ nbytes: int = 0,
684
+ flags: int = 0,
685
+ ) -> Awaitable[int]:
686
+ raise NotImplementedError
687
+
688
+ # return type of socket.socket.recvfrom in typeshed is tuple[bytes, Any]
689
+ def recvfrom(
690
+ self,
691
+ bufsize: int,
692
+ flags: int = 0,
693
+ /,
694
+ ) -> Awaitable[tuple[bytes, AddressFormat]]:
695
+ raise NotImplementedError
696
+
697
+ # return type of socket.socket.recvfrom_into in typeshed is tuple[bytes, Any]
698
+ def recvfrom_into(
699
+ self,
700
+ buffer: Buffer,
701
+ nbytes: int = 0,
702
+ flags: int = 0,
703
+ ) -> Awaitable[tuple[int, AddressFormat]]:
704
+ raise NotImplementedError
705
+
706
+ if sys.platform != "win32" or (
707
+ not TYPE_CHECKING and hasattr(_stdlib_socket.socket, "recvmsg")
708
+ ):
709
+
710
+ def recvmsg(
711
+ self,
712
+ bufsize: int,
713
+ ancbufsize: int = 0,
714
+ flags: int = 0,
715
+ /,
716
+ ) -> Awaitable[tuple[bytes, list[tuple[int, int, bytes]], int, object]]:
717
+ raise NotImplementedError
718
+
719
+ if sys.platform != "win32" or (
720
+ not TYPE_CHECKING and hasattr(_stdlib_socket.socket, "recvmsg_into")
721
+ ):
722
+
723
+ def recvmsg_into(
724
+ self,
725
+ buffers: Iterable[Buffer],
726
+ ancbufsize: int = 0,
727
+ flags: int = 0,
728
+ /,
729
+ ) -> Awaitable[tuple[int, list[tuple[int, int, bytes]], int, object]]:
730
+ raise NotImplementedError
731
+
732
+ def send(self, bytes: Buffer, flags: int = 0, /) -> Awaitable[int]:
733
+ raise NotImplementedError
734
+
735
+ @overload
736
+ async def sendto(
737
+ self,
738
+ data: Buffer,
739
+ address: tuple[object, ...] | str | Buffer,
740
+ /,
741
+ ) -> int: ...
742
+
743
+ @overload
744
+ async def sendto(
745
+ self,
746
+ data: Buffer,
747
+ flags: int,
748
+ address: tuple[object, ...] | str | Buffer,
749
+ /,
750
+ ) -> int: ...
751
+
752
+ async def sendto(self, *args: object) -> int:
753
+ raise NotImplementedError
754
+
755
+ if sys.platform != "win32" or (
756
+ not TYPE_CHECKING and hasattr(_stdlib_socket.socket, "sendmsg")
757
+ ):
758
+
759
+ @_wraps(_stdlib_socket.socket.sendmsg, assigned=(), updated=())
760
+ async def sendmsg(
761
+ self,
762
+ buffers: Iterable[Buffer],
763
+ ancdata: Iterable[tuple[int, int, Buffer]] = (),
764
+ flags: int = 0,
765
+ address: AddressFormat | None = None,
766
+ /,
767
+ ) -> int:
768
+ raise NotImplementedError
769
+
770
+
771
+ # copy docstrings from socket.SocketType / socket.socket
772
+ for name, obj in SocketType.__dict__.items():
773
+ # skip dunders and already defined docstrings
774
+ if name.startswith("__") or obj.__doc__:
775
+ continue
776
+ # try both socket.socket and socket.SocketType
777
+ for stdlib_type in _stdlib_socket.socket, _stdlib_socket.SocketType:
778
+ stdlib_obj = getattr(stdlib_type, name, None)
779
+ if stdlib_obj and stdlib_obj.__doc__:
780
+ break
781
+ else:
782
+ continue
783
+ obj.__doc__ = stdlib_obj.__doc__
784
+
785
+
786
+ class _SocketType(SocketType):
787
+ def __init__(self, sock: _stdlib_socket.socket) -> None:
788
+ if type(sock) is not _stdlib_socket.socket:
789
+ # For example, ssl.SSLSocket subclasses socket.socket, but we
790
+ # certainly don't want to blindly wrap one of those.
791
+ raise TypeError(
792
+ f"expected object of type 'socket.socket', not '{type(sock).__name__}'",
793
+ )
794
+ self._sock = sock
795
+ self._sock.setblocking(False)
796
+ self._did_shutdown_SHUT_WR = False
797
+
798
+ ################################################################
799
+ # Simple + portable methods and attributes
800
+ ################################################################
801
+
802
+ # forwarded methods
803
+ def detach(self) -> int:
804
+ return self._sock.detach()
805
+
806
+ def fileno(self) -> int:
807
+ return self._sock.fileno()
808
+
809
+ def getpeername(self) -> AddressFormat:
810
+ return self._sock.getpeername()
811
+
812
+ def getsockname(self) -> AddressFormat:
813
+ return self._sock.getsockname()
814
+
815
+ @overload
816
+ def getsockopt(self, level: int, optname: int) -> int: ...
817
+
818
+ @overload
819
+ def getsockopt(self, level: int, optname: int, buflen: int) -> bytes: ...
820
+
821
+ def getsockopt(
822
+ self,
823
+ level: int,
824
+ optname: int,
825
+ buflen: int | None = None,
826
+ ) -> int | bytes:
827
+ if buflen is None:
828
+ return self._sock.getsockopt(level, optname)
829
+ return self._sock.getsockopt(level, optname, buflen)
830
+
831
+ @overload
832
+ def setsockopt(self, level: int, optname: int, value: int | Buffer) -> None: ...
833
+
834
+ @overload
835
+ def setsockopt(
836
+ self,
837
+ level: int,
838
+ optname: int,
839
+ value: None,
840
+ optlen: int,
841
+ ) -> None: ...
842
+
843
+ def setsockopt(
844
+ self,
845
+ level: int,
846
+ optname: int,
847
+ value: int | Buffer | None,
848
+ optlen: int | None = None,
849
+ ) -> None:
850
+ if optlen is None:
851
+ if value is None:
852
+ raise TypeError(
853
+ "invalid value for argument 'value', must not be None when specifying optlen",
854
+ )
855
+ return self._sock.setsockopt(level, optname, value)
856
+ if value is not None:
857
+ raise TypeError(
858
+ f"invalid value for argument 'value': {value!r}, must be None when specifying optlen",
859
+ )
860
+
861
+ # Note: PyPy may crash here due to setsockopt only supporting
862
+ # four parameters.
863
+ return self._sock.setsockopt(level, optname, value, optlen)
864
+
865
+ def listen(self, backlog: int = min(_stdlib_socket.SOMAXCONN, 128)) -> None:
866
+ return self._sock.listen(backlog)
867
+
868
+ def get_inheritable(self) -> bool:
869
+ return self._sock.get_inheritable()
870
+
871
+ def set_inheritable(self, inheritable: bool) -> None:
872
+ return self._sock.set_inheritable(inheritable)
873
+
874
+ if sys.platform == "win32" or (
875
+ not TYPE_CHECKING and hasattr(_stdlib_socket.socket, "share")
876
+ ):
877
+
878
+ def share(self, process_id: int) -> bytes:
879
+ return self._sock.share(process_id)
880
+
881
+ def __enter__(self) -> Self:
882
+ return self
883
+
884
+ def __exit__(
885
+ self,
886
+ exc_type: type[BaseException] | None,
887
+ exc_value: BaseException | None,
888
+ traceback: TracebackType | None,
889
+ ) -> None:
890
+ return self._sock.__exit__(exc_type, exc_value, traceback)
891
+
892
+ @property
893
+ def family(self) -> AddressFamily:
894
+ return self._sock.family
895
+
896
+ @property
897
+ def type(self) -> SocketKind:
898
+ return self._sock.type
899
+
900
+ @property
901
+ def proto(self) -> int:
902
+ return self._sock.proto
903
+
904
+ @property
905
+ def did_shutdown_SHUT_WR(self) -> bool:
906
+ return self._did_shutdown_SHUT_WR
907
+
908
+ def __repr__(self) -> str:
909
+ return repr(self._sock).replace("socket.socket", "trio.socket.socket")
910
+
911
+ def dup(self) -> SocketType:
912
+ """Same as :meth:`socket.socket.dup`."""
913
+ return _SocketType(self._sock.dup())
914
+
915
+ def close(self) -> None:
916
+ if self._sock.fileno() != -1:
917
+ trio.lowlevel.notify_closing(self._sock)
918
+ self._sock.close()
919
+
920
+ async def bind(self, address: AddressFormat) -> None:
921
+ address = await self._resolve_address_nocp(address, local=True)
922
+ if (
923
+ hasattr(_stdlib_socket, "AF_UNIX")
924
+ and self.family == _stdlib_socket.AF_UNIX
925
+ and address[0]
926
+ ):
927
+ # Use a thread for the filesystem traversal (unless it's an
928
+ # abstract domain socket)
929
+ return await trio.to_thread.run_sync(self._sock.bind, address)
930
+ else:
931
+ # POSIX actually says that bind can return EWOULDBLOCK and
932
+ # complete asynchronously, like connect. But in practice AFAICT
933
+ # there aren't yet any real systems that do this, so we'll worry
934
+ # about it when it happens.
935
+ await trio.lowlevel.checkpoint()
936
+ return self._sock.bind(address)
937
+
938
+ def shutdown(self, flag: int) -> None:
939
+ # no need to worry about return value b/c always returns None:
940
+ self._sock.shutdown(flag)
941
+ # only do this if the call succeeded:
942
+ if flag in [_stdlib_socket.SHUT_WR, _stdlib_socket.SHUT_RDWR]:
943
+ self._did_shutdown_SHUT_WR = True
944
+
945
+ def is_readable(self) -> bool:
946
+ # use select.select on Windows, and select.poll everywhere else
947
+ if sys.platform == "win32":
948
+ rready, _, _ = select.select([self._sock], [], [], 0)
949
+ return bool(rready)
950
+ p = select.poll()
951
+ p.register(self._sock, select.POLLIN)
952
+ return bool(p.poll(0))
953
+
954
+ async def wait_writable(self) -> None:
955
+ await _core.wait_writable(self._sock)
956
+
957
+ async def _resolve_address_nocp(
958
+ self,
959
+ address: AddressFormat,
960
+ *,
961
+ local: bool,
962
+ ) -> AddressFormat:
963
+ if self.family == _stdlib_socket.AF_INET6:
964
+ ipv6_v6only = self._sock.getsockopt(
965
+ _stdlib_socket.IPPROTO_IPV6,
966
+ _stdlib_socket.IPV6_V6ONLY,
967
+ )
968
+ else:
969
+ ipv6_v6only = False
970
+ return await _resolve_address_nocp(
971
+ self.type,
972
+ self.family,
973
+ self.proto,
974
+ ipv6_v6only=ipv6_v6only,
975
+ address=address,
976
+ local=local,
977
+ )
978
+
979
+ # args and kwargs must be starred, otherwise pyright complains:
980
+ # '"args" member of ParamSpec is valid only when used with *args parameter'
981
+ # '"kwargs" member of ParamSpec is valid only when used with **kwargs parameter'
982
+ # wait_fn and fn must also be first in the signature
983
+ # 'Keyword parameter cannot appear in signature after ParamSpec args parameter'
984
+
985
+ async def _nonblocking_helper(
986
+ self,
987
+ wait_fn: Callable[[_stdlib_socket.socket], Awaitable[None]],
988
+ fn: Callable[Concatenate[_stdlib_socket.socket, P], T],
989
+ *args: P.args,
990
+ **kwargs: P.kwargs,
991
+ ) -> T:
992
+ # We have to reconcile two conflicting goals:
993
+ # - We want to make it look like we always blocked in doing these
994
+ # operations. The obvious way is to always do an IO wait before
995
+ # calling the function.
996
+ # - But, we also want to provide the correct semantics, and part
997
+ # of that means giving correct errors. So, for example, if you
998
+ # haven't called .listen(), then .accept() raises an error
999
+ # immediately. But in this same circumstance, then on macOS, the
1000
+ # socket does not register as readable. So if we block waiting
1001
+ # for read *before* we call accept, then we'll be waiting
1002
+ # forever instead of properly raising an error. (On Linux,
1003
+ # interestingly, AFAICT a socket that can't possible read/write
1004
+ # *does* count as readable/writable for select() purposes. But
1005
+ # not on macOS.)
1006
+ #
1007
+ # So, we have to call the function once, with the appropriate
1008
+ # cancellation/yielding sandwich if it succeeds, and if it gives
1009
+ # BlockingIOError *then* we fall back to IO wait.
1010
+ #
1011
+ # XX think if this can be combined with the similar logic for IOCP
1012
+ # submission...
1013
+ async with _try_sync():
1014
+ return fn(self._sock, *args, **kwargs)
1015
+ # First attempt raised BlockingIOError:
1016
+ while True:
1017
+ await wait_fn(self._sock)
1018
+ try:
1019
+ return fn(self._sock, *args, **kwargs)
1020
+ except BlockingIOError:
1021
+ pass
1022
+
1023
+ ################################################################
1024
+ # accept
1025
+ ################################################################
1026
+
1027
+ _accept = _make_simple_sock_method_wrapper(
1028
+ _stdlib_socket.socket.accept,
1029
+ _core.wait_readable,
1030
+ )
1031
+
1032
+ async def accept(self) -> tuple[SocketType, AddressFormat]:
1033
+ """Like :meth:`socket.socket.accept`, but async."""
1034
+ sock, addr = await self._accept()
1035
+ return from_stdlib_socket(sock), addr
1036
+
1037
+ ################################################################
1038
+ # connect
1039
+ ################################################################
1040
+
1041
+ async def connect(self, address: AddressFormat) -> None:
1042
+ # nonblocking connect is weird -- you call it to start things
1043
+ # off, then the socket becomes writable as a completion
1044
+ # notification. This means it isn't really cancellable... we close the
1045
+ # socket if cancelled, to avoid confusion.
1046
+ try:
1047
+ address = await self._resolve_address_nocp(address, local=False)
1048
+ async with _try_sync():
1049
+ # An interesting puzzle: can a non-blocking connect() return EINTR
1050
+ # (= raise InterruptedError)? PEP 475 specifically left this as
1051
+ # the one place where it lets an InterruptedError escape instead
1052
+ # of automatically retrying. This is based on the idea that EINTR
1053
+ # from connect means that the connection was already started, and
1054
+ # will continue in the background. For a blocking connect, this
1055
+ # sort of makes sense: if it returns EINTR then the connection
1056
+ # attempt is continuing in the background, and on many system you
1057
+ # can't then call connect() again because there is already a
1058
+ # connect happening. See:
1059
+ #
1060
+ # http://www.madore.org/~david/computers/connect-intr.html
1061
+ #
1062
+ # For a non-blocking connect, it doesn't make as much sense --
1063
+ # surely the interrupt didn't happen after we successfully
1064
+ # initiated the connect and are just waiting for it to complete,
1065
+ # because a non-blocking connect does not wait! And the spec
1066
+ # describes the interaction between EINTR/blocking connect, but
1067
+ # doesn't have anything useful to say about non-blocking connect:
1068
+ #
1069
+ # http://pubs.opengroup.org/onlinepubs/007904975/functions/connect.html
1070
+ #
1071
+ # So we have a conundrum: if EINTR means that the connect() hasn't
1072
+ # happened (like it does for essentially every other syscall),
1073
+ # then InterruptedError should be caught and retried. If EINTR
1074
+ # means that the connect() has successfully started, then
1075
+ # InterruptedError should be caught and ignored. Which should we
1076
+ # do?
1077
+ #
1078
+ # In practice, the resolution is probably that non-blocking
1079
+ # connect simply never returns EINTR, so the question of how to
1080
+ # handle it is moot. Someone spelunked macOS/FreeBSD and
1081
+ # confirmed this is true there:
1082
+ #
1083
+ # https://stackoverflow.com/questions/14134440/eintr-and-non-blocking-calls
1084
+ #
1085
+ # and exarkun seems to think it's true in general of non-blocking
1086
+ # calls:
1087
+ #
1088
+ # https://twistedmatrix.com/pipermail/twisted-python/2010-September/022864.html
1089
+ # (and indeed, AFAICT twisted doesn't try to handle
1090
+ # InterruptedError).
1091
+ #
1092
+ # So we don't try to catch InterruptedError. This way if it
1093
+ # happens, someone will hopefully tell us, and then hopefully we
1094
+ # can investigate their system to figure out what its semantics
1095
+ # are.
1096
+ return self._sock.connect(address)
1097
+ # It raised BlockingIOError, meaning that it's started the
1098
+ # connection attempt. We wait for it to complete:
1099
+ await _core.wait_writable(self._sock)
1100
+ except trio.Cancelled:
1101
+ # We can't really cancel a connect, and the socket is in an
1102
+ # indeterminate state. Better to close it so we don't get
1103
+ # confused.
1104
+ self._sock.close()
1105
+ raise
1106
+ # Okay, the connect finished, but it might have failed:
1107
+ err = self._sock.getsockopt(_stdlib_socket.SOL_SOCKET, _stdlib_socket.SO_ERROR)
1108
+ if err != 0:
1109
+ raise OSError(err, f"Error connecting to {address!r}: {os.strerror(err)}")
1110
+
1111
+ ################################################################
1112
+ # recv
1113
+ ################################################################
1114
+
1115
+ # Not possible to typecheck with a Callable (due to DefaultArg), nor with a
1116
+ # callback Protocol (https://github.com/python/typing/discussions/1040)
1117
+ # but this seems to work. If not explicitly defined then pyright --verifytypes will
1118
+ # complain about AmbiguousType
1119
+ if TYPE_CHECKING:
1120
+
1121
+ def recv(self, buflen: int, flags: int = 0, /) -> Awaitable[bytes]: ...
1122
+
1123
+ recv = _make_simple_sock_method_wrapper(
1124
+ _stdlib_socket.socket.recv,
1125
+ _core.wait_readable,
1126
+ )
1127
+
1128
+ ################################################################
1129
+ # recv_into
1130
+ ################################################################
1131
+
1132
+ if TYPE_CHECKING:
1133
+
1134
+ def recv_into(
1135
+ self,
1136
+ /,
1137
+ buffer: Buffer,
1138
+ nbytes: int = 0,
1139
+ flags: int = 0,
1140
+ ) -> Awaitable[int]: ...
1141
+
1142
+ recv_into = _make_simple_sock_method_wrapper(
1143
+ _stdlib_socket.socket.recv_into,
1144
+ _core.wait_readable,
1145
+ )
1146
+
1147
+ ################################################################
1148
+ # recvfrom
1149
+ ################################################################
1150
+
1151
+ if TYPE_CHECKING:
1152
+ # return type of socket.socket.recvfrom in typeshed is tuple[bytes, Any]
1153
+ def recvfrom(
1154
+ self,
1155
+ bufsize: int,
1156
+ flags: int = 0,
1157
+ /,
1158
+ ) -> Awaitable[tuple[bytes, AddressFormat]]: ...
1159
+
1160
+ recvfrom = _make_simple_sock_method_wrapper(
1161
+ _stdlib_socket.socket.recvfrom,
1162
+ _core.wait_readable,
1163
+ )
1164
+
1165
+ ################################################################
1166
+ # recvfrom_into
1167
+ ################################################################
1168
+
1169
+ if TYPE_CHECKING:
1170
+ # return type of socket.socket.recvfrom_into in typeshed is tuple[bytes, Any]
1171
+ def recvfrom_into(
1172
+ self,
1173
+ /,
1174
+ buffer: Buffer,
1175
+ nbytes: int = 0,
1176
+ flags: int = 0,
1177
+ ) -> Awaitable[tuple[int, AddressFormat]]: ...
1178
+
1179
+ recvfrom_into = _make_simple_sock_method_wrapper(
1180
+ _stdlib_socket.socket.recvfrom_into,
1181
+ _core.wait_readable,
1182
+ )
1183
+
1184
+ ################################################################
1185
+ # recvmsg
1186
+ ################################################################
1187
+
1188
+ if sys.platform != "win32" or (
1189
+ not TYPE_CHECKING and hasattr(_stdlib_socket.socket, "recvmsg")
1190
+ ):
1191
+ if TYPE_CHECKING:
1192
+
1193
+ def recvmsg(
1194
+ self,
1195
+ bufsize: int,
1196
+ ancbufsize: int = 0,
1197
+ flags: int = 0,
1198
+ /,
1199
+ ) -> Awaitable[tuple[bytes, list[tuple[int, int, bytes]], int, object]]: ...
1200
+
1201
+ recvmsg = _make_simple_sock_method_wrapper(
1202
+ _stdlib_socket.socket.recvmsg,
1203
+ _core.wait_readable,
1204
+ maybe_avail=True,
1205
+ )
1206
+
1207
+ ################################################################
1208
+ # recvmsg_into
1209
+ ################################################################
1210
+
1211
+ if sys.platform != "win32" or (
1212
+ not TYPE_CHECKING and hasattr(_stdlib_socket.socket, "recvmsg_into")
1213
+ ):
1214
+ if TYPE_CHECKING:
1215
+
1216
+ def recvmsg_into(
1217
+ self,
1218
+ buffers: Iterable[Buffer],
1219
+ ancbufsize: int = 0,
1220
+ flags: int = 0,
1221
+ /,
1222
+ ) -> Awaitable[tuple[int, list[tuple[int, int, bytes]], int, object]]: ...
1223
+
1224
+ recvmsg_into = _make_simple_sock_method_wrapper(
1225
+ _stdlib_socket.socket.recvmsg_into,
1226
+ _core.wait_readable,
1227
+ maybe_avail=True,
1228
+ )
1229
+
1230
+ ################################################################
1231
+ # send
1232
+ ################################################################
1233
+
1234
+ if TYPE_CHECKING:
1235
+
1236
+ def send(self, bytes: Buffer, flags: int = 0, /) -> Awaitable[int]: ...
1237
+
1238
+ send = _make_simple_sock_method_wrapper(
1239
+ _stdlib_socket.socket.send,
1240
+ _core.wait_writable,
1241
+ )
1242
+
1243
+ ################################################################
1244
+ # sendto
1245
+ ################################################################
1246
+
1247
+ @overload
1248
+ async def sendto(
1249
+ self,
1250
+ data: Buffer,
1251
+ address: tuple[object, ...] | str | Buffer,
1252
+ /,
1253
+ ) -> int: ...
1254
+
1255
+ @overload
1256
+ async def sendto(
1257
+ self,
1258
+ data: Buffer,
1259
+ flags: int,
1260
+ address: tuple[object, ...] | str | Buffer,
1261
+ /,
1262
+ ) -> int: ...
1263
+
1264
+ @_wraps(_stdlib_socket.socket.sendto, assigned=(), updated=())
1265
+ async def sendto(self, *args: object) -> int:
1266
+ """Similar to :meth:`socket.socket.sendto`, but async."""
1267
+ # args is: data[, flags], address
1268
+ # and kwargs are not accepted
1269
+ args_list = list(args)
1270
+ args_list[-1] = await self._resolve_address_nocp(args[-1], local=False)
1271
+ # args_list is Any, which isn't the signature of sendto().
1272
+ # We don't care about invalid types, sendto() will do the checking.
1273
+ return await self._nonblocking_helper(
1274
+ _core.wait_writable,
1275
+ _stdlib_socket.socket.sendto, # type: ignore[arg-type]
1276
+ *args_list,
1277
+ )
1278
+
1279
+ ################################################################
1280
+ # sendmsg
1281
+ ################################################################
1282
+
1283
+ if sys.platform != "win32" or (
1284
+ not TYPE_CHECKING and hasattr(_stdlib_socket.socket, "sendmsg")
1285
+ ):
1286
+
1287
+ @_wraps(_stdlib_socket.socket.sendmsg, assigned=(), updated=())
1288
+ async def sendmsg(
1289
+ self,
1290
+ buffers: Iterable[Buffer],
1291
+ ancdata: Iterable[tuple[int, int, Buffer]] = (),
1292
+ flags: int = 0,
1293
+ address: AddressFormat | None = None,
1294
+ /,
1295
+ ) -> int:
1296
+ """Similar to :meth:`socket.socket.sendmsg`, but async.
1297
+
1298
+ Only available on platforms where :meth:`socket.socket.sendmsg` is
1299
+ available.
1300
+
1301
+ """
1302
+ if address is not None:
1303
+ address = await self._resolve_address_nocp(address, local=False)
1304
+ return await self._nonblocking_helper(
1305
+ _core.wait_writable,
1306
+ _stdlib_socket.socket.sendmsg,
1307
+ buffers,
1308
+ ancdata,
1309
+ flags,
1310
+ address,
1311
+ )
1312
+
1313
+ ################################################################
1314
+ # sendfile
1315
+ ################################################################
1316
+
1317
+ # Not implemented yet:
1318
+ # async def sendfile(self, file, offset=0, count=None):
1319
+ # XX
1320
+
1321
+ # Intentionally omitted:
1322
+ # sendall
1323
+ # makefile
1324
+ # setblocking/getblocking
1325
+ # settimeout/gettimeout
1326
+ # timeout