diff --git a/docs/source/reference-lowlevel.rst b/docs/source/reference-lowlevel.rst index 82bd8537d9..7a39180e02 100644 --- a/docs/source/reference-lowlevel.rst +++ b/docs/source/reference-lowlevel.rst @@ -274,18 +274,21 @@ TODO: these are implemented, but are currently more of a sketch than anything real. See `#26 `__. -.. function:: current_kqueue() +.. autofunction:: current_kqueue() -.. function:: wait_kevent(ident, filter, abort_func) +.. autofunction:: wait_kevent(ident, filter, abort_func) :async: -.. function:: monitor_kevent(ident, filter) +.. autofunction:: monitor_kevent(ident, filter) :with: queue Windows-specific API -------------------- +.. note: this is a function and not `autofunction` since it relies on cffi + compiling some things. + .. function:: WaitForSingleObject(handle) :async: @@ -304,20 +307,20 @@ anything real. See `#26 `__ and `#52 `__. -.. function:: register_with_iocp(handle) +.. autofunction:: register_with_iocp(handle) -.. function:: wait_overlapped(handle, lpOverlapped) +.. autofunction:: wait_overlapped(handle, lpOverlapped) :async: -.. function:: write_overlapped(handle, data) +.. autofunction:: write_overlapped(handle, data) :async: -.. function:: readinto_overlapped(handle, data) +.. autofunction:: readinto_overlapped(handle, data) :async: -.. function:: current_iocp() +.. autofunction:: current_iocp() -.. function:: monitor_completion_key() +.. autofunction:: monitor_completion_key() :with: queue diff --git a/pyproject.toml b/pyproject.toml index 6e6a946845..1041959479 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -330,7 +330,8 @@ exclude_also = [ "@overload", 'class .*\bProtocol\b.*\):', "raise NotImplementedError", - 'TODO: test this line' + 'TODO: test this line', + 'if "sphinx.ext.autodoc" in sys.modules:', ] partial_branches = [ "pragma: no branch", diff --git a/src/trio/_core/__init__.py b/src/trio/_core/__init__.py index d21aefb3e2..f9d8068f0c 100644 --- a/src/trio/_core/__init__.py +++ b/src/trio/_core/__init__.py @@ -5,6 +5,7 @@ """ import sys +import typing as _t from ._entry_queue import TrioToken from ._exceptions import ( @@ -73,7 +74,9 @@ from ._unbounded_queue import UnboundedQueue, UnboundedQueueStatistics # Windows imports -if sys.platform == "win32": +if sys.platform == "win32" or ( + not _t.TYPE_CHECKING and "sphinx.ext.autodoc" in sys.modules +): from ._run import ( current_iocp, monitor_completion_key, @@ -83,7 +86,9 @@ write_overlapped, ) # Kqueue imports -elif sys.platform != "linux" and sys.platform != "win32": +if (sys.platform != "linux" and sys.platform != "win32") or ( + not _t.TYPE_CHECKING and "sphinx.ext.autodoc" in sys.modules +): from ._run import current_kqueue, monitor_kevent, wait_kevent del sys # It would be better to import sys as _sys, but mypy does not understand it diff --git a/src/trio/_core/_run.py b/src/trio/_core/_run.py index 1552870ece..c86aee39a8 100644 --- a/src/trio/_core/_run.py +++ b/src/trio/_core/_run.py @@ -2960,6 +2960,12 @@ def in_trio_task() -> bool: return hasattr(GLOBAL_RUN_CONTEXT, "task") +# export everything for the documentation +if "sphinx.ext.autodoc" in sys.modules: + from ._generated_io_epoll import * + from ._generated_io_kqueue import * + from ._generated_io_windows import * + if sys.platform == "win32": from ._generated_io_windows import * from ._io_windows import ( @@ -2985,7 +2991,7 @@ def in_trio_task() -> bool: _patchers = sorted({"eventlet", "gevent"}.intersection(sys.modules)) if _patchers: raise NotImplementedError( - "unsupported platform or primitives trio depends on are monkey-patched out by " + "unsupported platform or primitives Trio depends on are monkey-patched out by " + ", ".join(_patchers), ) diff --git a/src/trio/_highlevel_socket.py b/src/trio/_highlevel_socket.py index c04e66e1bf..142ab11e07 100644 --- a/src/trio/_highlevel_socket.py +++ b/src/trio/_highlevel_socket.py @@ -14,10 +14,18 @@ if TYPE_CHECKING: from collections.abc import Generator - from typing_extensions import Buffer - from ._socket import SocketType +import sys + +if sys.version_info >= (3, 12): + # NOTE: this isn't in the `TYPE_CHECKING` since for some reason + # sphinx doesn't autoreload this module for SocketStream + # (hypothesis: it's our module renaming magic) + from collections.abc import Buffer +elif TYPE_CHECKING: + from typing_extensions import Buffer + # XX TODO: this number was picked arbitrarily. We should do experiments to # tune it. (Or make it dynamic -- one idea is to start small and increase it # 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: ... @overload def setsockopt(self, level: int, option: int, value: None, length: int) -> None: ... + # TODO: rename `length` to `optlen` def setsockopt( self, level: int, diff --git a/src/trio/_path.py b/src/trio/_path.py index 53bd0a700f..a9b2c2e52a 100644 --- a/src/trio/_path.py +++ b/src/trio/_path.py @@ -39,8 +39,18 @@ async def wrapper(*args: P.args, **kwargs: P.kwargs) -> T: update_wrapper(wrapper, wrapped) if wrapped.__doc__: + module = wrapped.__module__ + # these are exported specially from CPython's intersphinx inventory + module = module.replace("pathlib._local", "pathlib") + module = module.replace("pathlib._abc", "pathlib") + + name = wrapped.__qualname__ + name = name.replace( + "PathBase", "Path" + ) # I'm not sure why this is necessary + wrapper.__doc__ = ( - f"Like :meth:`~{wrapped.__module__}.{wrapped.__qualname__}`, but async.\n" + f"Like :meth:`~{module}.{name}`, but async.\n" f"\n" f"{cleandoc(wrapped.__doc__)}\n" ) @@ -245,6 +255,10 @@ def __repr__(self) -> str: full_match = _wrap_method(pathlib.Path.full_match) +if Path.relative_to.__doc__: # pragma: no branch + Path.relative_to.__doc__ = Path.relative_to.__doc__.replace(" `..` ", " ``..`` ") + + @final class PosixPath(Path, pathlib.PurePosixPath): """An async :class:`pathlib.PosixPath` that executes blocking methods in :meth:`trio.to_thread.run_sync`.""" diff --git a/src/trio/_tests/test_unix_pipes.py b/src/trio/_tests/test_unix_pipes.py index e0c2d4e4f2..4d1b08c06e 100644 --- a/src/trio/_tests/test_unix_pipes.py +++ b/src/trio/_tests/test_unix_pipes.py @@ -22,9 +22,6 @@ if posix: from .._unix_pipes import FdStream -else: - with pytest.raises(ImportError): - from .._unix_pipes import FdStream async def make_pipe() -> tuple[FdStream, FdStream]: diff --git a/src/trio/_unix_pipes.py b/src/trio/_unix_pipes.py index a95f761bcc..65a4fa889b 100644 --- a/src/trio/_unix_pipes.py +++ b/src/trio/_unix_pipes.py @@ -15,11 +15,6 @@ assert not TYPE_CHECKING or sys.platform != "win32" -if os.name != "posix": - # We raise an error here rather than gating the import in lowlevel.py - # in order to keep jedi static analysis happy. - raise ImportError - # XX TODO: is this a good number? who knows... it does match the default Linux # pipe capacity though. DEFAULT_RECEIVE_SIZE: FinalType = 65536 diff --git a/src/trio/lowlevel.py b/src/trio/lowlevel.py index bbeab6af17..b6621d47ed 100644 --- a/src/trio/lowlevel.py +++ b/src/trio/lowlevel.py @@ -4,7 +4,6 @@ """ # imports are renamed with leading underscores to indicate they are not part of the public API - import select as _select # static checkers don't understand if importing this as _sys, so it's deleted later @@ -60,8 +59,9 @@ # Uses `from x import y as y` for compatibility with `pyright --verifytypes` (#2625) - -if sys.platform == "win32": +if sys.platform == "win32" or ( + not _t.TYPE_CHECKING and "sphinx.ext.autodoc" in sys.modules +): # Windows symbols from ._core import ( current_iocp as current_iocp, @@ -71,13 +71,21 @@ wait_overlapped as wait_overlapped, write_overlapped as write_overlapped, ) - from ._wait_for_object import WaitForSingleObject as WaitForSingleObject -else: + + # don't let documentation import the actual implementation + if sys.platform == "win32": # pragma: no branch + from ._wait_for_object import WaitForSingleObject as WaitForSingleObject + +if sys.platform != "win32" or ( + not _t.TYPE_CHECKING and "sphinx.ext.autodoc" in sys.modules +): # Unix symbols from ._unix_pipes import FdStream as FdStream # Kqueue-specific symbols - if sys.platform != "linux" and (_t.TYPE_CHECKING or not hasattr(_select, "epoll")): + if ( + sys.platform != "linux" and (_t.TYPE_CHECKING or not hasattr(_select, "epoll")) + ) or (not _t.TYPE_CHECKING and "sphinx.ext.autodoc" in sys.modules): from ._core import ( current_kqueue as current_kqueue, monitor_kevent as monitor_kevent,