Skip to content

Commit 79f685f

Browse files
authored
Allow documentation builds on Windows (#3227)
* Stop raising in `_unix_pipes` * Successfully build docs on Windows on CPython 3.13 * Be a bit stricter about what is allowed for Unix-seeing-Windows * Make use of these new capabilities * Appease type checker * Appease codecov * More codecov appeasement * Migrate to a single excluded line
1 parent 4f54774 commit 79f685f

11 files changed

Lines changed: 69 additions & 32 deletions

File tree

docs/source/reference-lowlevel.rst

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -274,18 +274,21 @@ TODO: these are implemented, but are currently more of a sketch than
274274
anything real. See `#26
275275
<https://github.com/python-trio/trio/issues/26>`__.
276276

277-
.. function:: current_kqueue()
277+
.. autofunction:: current_kqueue()
278278

279-
.. function:: wait_kevent(ident, filter, abort_func)
279+
.. autofunction:: wait_kevent(ident, filter, abort_func)
280280
:async:
281281

282-
.. function:: monitor_kevent(ident, filter)
282+
.. autofunction:: monitor_kevent(ident, filter)
283283
:with: queue
284284

285285

286286
Windows-specific API
287287
--------------------
288288

289+
.. note: this is a function and not `autofunction` since it relies on cffi
290+
compiling some things.
291+
289292
.. function:: WaitForSingleObject(handle)
290293
:async:
291294

@@ -304,20 +307,20 @@ anything real. See `#26
304307
<https://github.com/python-trio/trio/issues/26>`__ and `#52
305308
<https://github.com/python-trio/trio/issues/52>`__.
306309

307-
.. function:: register_with_iocp(handle)
310+
.. autofunction:: register_with_iocp(handle)
308311

309-
.. function:: wait_overlapped(handle, lpOverlapped)
312+
.. autofunction:: wait_overlapped(handle, lpOverlapped)
310313
:async:
311314

312-
.. function:: write_overlapped(handle, data)
315+
.. autofunction:: write_overlapped(handle, data)
313316
:async:
314317

315-
.. function:: readinto_overlapped(handle, data)
318+
.. autofunction:: readinto_overlapped(handle, data)
316319
:async:
317320

318-
.. function:: current_iocp()
321+
.. autofunction:: current_iocp()
319322

320-
.. function:: monitor_completion_key()
323+
.. autofunction:: monitor_completion_key()
321324
:with: queue
322325

323326

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ exclude_also = [
335335
"@overload",
336336
'class .*\bProtocol\b.*\):',
337337
"raise NotImplementedError",
338-
'.*if "sphinx" in sys.modules:',
338+
'.*if "sphinx.ext.autodoc" in sys.modules:',
339339
'TODO: test this line',
340340
'if __name__ == "__main__":',
341341
]

src/trio/_channel.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
from typing_extensions import ParamSpec, Self
3636

3737
P = ParamSpec("P")
38-
elif "sphinx" in sys.modules:
38+
elif "sphinx.ext.autodoc" in sys.modules:
3939
# P needs to exist for Sphinx to parse the type hints successfully.
4040
try:
4141
from typing_extensions import ParamSpec

src/trio/_core/__init__.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"""
66

77
import sys
8+
import typing as _t
89

910
from ._entry_queue import TrioToken
1011
from ._exceptions import (
@@ -73,7 +74,9 @@
7374
from ._unbounded_queue import UnboundedQueue, UnboundedQueueStatistics
7475

7576
# Windows imports
76-
if sys.platform == "win32":
77+
if sys.platform == "win32" or (
78+
not _t.TYPE_CHECKING and "sphinx.ext.autodoc" in sys.modules
79+
):
7780
from ._run import (
7881
current_iocp,
7982
monitor_completion_key,
@@ -83,7 +86,9 @@
8386
write_overlapped,
8487
)
8588
# Kqueue imports
86-
elif sys.platform != "linux" and sys.platform != "win32":
89+
if (sys.platform != "linux" and sys.platform != "win32") or (
90+
not _t.TYPE_CHECKING and "sphinx.ext.autodoc" in sys.modules
91+
):
8792
from ._run import current_kqueue, monitor_kevent, wait_kevent
8893

8994
del sys # It would be better to import sys as _sys, but mypy does not understand it

src/trio/_core/_run.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3080,6 +3080,12 @@ def in_trio_task() -> bool:
30803080
return hasattr(GLOBAL_RUN_CONTEXT, "task")
30813081

30823082

3083+
# export everything for the documentation
3084+
if "sphinx.ext.autodoc" in sys.modules:
3085+
from ._generated_io_epoll import *
3086+
from ._generated_io_kqueue import *
3087+
from ._generated_io_windows import *
3088+
30833089
if sys.platform == "win32":
30843090
from ._generated_io_windows import *
30853091
from ._io_windows import (
@@ -3105,7 +3111,7 @@ def in_trio_task() -> bool:
31053111
_patchers = sorted({"eventlet", "gevent"}.intersection(sys.modules))
31063112
if _patchers:
31073113
raise NotImplementedError(
3108-
"unsupported platform or primitives trio depends on are monkey-patched out by "
3114+
"unsupported platform or primitives Trio depends on are monkey-patched out by "
31093115
+ ", ".join(_patchers),
31103116
)
31113117

src/trio/_highlevel_socket.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,18 @@
1414
if TYPE_CHECKING:
1515
from collections.abc import Generator
1616

17-
from typing_extensions import Buffer
18-
1917
from ._socket import SocketType
2018

19+
import sys
20+
21+
if sys.version_info >= (3, 12):
22+
# NOTE: this isn't in the `TYPE_CHECKING` since for some reason
23+
# sphinx doesn't autoreload this module for SocketStream
24+
# (hypothesis: it's our module renaming magic)
25+
from collections.abc import Buffer
26+
elif TYPE_CHECKING:
27+
from typing_extensions import Buffer
28+
2129
# XX TODO: this number was picked arbitrarily. We should do experiments to
2230
# tune it. (Or make it dynamic -- one idea is to start small and increase it
2331
# if we observe single reads filling up the whole buffer, at least within some
@@ -152,6 +160,7 @@ def setsockopt(self, level: int, option: int, value: int | Buffer) -> None: ...
152160
@overload
153161
def setsockopt(self, level: int, option: int, value: None, length: int) -> None: ...
154162

163+
# TODO: rename `length` to `optlen`
155164
def setsockopt(
156165
self,
157166
level: int,

src/trio/_path.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,18 @@ async def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
3939

4040
update_wrapper(wrapper, wrapped)
4141
if wrapped.__doc__:
42+
module = wrapped.__module__
43+
# these are exported specially from CPython's intersphinx inventory
44+
module = module.replace("pathlib._local", "pathlib")
45+
module = module.replace("pathlib._abc", "pathlib")
46+
47+
name = wrapped.__qualname__
48+
name = name.replace(
49+
"PathBase", "Path"
50+
) # I'm not sure why this is necessary
51+
4252
wrapper.__doc__ = (
43-
f"Like :meth:`~{wrapped.__module__}.{wrapped.__qualname__}`, but async.\n"
53+
f"Like :meth:`~{module}.{name}`, but async.\n"
4454
f"\n"
4555
f"{cleandoc(wrapped.__doc__)}\n"
4656
)
@@ -248,6 +258,10 @@ def as_uri(self) -> str:
248258
return pathlib.Path.as_uri(self)
249259

250260

261+
if Path.relative_to.__doc__: # pragma: no branch
262+
Path.relative_to.__doc__ = Path.relative_to.__doc__.replace(" `..` ", " ``..`` ")
263+
264+
251265
@final
252266
class PosixPath(Path, pathlib.PurePosixPath):
253267
"""An async :class:`pathlib.PosixPath` that executes blocking methods in :meth:`trio.to_thread.run_sync`."""

src/trio/_tests/test_unix_pipes.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,6 @@
2222

2323
if posix:
2424
from .._unix_pipes import FdStream
25-
else:
26-
with pytest.raises(ImportError):
27-
from .._unix_pipes import FdStream
2825

2926

3027
async def make_pipe() -> tuple[FdStream, FdStream]:

src/trio/_timeouts.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ def fail_after(
190190
# Users don't need to know that fail_at & fail_after wraps move_on_at and move_on_after
191191
# and there is no functional difference. So we replace the return value when generating
192192
# documentation.
193-
if "sphinx" in sys.modules: # pragma: no cover
193+
if "sphinx.ext.autodoc" in sys.modules:
194194
import inspect
195195

196196
for c in (fail_at, fail_after):

src/trio/_unix_pipes.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,6 @@
1515

1616
assert not TYPE_CHECKING or sys.platform != "win32"
1717

18-
if os.name != "posix":
19-
# We raise an error here rather than gating the import in lowlevel.py
20-
# in order to keep jedi static analysis happy.
21-
raise ImportError
22-
2318
# XX TODO: is this a good number? who knows... it does match the default Linux
2419
# pipe capacity though.
2520
DEFAULT_RECEIVE_SIZE: FinalType = 65536

0 commit comments

Comments
 (0)