Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions newsfragments/3221.doc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Added docstrings to :class:`MemoryChannelStatistics`, :class:`MemorySendChannel`,
:class:`MemoryReceiveChannel`, and several :class:`SocketStream` methods that
were missing from the API reference.
27 changes: 27 additions & 0 deletions src/trio/_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,19 @@ def __init__(self, max_buffer_size: int | float) -> None: # noqa: PYI041

@attrs.frozen
class MemoryChannelStatistics:
"""Statistics about a memory channel, as returned by
:meth:`MemorySendChannel.statistics` or
:meth:`MemoryReceiveChannel.statistics`.

Attributes:
current_buffer_used: Number of items currently stored in the channel buffer.
max_buffer_size: Maximum number of items allowed in the buffer.
open_send_channels: Number of open :class:`MemorySendChannel` endpoints.
open_receive_channels: Number of open :class:`MemoryReceiveChannel` endpoints.
tasks_waiting_send: Number of tasks blocked in ``send`` across all clones.
tasks_waiting_receive: Number of tasks blocked in ``receive`` across all clones.
"""

current_buffer_used: int
max_buffer_size: int | float
open_send_channels: int
Expand Down Expand Up @@ -152,6 +165,13 @@ def statistics(self) -> MemoryChannelStatistics:
@final
@attrs.define(eq=False, repr=False, slots=False)
class MemorySendChannel(SendChannel[SendType], metaclass=NoPublicConstructor):
"""The send end of a memory channel, as returned by :func:`open_memory_channel`.

Use :meth:`send` to send objects and :meth:`aclose` (or ``async with``)
to close. Call :meth:`clone` to create additional send endpoints that
share the same underlying channel.
"""

_state: MemoryChannelState[SendType]
_closed: bool = False
# This is just the tasks waiting on *this* object. As compared to
Expand Down Expand Up @@ -300,6 +320,13 @@ async def aclose(self) -> None:
@final
@attrs.define(eq=False, repr=False, slots=False)
class MemoryReceiveChannel(ReceiveChannel[ReceiveType], metaclass=NoPublicConstructor):
"""The receive end of a memory channel, as returned by :func:`open_memory_channel`.

Use :meth:`receive` to receive objects and :meth:`aclose` (or ``async with``)
to close. Call :meth:`clone` to create additional receive endpoints that
share the same underlying channel.
"""

_state: MemoryChannelState[ReceiveType]
_closed: bool = False
_tasks: set[trio._core._run.Task] = attrs.Factory(set)
Expand Down
5 changes: 5 additions & 0 deletions src/trio/_highlevel_socket.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ def __init__(self, socket: SocketType) -> None:
self.setsockopt(tsocket.IPPROTO_TCP, tsocket.TCP_NOTSENT_LOWAT, 2**14)

async def send_all(self, data: bytes | bytearray | memoryview) -> None:
"""See :meth:`trio.abc.SendStream.send_all`."""
if self.socket.did_shutdown_SHUT_WR:
raise trio.ClosedResourceError("can't send data after sending EOF")
with self._send_conflict_detector:
Expand All @@ -124,13 +125,15 @@ async def send_all(self, data: bytes | bytearray | memoryview) -> None:
total_sent += sent

async def wait_send_all_might_not_block(self) -> None:
"""See :meth:`trio.abc.HalfCloseableStream.wait_send_all_might_not_block`."""
with self._send_conflict_detector:
if self.socket.fileno() == -1:
raise trio.ClosedResourceError
with _translate_socket_errors_to_stream_errors():
await self.socket.wait_writable()

async def send_eof(self) -> None:
"""See :meth:`trio.abc.HalfCloseableStream.send_eof`."""
with self._send_conflict_detector:
await trio.lowlevel.checkpoint()
# On macOS, calling shutdown a second time raises ENOTCONN, but
Expand All @@ -141,6 +144,7 @@ async def send_eof(self) -> None:
self.socket.shutdown(tsocket.SHUT_WR)

async def receive_some(self, max_bytes: int | None = None) -> bytes:
"""See :meth:`trio.abc.ReceiveStream.receive_some`."""
if max_bytes is None:
max_bytes = DEFAULT_RECEIVE_SIZE
if max_bytes < 1:
Expand All @@ -149,6 +153,7 @@ async def receive_some(self, max_bytes: int | None = None) -> bytes:
return await self.socket.recv(max_bytes)

async def aclose(self) -> None:
"""See :meth:`trio.abc.AsyncResource.aclose`."""
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC this is because of how we configured the autoclass. Can we do that instead?

self.socket.close()
await trio.lowlevel.checkpoint()

Expand Down
Loading