@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,626 @@
1
+ from __future__ import annotations # isort: split
2
+
3
+ import __future__ # Regular import, not special!
4
+
5
+ import enum
6
+ import functools
7
+ import importlib
8
+ import inspect
9
+ import json
10
+ import socket as stdlib_socket
11
+ import sys
12
+ import types
13
+ from pathlib import Path, PurePath
14
+ from types import ModuleType
15
+ from typing import TYPE_CHECKING, Any, Protocol
16
+
17
+ import attrs
18
+ import pytest
19
+
20
+ import trio
21
+ import trio.testing
22
+ from trio._tests.pytest_plugin import RUN_SLOW, skip_if_optional_else_raise
23
+
24
+ from .. import _core, _util
25
+ from .._core._tests.tutil import slow
26
+
27
+ if TYPE_CHECKING:
28
+ from collections.abc import Iterable, Iterator
29
+
30
+ mypy_cache_updated = False
31
+
32
+
33
+ try: # If installed, check both versions of this class.
34
+ from typing_extensions import Protocol as Protocol_ext
35
+ except ImportError: # pragma: no cover
36
+ Protocol_ext = Protocol
37
+
38
+
39
+ def _ensure_mypy_cache_updated() -> None:
40
+ # This pollutes the `empty` dir. Should this be changed?
41
+ try:
42
+ from mypy.api import run
43
+ except ImportError as error:
44
+ skip_if_optional_else_raise(error)
45
+
46
+ global mypy_cache_updated
47
+ if not mypy_cache_updated:
48
+ # mypy cache was *probably* already updated by the other tests,
49
+ # but `pytest -k ...` might run just this test on its own
50
+ result = run(
51
+ [
52
+ "--config-file=",
53
+ "--cache-dir=./.mypy_cache",
54
+ "--no-error-summary",
55
+ "-c",
56
+ "import trio",
57
+ ],
58
+ )
59
+ assert not result[1] # stderr
60
+ assert not result[0] # stdout
61
+ mypy_cache_updated = True
62
+
63
+
64
+ def test_core_is_properly_reexported() -> None:
65
+ # Each export from _core should be re-exported by exactly one of these
66
+ # three modules:
67
+ sources = [trio, trio.lowlevel, trio.testing]
68
+ for symbol in dir(_core):
69
+ if symbol.startswith("_"):
70
+ continue
71
+ found = 0
72
+ for source in sources:
73
+ if symbol in dir(source) and getattr(source, symbol) is getattr(
74
+ _core,
75
+ symbol,
76
+ ):
77
+ found += 1
78
+ print(symbol, found)
79
+ assert found == 1
80
+
81
+
82
+ def class_is_final(cls: type) -> bool:
83
+ """Check if a class cannot be subclassed."""
84
+ try:
85
+ # new_class() handles metaclasses properly, type(...) does not.
86
+ types.new_class("SubclassTester", (cls,))
87
+ except TypeError:
88
+ return True
89
+ else:
90
+ return False
91
+
92
+
93
+ def iter_modules(
94
+ module: types.ModuleType,
95
+ only_public: bool,
96
+ ) -> Iterator[types.ModuleType]:
97
+ yield module
98
+ for name, class_ in module.__dict__.items():
99
+ if name.startswith("_") and only_public:
100
+ continue
101
+ if not isinstance(class_, ModuleType):
102
+ continue
103
+ if not class_.__name__.startswith(module.__name__): # pragma: no cover
104
+ continue
105
+ if class_ is module: # pragma: no cover
106
+ continue
107
+ yield from iter_modules(class_, only_public)
108
+
109
+
110
+ PUBLIC_MODULES = list(iter_modules(trio, only_public=True))
111
+ ALL_MODULES = list(iter_modules(trio, only_public=False))
112
+ PUBLIC_MODULE_NAMES = [m.__name__ for m in PUBLIC_MODULES]
113
+
114
+
115
+ # It doesn't make sense for downstream redistributors to run this test, since
116
+ # they might be using a newer version of Python with additional symbols which
117
+ # won't be reflected in trio.socket, and this shouldn't cause downstream test
118
+ # runs to start failing.
119
+ @pytest.mark.redistributors_should_skip
120
+ @pytest.mark.skipif(
121
+ sys.version_info[:4] == (3, 14, 0, "beta"),
122
+ # 12 pass, 16 fail
123
+ reason="several tools don't support 3.14",
124
+ )
125
+ # Static analysis tools often have trouble with alpha releases, where Python's
126
+ # internals are in flux, grammar may not have settled down, etc.
127
+ @pytest.mark.skipif(
128
+ sys.version_info.releaselevel == "alpha",
129
+ reason="skip static introspection tools on Python dev/alpha releases",
130
+ )
131
+ @pytest.mark.parametrize("modname", PUBLIC_MODULE_NAMES)
132
+ @pytest.mark.parametrize("tool", ["pylint", "jedi", "mypy", "pyright_verifytypes"])
133
+ @pytest.mark.filterwarnings(
134
+ # https://github.com/pypa/setuptools/issues/3274
135
+ "ignore:module 'sre_constants' is deprecated:DeprecationWarning",
136
+ )
137
+ def test_static_tool_sees_all_symbols(tool: str, modname: str, tmp_path: Path) -> None:
138
+ module = importlib.import_module(modname)
139
+
140
+ def no_underscores(symbols: Iterable[str]) -> set[str]:
141
+ return {symbol for symbol in symbols if not symbol.startswith("_")}
142
+
143
+ runtime_names = no_underscores(dir(module))
144
+
145
+ # ignore deprecated module `tests` being invisible
146
+ if modname == "trio":
147
+ runtime_names.discard("tests")
148
+
149
+ # Ignore any __future__ feature objects, if imported under that name.
150
+ for name in __future__.all_feature_names:
151
+ if getattr(module, name, None) is getattr(__future__, name):
152
+ runtime_names.remove(name)
153
+
154
+ if tool == "pylint":
155
+ try:
156
+ from pylint.lint import PyLinter
157
+ except ImportError as error:
158
+ skip_if_optional_else_raise(error)
159
+
160
+ linter = PyLinter()
161
+ assert module.__file__ is not None
162
+ ast = linter.get_ast(module.__file__, modname)
163
+ static_names = no_underscores(ast) # type: ignore[arg-type]
164
+ elif tool == "jedi":
165
+ if sys.implementation.name != "cpython":
166
+ pytest.skip("jedi does not support pypy")
167
+
168
+ try:
169
+ import jedi
170
+ except ImportError as error:
171
+ skip_if_optional_else_raise(error)
172
+
173
+ # Simulate typing "import trio; trio.<TAB>"
174
+ script = jedi.Script(f"import {modname}; {modname}.")
175
+ completions = script.complete()
176
+ static_names = no_underscores(c.name for c in completions)
177
+ elif tool == "mypy":
178
+ if sys.implementation.name != "cpython":
179
+ # https://github.com/python/mypy/issues/20329
180
+ pytest.skip("mypy does not support pypy")
181
+
182
+ if not RUN_SLOW: # pragma: no cover
183
+ pytest.skip("use --run-slow to check against mypy")
184
+
185
+ cache = Path.cwd() / ".mypy_cache"
186
+
187
+ _ensure_mypy_cache_updated()
188
+
189
+ trio_cache = next(cache.glob("*/trio"))
190
+ _, modname = (modname + ".").split(".", 1)
191
+ modname = modname[:-1]
192
+ mod_cache = trio_cache / modname if modname else trio_cache
193
+ if mod_cache.is_dir(): # pragma: no coverage
194
+ mod_cache = mod_cache / "__init__.data.json"
195
+ else:
196
+ mod_cache = trio_cache / (modname + ".data.json")
197
+
198
+ assert mod_cache.exists()
199
+ assert mod_cache.is_file()
200
+ with mod_cache.open() as cache_file:
201
+ cache_json = json.loads(cache_file.read())
202
+ static_names = no_underscores(
203
+ key
204
+ for key, value in cache_json["names"].items()
205
+ if not key.startswith(".") and value["kind"] == "Gdef"
206
+ )
207
+ elif tool == "pyright_verifytypes":
208
+ if not RUN_SLOW: # pragma: no cover
209
+ pytest.skip("use --run-slow to check against pyright")
210
+
211
+ try:
212
+ import pyright # noqa: F401
213
+ except ImportError as error:
214
+ skip_if_optional_else_raise(error)
215
+ import subprocess
216
+
217
+ res = subprocess.run(
218
+ ["pyright", f"--verifytypes={modname}", "--outputjson"],
219
+ capture_output=True,
220
+ )
221
+ current_result = json.loads(res.stdout)
222
+
223
+ static_names = {
224
+ x["name"][len(modname) + 1 :]
225
+ for x in current_result["typeCompleteness"]["symbols"]
226
+ if x["name"].startswith(modname)
227
+ }
228
+ else: # pragma: no cover
229
+ raise AssertionError()
230
+
231
+ # It's expected that the static set will contain more names than the
232
+ # runtime set:
233
+ # - static tools are sometimes sloppy and include deleted names
234
+ # - some symbols are platform-specific at runtime, but always show up in
235
+ # static analysis (e.g. in trio.socket or trio.lowlevel)
236
+ # So we check that the runtime names are a subset of the static names.
237
+ missing_names = runtime_names - static_names
238
+
239
+ # ignore warnings about deprecated module tests
240
+ missing_names -= {"tests"}
241
+
242
+ if missing_names: # pragma: no cover
243
+ print(f"{tool} can't see the following names in {modname}:")
244
+ print()
245
+ for name in sorted(missing_names):
246
+ print(f" {name}")
247
+ raise AssertionError()
248
+
249
+
250
+ @slow
251
+ # see comment on test_static_tool_sees_all_symbols
252
+ @pytest.mark.redistributors_should_skip
253
+ # Static analysis tools often have trouble with alpha releases, where Python's
254
+ # internals are in flux, grammar may not have settled down, etc.
255
+ @pytest.mark.skipif(
256
+ sys.version_info.releaselevel == "alpha",
257
+ reason="skip static introspection tools on Python dev/alpha releases",
258
+ )
259
+ @pytest.mark.parametrize("module_name", PUBLIC_MODULE_NAMES)
260
+ @pytest.mark.parametrize("tool", ["jedi", "mypy"])
261
+ def test_static_tool_sees_class_members(
262
+ tool: str,
263
+ module_name: str,
264
+ tmp_path: Path,
265
+ ) -> None:
266
+ module = PUBLIC_MODULES[PUBLIC_MODULE_NAMES.index(module_name)]
267
+
268
+ # ignore hidden, but not dunder, symbols
269
+ def no_hidden(symbols: Iterable[str]) -> set[str]:
270
+ return {
271
+ symbol
272
+ for symbol in symbols
273
+ if (not symbol.startswith("_")) or symbol.startswith("__")
274
+ }
275
+
276
+ if tool == "jedi" and sys.implementation.name != "cpython":
277
+ pytest.skip("jedi does not support pypy")
278
+
279
+ if tool == "mypy" and sys.implementation.name != "cpython":
280
+ # https://github.com/python/mypy/issues/20329
281
+ pytest.skip("mypy does not support pypy")
282
+
283
+ if tool == "mypy":
284
+ cache = Path.cwd() / ".mypy_cache"
285
+
286
+ _ensure_mypy_cache_updated()
287
+
288
+ trio_cache = next(cache.glob("*/trio"))
289
+ modname = module_name
290
+ _, modname = (modname + ".").split(".", 1)
291
+ modname = modname[:-1]
292
+ mod_cache = trio_cache / modname if modname else trio_cache
293
+ if mod_cache.is_dir():
294
+ mod_cache = mod_cache / "__init__.data.json"
295
+ else:
296
+ mod_cache = trio_cache / (modname + ".data.json")
297
+
298
+ assert mod_cache.exists()
299
+ assert mod_cache.is_file()
300
+ with mod_cache.open() as cache_file:
301
+ cache_json = json.loads(cache_file.read())
302
+
303
+ # skip a bunch of file-system activity (probably can un-memoize?)
304
+ @functools.lru_cache
305
+ def lookup_symbol(symbol: str) -> dict[str, Any]: # type: ignore[misc, explicit-any]
306
+ topname, *modname, name = symbol.split(".")
307
+ version = next(cache.glob("3.*/"))
308
+ mod_cache = version / topname
309
+ if not mod_cache.is_dir():
310
+ mod_cache = version / (topname + ".data.json")
311
+
312
+ if modname:
313
+ for piece in modname[:-1]:
314
+ mod_cache /= piece
315
+ next_cache = mod_cache / modname[-1]
316
+ if next_cache.is_dir(): # pragma: no coverage
317
+ mod_cache = next_cache / "__init__.data.json"
318
+ else:
319
+ mod_cache = mod_cache / (modname[-1] + ".data.json")
320
+ elif mod_cache.is_dir():
321
+ mod_cache /= "__init__.data.json"
322
+ with mod_cache.open() as f:
323
+ return json.loads(f.read())["names"][name] # type: ignore[no-any-return]
324
+
325
+ errors: dict[str, object] = {}
326
+ for class_name, class_ in module.__dict__.items():
327
+ if not isinstance(class_, type):
328
+ continue
329
+ if module_name == "trio.socket" and class_name in dir(stdlib_socket):
330
+ continue
331
+
332
+ # Ignore classes that don't use attrs, they only define their members once
333
+ # __init__ is called (and reason they don't use attrs is because they're going
334
+ # to be reimplemented in pytest).
335
+ # Not 100% that's the case, and it works locally, so whatever /shrug
336
+ if module_name == "trio.testing" and class_name in ("_RaisesGroup", "_Matcher"):
337
+ continue
338
+
339
+ # dir() and inspect.getmembers doesn't display properties from the metaclass
340
+ # also ignore some dunder methods that tend to differ but are of no consequence
341
+ ignore_names = set(dir(type(class_))) | {
342
+ "__annotations__",
343
+ "__attrs_attrs__",
344
+ "__attrs_own_setattr__",
345
+ "__callable_proto_members_only__",
346
+ "__class_getitem__",
347
+ "__final__",
348
+ "__getstate__",
349
+ "__match_args__",
350
+ "__order__",
351
+ "__orig_bases__",
352
+ "__parameters__",
353
+ "__protocol_attrs__",
354
+ "__setstate__",
355
+ "__slots__",
356
+ "__weakref__",
357
+ # ignore errors about dunders inherited from stdlib that tools might
358
+ # not see
359
+ "__copy__",
360
+ "__deepcopy__",
361
+ }
362
+
363
+ if type(class_) is type:
364
+ # C extension classes don't have these dunders, but Python classes do
365
+ ignore_names.add("__firstlineno__")
366
+ ignore_names.add("__static_attributes__")
367
+
368
+ # inspect.getmembers sees `name` and `value` in Enums, otherwise
369
+ # it behaves the same way as `dir`
370
+ # runtime_names = no_underscores(dir(class_))
371
+ runtime_names = (
372
+ no_hidden(x[0] for x in inspect.getmembers(class_)) - ignore_names
373
+ )
374
+
375
+ if tool == "jedi":
376
+ try:
377
+ import jedi
378
+ except ImportError as error:
379
+ skip_if_optional_else_raise(error)
380
+
381
+ script = jedi.Script(
382
+ f"from {module_name} import {class_name}; {class_name}.",
383
+ )
384
+ completions = script.complete()
385
+ static_names = no_hidden(c.name for c in completions) - ignore_names
386
+
387
+ elif tool == "mypy":
388
+ # load the cached type information
389
+ cached_type_info = cache_json["names"][class_name]
390
+ assert (
391
+ "node" not in cached_type_info
392
+ ), "previously this was an 'if' but it seems it's no longer possible for this cache to contain 'node', if this assert raises for you please let us know!"
393
+ cached_type_info = lookup_symbol(cached_type_info["cross_ref"])
394
+
395
+ assert "node" in cached_type_info
396
+ node = cached_type_info["node"]
397
+ static_names = no_hidden(
398
+ k for k in node.get("names", ()) if not k.startswith(".")
399
+ )
400
+ for symbol in node["mro"][1:]:
401
+ node = lookup_symbol(symbol)["node"]
402
+ static_names |= no_hidden(
403
+ k for k in node.get("names", ()) if not k.startswith(".")
404
+ )
405
+ static_names -= ignore_names
406
+
407
+ else: # pragma: no cover
408
+ raise AssertionError("unknown tool")
409
+
410
+ missing = runtime_names - static_names
411
+ extra = static_names - runtime_names
412
+
413
+ # using .remove() instead of .delete() to get an error in case they start not
414
+ # being missing
415
+
416
+ if (
417
+ tool == "jedi"
418
+ and BaseException in class_.__mro__
419
+ and sys.version_info >= (3, 11)
420
+ ):
421
+ missing.remove("add_note")
422
+
423
+ if (
424
+ tool == "mypy"
425
+ and BaseException in class_.__mro__
426
+ and sys.version_info >= (3, 11)
427
+ ):
428
+ extra.remove("__notes__")
429
+
430
+ if tool == "mypy" and attrs.has(class_):
431
+ # e.g. __trio__core__run_CancelScope_AttrsAttributes__
432
+ before = len(extra)
433
+ extra = {e for e in extra if not e.endswith("AttrsAttributes__")}
434
+ assert len(extra) == before - 1
435
+
436
+ if attrs.has(class_):
437
+ # dynamically created attribute by attrs?
438
+ missing.remove("__attrs_props__")
439
+
440
+ # dir does not see `__signature__` on enums until 3.14
441
+ if (
442
+ tool == "mypy"
443
+ and enum.Enum in class_.__mro__
444
+ and sys.version_info >= (3, 12)
445
+ and sys.version_info < (3, 14)
446
+ ):
447
+ extra.remove("__signature__")
448
+
449
+ # TODO: this *should* be visible via `dir`!!
450
+ if tool == "mypy" and class_ == trio.Nursery:
451
+ extra.remove("cancel_scope")
452
+
453
+ # These are (mostly? solely?) *runtime* attributes, often set in
454
+ # __init__, which doesn't show up with dir() or inspect.getmembers,
455
+ # but we get them in the way we query mypy & jedi
456
+ EXTRAS = {
457
+ trio.DTLSChannel: {"peer_address", "endpoint"},
458
+ trio.DTLSEndpoint: {"socket", "incoming_packets_buffer"},
459
+ trio.Process: {"args", "pid", "stderr", "stdin", "stdio", "stdout"},
460
+ trio.SSLListener: {"transport_listener"},
461
+ trio.SSLStream: {"transport_stream"},
462
+ trio.SocketListener: {"socket"},
463
+ trio.SocketStream: {"socket"},
464
+ trio.testing.MemoryReceiveStream: {"close_hook", "receive_some_hook"},
465
+ trio.testing.MemorySendStream: {
466
+ "close_hook",
467
+ "send_all_hook",
468
+ "wait_send_all_might_not_block_hook",
469
+ },
470
+ }
471
+ if tool == "mypy" and class_ in EXTRAS:
472
+ before = len(extra)
473
+ extra -= EXTRAS[class_]
474
+ assert len(extra) == before - len(EXTRAS[class_])
475
+
476
+ # TODO: why is this? Is it a problem?
477
+ # see https://github.com/python-trio/trio/pull/2631#discussion_r1185615916
478
+ if class_ == trio.StapledStream:
479
+ extra.remove("receive_stream")
480
+ extra.remove("send_stream")
481
+
482
+ # I have not researched why these are missing, should maybe create an issue
483
+ # upstream with jedi
484
+ if tool == "jedi" and sys.version_info >= (3, 11):
485
+ if class_ in (
486
+ trio.DTLSChannel,
487
+ trio.MemoryReceiveChannel,
488
+ trio.MemorySendChannel,
489
+ trio.SSLListener,
490
+ trio.SocketListener,
491
+ ):
492
+ missing.remove("__aenter__")
493
+ missing.remove("__aexit__")
494
+ if class_ in (trio.DTLSChannel, trio.MemoryReceiveChannel):
495
+ missing.remove("__aiter__")
496
+ missing.remove("__anext__")
497
+
498
+ if class_ in (trio.Path, trio.WindowsPath, trio.PosixPath):
499
+ # These are from inherited subclasses.
500
+ missing -= PurePath.__dict__.keys()
501
+ # These are unix-only.
502
+ if tool == "mypy" and sys.platform == "win32":
503
+ missing -= {"owner", "is_mount", "group"}
504
+ if tool == "jedi" and sys.platform == "win32":
505
+ extra -= {"owner", "is_mount", "group"}
506
+
507
+ # not sure why jedi in particular ignores this (static?) method in 3.13
508
+ if (
509
+ tool == "jedi"
510
+ and sys.version_info[:2] == (3, 13)
511
+ and class_ in (trio.Path, trio.WindowsPath, trio.PosixPath)
512
+ ):
513
+ missing.remove("with_segments")
514
+
515
+ # tuple subclasses are weird
516
+ if issubclass(class_, tuple):
517
+ extra.remove("__reversed__")
518
+ missing.remove("__getnewargs__")
519
+
520
+ if sys.version_info >= (3, 13) and attrs.has(class_):
521
+ missing.remove("__replace__")
522
+
523
+ if sys.version_info >= (3, 14):
524
+ # these depend on whether a class has processed deferred annotations.
525
+ # (which might or might not happen and we don't know)
526
+ missing.discard("__annotate_func__")
527
+ missing.discard("__annotations_cache__")
528
+
529
+ if missing or extra: # pragma: no cover
530
+ errors[f"{module_name}.{class_name}"] = {
531
+ "missing": missing,
532
+ "extra": extra,
533
+ }
534
+
535
+ # `assert not errors` will not print the full content of errors, even with
536
+ # `--verbose`, so we manually print it
537
+ if errors: # pragma: no cover
538
+ from pprint import pprint
539
+
540
+ print(f"\n{tool} can't see the following symbols in {module_name}:")
541
+ pprint(errors)
542
+ assert not errors
543
+
544
+
545
+ def test_nopublic_is_final() -> None:
546
+ """Check all NoPublicConstructor classes are also @final."""
547
+ assert class_is_final(_util.NoPublicConstructor) # This is itself final.
548
+
549
+ for module in ALL_MODULES:
550
+ for class_ in module.__dict__.values():
551
+ if isinstance(class_, _util.NoPublicConstructor):
552
+ assert class_is_final(class_)
553
+
554
+
555
+ def test_classes_are_final() -> None:
556
+ # Sanity checks.
557
+ assert not class_is_final(object)
558
+ assert class_is_final(bool)
559
+
560
+ for module in PUBLIC_MODULES:
561
+ for name, class_ in module.__dict__.items():
562
+ if not isinstance(class_, type):
563
+ continue
564
+ # Deprecated classes are exported with a leading underscore
565
+ if name.startswith("_"): # pragma: no cover
566
+ continue
567
+
568
+ # Abstract classes can be subclassed, because that's the whole
569
+ # point of ABCs
570
+ if inspect.isabstract(class_):
571
+ continue
572
+ # Same with protocols, but only direct children.
573
+ if Protocol in class_.__bases__ or Protocol_ext in class_.__bases__:
574
+ continue
575
+ # Exceptions are allowed to be subclassed, because exception
576
+ # subclassing isn't used to inherit behavior.
577
+ if issubclass(class_, BaseException):
578
+ continue
579
+ # These are classes that are conceptually abstract, but
580
+ # inspect.isabstract returns False for boring reasons.
581
+ if class_ is trio.abc.Instrument or class_ is trio.socket.SocketType:
582
+ continue
583
+ # ... insert other special cases here ...
584
+
585
+ # The `Path` class needs to support inheritance to allow `WindowsPath` and `PosixPath`.
586
+ if class_ is trio.Path:
587
+ continue
588
+ # don't care about the *Statistics classes
589
+ if name.endswith("Statistics"):
590
+ continue
591
+
592
+ assert class_is_final(class_)
593
+
594
+
595
+ # Plugin might not be running, especially if running from an installed version.
596
+ @pytest.mark.skipif(
597
+ not hasattr(attrs.field, "trio_modded"),
598
+ reason="Pytest plugin not installed.",
599
+ )
600
+ def test_pyright_recognizes_init_attributes() -> None:
601
+ """Check whether we provide `alias` for all underscore prefixed attributes.
602
+
603
+ Attrs always sets the `alias` attribute on fields, so a pytest plugin is used
604
+ to monkeypatch `field()` to record whether an alias was defined in the metadata.
605
+ See `_trio_check_attrs_aliases`.
606
+ """
607
+ for module in PUBLIC_MODULES:
608
+ for class_ in module.__dict__.values():
609
+ if not attrs.has(class_):
610
+ continue
611
+ if isinstance(class_, _util.NoPublicConstructor):
612
+ continue
613
+
614
+ attributes = [
615
+ attr
616
+ for attr in attrs.fields(class_)
617
+ if attr.init
618
+ if attr.alias
619
+ not in (
620
+ attr.name,
621
+ # trio_original_args may not be present in autoattribs
622
+ attr.metadata.get("trio_original_args", {}).get("alias"),
623
+ )
624
+ ]
625
+
626
+ assert attributes == [], class_