# I/O in Trio

## The abstract Stream API

Trio provides a set of abstract base classes that define a standard interface for unidirectional and bidirectional byte streams.

Why is this useful? Because it lets you write generic protocol implementations that can work over arbitrary transports, and easily create complex transport configurations. Here’s some examples:

- `trio.SocketStream` wraps a raw socket (like a TCP connection over the network), and converts it to the standard stream interface.

- `trio.SSLStream` is a “stream adapter” that can take any object that implements the `trio.abc.Stream` interface, and convert it into an encrypted stream. In Trio the standard way to speak SSL over the network is to wrap an `SSLStream` around a `SocketStream`.

- If you spawn a subprocess, you can get a `SendStream` that lets you write to its stdin, and a `ReceiveStream` that lets you read from its stdout. If for some reason you wanted to speak SSL to a subprocess, you could use a `StapledStream` to combine its stdin/stdout into a single bidirectional `Stream`, and then wrap that in an `SSLStream`:

      ssl_context = ssl.create_default_context()
      ssl_context.check_hostname = False
      s = SSLStream(StapledStream(process.stdin, process.stdout), ssl_context)

- It sometimes happens that you want to connect to an HTTPS server, but you have to go through a web proxy… and the proxy also uses HTTPS. So you end up having to do SSL-on-top-of-SSL. In Trio this is trivial – just wrap your first `SSLStream` in a second `SSLStream`:

      # Get a raw SocketStream connection to the proxy:
      s0 = await open_tcp_stream("proxy", 443)

      # Set up SSL connection to proxy:
      s1 = SSLStream(s0, proxy_ssl_context, server_hostname="proxy")
      # Request a connection to the website
      await s1.send_all(b"CONNECT website:443 / HTTP/1.0\r\n\r\n")
      await check_CONNECT_response(s1)

      # Set up SSL connection to the real website. Notice that s1 is
      # already an SSLStream object, and here we're wrapping a second
      # SSLStream object around it.
      s2 = SSLStream(s1, website_ssl_context, server_hostname="website")
      # Make our request
      await s2.send_all(b"GET /index.html HTTP/1.0\r\n\r\n")
      ...

- The `trio.testing` module provides a set of flexible in-memory stream object implementations, so if you have a protocol implementation to test then you can start two tasks, set up a virtual “socket” connecting them, and then do things like inject random-but-repeatable delays into the connection.

### Abstract base classes

Overview: abstract base classes for I/O
Abstract base class | Inherits from… | Adds these abstract methods… | And these concrete methods. | Example implementations
--- | --- | --- | --- | ---
`AsyncResource` |  | `aclose()` | `__aenter__`, `__aexit__` | Asynchronous file objects
`SendStream` | `AsyncResource` | `send_all()`, `wait_send_all_might_not_block()` |  | `MemorySendStream`
`ReceiveStream` | `AsyncResource` | `receive_some()` | `__aiter__`, `__anext__` | `MemoryReceiveStream`
`Stream` | `SendStream`, `ReceiveStream` |  |  | `SSLStream`
`HalfCloseableStream` | `Stream` | `send_eof()` |  | `SocketStream`, `StapledStream`
`Listener` | `AsyncResource` | `accept()` |  | `SocketListener`, `SSLListener`
`SendChannel` | `AsyncResource` | `send()` |  | `MemorySendChannel`
`ReceiveChannel` | `AsyncResource` | `receive()` | `__aiter__`, `__anext__` | `MemoryReceiveChannel`
`Channel` | `SendChannel`, `ReceiveChannel` |  |  |

class trio.abc.AsyncResource

  A standard interface for resources that needs to be cleaned up, and where that cleanup may require blocking operations.

  This class distinguishes between “graceful” closes, which may perform I/O and thus block, and a “forceful” close, which cannot. For example, cleanly shutting down a TLS-encrypted connection requires sending a “goodbye” message; but if a peer has become non-responsive, then sending this message might block forever, so we may want to just drop the connection instead. Therefore the `aclose()` method is unusual in that it should always close the connection (or at least make its best attempt) even if it fails; failure indicates a failure to achieve grace, not a failure to close the connection.

  Objects that implement this interface can be used as async context managers, i.e., you can write:

      async with create_resource() as some_async_resource:
          ...

  Entering the context manager is synchronous (not a checkpoint); exiting it calls `aclose()`. The default implementations of `__aenter__` and `__aexit__` should be adequate for all subclasses.

  abstractmethod await aclose() → None

    Close this resource, possibly blocking.

    IMPORTANT: This method may block in order to perform a “graceful” shutdown. But, if this fails, then it still must close any underlying resources before returning. An error from this method indicates a failure to achieve grace, not a failure to close the connection.

    For example, suppose we call `aclose()` on a TLS-encrypted connection. This requires sending a “goodbye” message; but if the peer has become non-responsive, then our attempt to send this message might block forever, and eventually time out and be cancelled. In this case the `aclose()` method on `SSLStream` will immediately close the underlying transport stream using `trio.aclose_forcefully()` before raising `Cancelled`.

    If the resource is already closed, then this method should silently succeed.

    Once this method completes, any other pending or future operations on this resource should generally raise `ClosedResourceError`, unless there’s a good reason to do otherwise.

    See also: `trio.aclose_forcefully()`.

await trio.aclose_forcefully(resource: AsyncResource) → None

  Close an async resource or async generator immediately, without blocking to do any graceful cleanup.

  `AsyncResource` objects guarantee that if their `aclose()` method is cancelled, then they will still close the resource (albeit in a potentially ungraceful fashion). `aclose_forcefully()` is a convenience function that exploits this behavior to let you force a resource to be closed without blocking: it works by calling `await resource.aclose()` and then cancelling it immediately.

  Most users won’t need this, but it may be useful on cleanup paths where you can’t afford to block, or if you want to close a resource and don’t care about handling it gracefully. For example, if `SSLStream` encounters an error and cannot perform its own graceful close, then there’s no point in waiting to gracefully shut down the underlying transport either, so it calls `await aclose_forcefully(self.transport_stream)`.

  Note that this function is async, and that it acts as a checkpoint, but unlike most async functions it cannot block indefinitely (at least, assuming the underlying resource object is correctly implemented).

class trio.abc.SendStream

  Bases: `AsyncResource`

  A standard interface for sending data on a byte stream.

  The underlying stream may be unidirectional, or bidirectional. If it’s bidirectional, then you probably want to also implement `ReceiveStream`, which makes your object a `Stream`.

  `SendStream` objects also implement the `AsyncResource` interface, so they can be closed by calling `aclose()` or using an `async with` block.

  If you want to send Python objects rather than raw bytes, see `SendChannel`.

  abstractmethod await send_all(data: bytes | bytearray | memoryview) → None

    Sends the given data through the stream, blocking if necessary.

    Parameters:

      data (bytes, bytearray, or memoryview) – The data to send.

    Raises:

      - trio.BusyResourceError – if another task is already executing a `send_all()`, `wait_send_all_might_not_block()`, or `HalfCloseableStream.send_eof()` on this stream.

      - trio.BrokenResourceError – if something has gone wrong, and the stream is broken.

      - trio.ClosedResourceError – if you previously closed this stream object, or if another task closes this stream object while `send_all()` is running.

    Most low-level operations in Trio provide a guarantee: if they raise `trio.Cancelled`, this means that they had no effect, so the system remains in a known state. This is not true for `send_all()`. If this operation raises `trio.Cancelled` (or any other exception for that matter), then it may have sent some, all, or none of the requested data, and there is no way to know which.

  abstractmethod await wait_send_all_might_not_block() → None

    Block until it’s possible that `send_all()` might not block.

    This method may return early: it’s possible that after it returns, `send_all()` will still block. (In the worst case, if no better implementation is available, then it might always return immediately without blocking. It’s nice to do better than that when possible, though.)

    This method must not return late: if it’s possible for `send_all()` to complete without blocking, then it must return. When implementing it, err on the side of returning early.

    Raises:

      - trio.BusyResourceError – if another task is already executing a `send_all()`, `wait_send_all_might_not_block()`, or `HalfCloseableStream.send_eof()` on this stream.

      - trio.BrokenResourceError – if something has gone wrong, and the stream is broken.

      - trio.ClosedResourceError – if you previously closed this stream object, or if another task closes this stream object while `wait_send_all_might_not_block()` is running.

    Note

    This method is intended to aid in implementing protocols that want to delay choosing which data to send until the last moment. E.g., suppose you’re working on an implementation of a remote display server like VNC, and the network connection is currently backed up so that if you call `send_all()` now then it will sit for 0.5 seconds before actually sending anything. In this case it doesn’t make sense to take a screenshot, then wait 0.5 seconds, and then send it, because the screen will keep changing while you wait; it’s better to wait 0.5 seconds, then take the screenshot, and then send it, because this way the data you deliver will be more up-to-date. Using `wait_send_all_might_not_block()` makes it possible to implement the better strategy.

    If you use this method, you might also want to read up on `TCP_NOTSENT_LOWAT`.

    Further reading:

    - Prioritization Only Works When There’s Pending Data to Prioritize

    - WWDC 2015: Your App and Next Generation Networks: slides, video and transcript

class trio.abc.ReceiveStream

  Bases: `AsyncResource`

  A standard interface for receiving data on a byte stream.

  The underlying stream may be unidirectional, or bidirectional. If it’s bidirectional, then you probably want to also implement `SendStream`, which makes your object a `Stream`.

  `ReceiveStream` objects also implement the `AsyncResource` interface, so they can be closed by calling `aclose()` or using an `async with` block.

  If you want to receive Python objects rather than raw bytes, see `ReceiveChannel`.

  `ReceiveStream` objects can be used in `async for` loops. Each iteration will produce an arbitrary sized chunk of bytes, like calling `receive_some` with no arguments. Every chunk will contain at least one byte, and the loop automatically exits when reaching end-of-file.

  abstractmethod await receive_some(max_bytes: int | None = None) → bytes | bytearray

    Wait until there is data available on this stream, and then return some of it.

    A return value of `b""` (an empty bytestring) indicates that the stream has reached end-of-file. Implementations should be careful that they return `b""` if, and only if, the stream has reached end-of-file!

    Parameters:

      max_bytes (int) – The maximum number of bytes to return. Must be greater than zero. Optional; if omitted, then the stream object is free to pick a reasonable default.

    Returns:

      The data received.

    Return type:

      bytes or bytearray

    Raises:

      - trio.BusyResourceError – if two tasks attempt to call `receive_some()` on the same stream at the same time.

      - trio.BrokenResourceError – if something has gone wrong, and the stream is broken.

      - trio.ClosedResourceError – if you previously closed this stream object, or if another task closes this stream object while `receive_some()` is running.

class trio.abc.Stream

  Bases: `SendStream`, `ReceiveStream`

  A standard interface for interacting with bidirectional byte streams.

  A `Stream` is an object that implements both the `SendStream` and `ReceiveStream` interfaces.

  If implementing this interface, you should consider whether you can go one step further and implement `HalfCloseableStream`.

class trio.abc.HalfCloseableStream

  Bases: `Stream`

  This interface extends `Stream` to also allow closing the send part of the stream without closing the receive part.

  abstractmethod await send_eof() → None

    Send an end-of-file indication on this stream, if possible.

    The difference between `send_eof()` and `aclose()` is that `send_eof()` is a unidirectional end-of-file indication. After you call this method, you shouldn’t try sending any more data on this stream, and your remote peer should receive an end-of-file indication (eventually, after receiving all the data you sent before that). But, they may continue to send data to you, and you can continue to receive it by calling `receive_some()`. You can think of it as calling `aclose()` on just the `SendStream` “half” of the stream object (and in fact that’s literally how `trio.StapledStream` implements it).

    Examples:

    - On a socket, this corresponds to `shutdown(..., SHUT_WR)` (man page).

    - The SSH protocol provides the ability to multiplex bidirectional “channels” on top of a single encrypted connection. A Trio implementation of SSH could expose these channels as `HalfCloseableStream` objects, and calling `send_eof()` would send an `SSH_MSG_CHANNEL_EOF` request (see RFC 4254 §5.3).

    - On an SSL/TLS-encrypted connection, the protocol doesn’t provide any way to do a unidirectional shutdown without closing the connection entirely, so `SSLStream` implements `Stream`, not `HalfCloseableStream`.

    If an EOF has already been sent, then this method should silently succeed.

    Raises:

      - trio.BusyResourceError – if another task is already executing a `send_all()`, `wait_send_all_might_not_block()`, or `send_eof()` on this stream.

      - trio.BrokenResourceError – if something has gone wrong, and the stream is broken.

      - trio.ClosedResourceError – if you previously closed this stream object, or if another task closes this stream object while `send_eof()` is running.

class trio.abc.Listener

  Bases: `AsyncResource`, `Generic`[`T_resource`]

  A standard interface for listening for incoming connections.

  `Listener` objects also implement the `AsyncResource` interface, so they can be closed by calling `aclose()` or using an `async with` block.

  abstractmethod await accept() → T_resource

    Wait until an incoming connection arrives, and then return it.

    Returns:

      An object representing the incoming connection. In practice this is generally some kind of `Stream`, but in principle you could also define a `Listener` that returned, say, channel objects.

    Return type:

      AsyncResource

    Raises:

      - trio.BusyResourceError – if two tasks attempt to call `accept()` on the same listener at the same time.

      - trio.ClosedResourceError – if you previously closed this listener object, or if another task closes this listener object while `accept()` is running.

    Listeners don’t generally raise `BrokenResourceError`, because for listeners there is no general condition of “the network/remote peer broke the connection” that can be handled in a generic way, like there is for streams. Other errors can occur and be raised from `accept()` – for example, if you run out of file descriptors then you might get an `OSError` with its errno set to `EMFILE`.

class trio.abc.SendChannel

  Bases: `AsyncResource`, `Generic`[`SendType`]

  A standard interface for sending Python objects to some receiver.

  `SendChannel` objects also implement the `AsyncResource` interface, so they can be closed by calling `aclose` or using an `async with` block.

  If you want to send raw bytes rather than Python objects, see `SendStream`.

  abstractmethod await send(value: SendType) → None

    Attempt to send an object through the channel, blocking if necessary.

    Parameters:

      value (object) – The object to send.

    Raises:

      - trio.BrokenResourceError – if something has gone wrong, and the channel is broken. For example, you may get this if the receiver has already been closed.

      - trio.ClosedResourceError – if you previously closed this `SendChannel` object, or if another task closes it while `send()` is running.

      - trio.BusyResourceError – some channels allow multiple tasks to call `send` at the same time, but others don’t. If you try to call `send` simultaneously from multiple tasks on a channel that doesn’t support it, then you can get `BusyResourceError`.

class trio.abc.ReceiveChannel

  Bases: `AsyncResource`, `Generic`[`ReceiveType`]

  A standard interface for receiving Python objects from some sender.

  You can iterate over a `ReceiveChannel` using an `async for` loop:

      async for value in receive_channel:
          ...

  This is equivalent to calling `receive()` repeatedly. The loop exits without error when `receive` raises `EndOfChannel`.

  `ReceiveChannel` objects also implement the `AsyncResource` interface, so they can be closed by calling `aclose` or using an `async with` block.

  If you want to receive raw bytes rather than Python objects, see `ReceiveStream`.

  abstractmethod await receive() → ReceiveType

    Attempt to receive an incoming object, blocking if necessary.

    Returns:

      Whatever object was received.

    Return type:

      object

    Raises:

      - trio.EndOfChannel – if the sender has been closed cleanly, and no more objects are coming. This is not an error condition.

      - trio.ClosedResourceError – if you previously closed this `ReceiveChannel` object.

      - trio.BrokenResourceError – if something has gone wrong, and the channel is broken.

      - trio.BusyResourceError – some channels allow multiple tasks to call `receive` at the same time, but others don’t. If you try to call `receive` simultaneously from multiple tasks on a channel that doesn’t support it, then you can get `BusyResourceError`.

class trio.abc.Channel

  Bases: `SendChannel`[`T`], `ReceiveChannel`[`T`]

  A standard interface for interacting with bidirectional channels.

  A `Channel` is an object that implements both the `SendChannel` and `ReceiveChannel` interfaces, so you can both send and receive objects.

### Generic stream tools

Trio currently provides a generic helper for writing servers that listen for connections using one or more `Listener`s, and a generic utility class for working with streams. And if you want to test code that’s written against the streams interface, you should also check out Streams in `trio.testing`.

await trio.serve_listeners(handler: Callable[[StreamT], Awaitable[object]], listeners: list[ListenerT], *, handler_nursery: Nursery | None = None, task_status: TaskStatus[list[ListenerT]] = TASK_STATUS_IGNORED) → NoReturn

  Listen for incoming connections on `listeners`, and for each one start a task running `handler(stream)`.

  Warning

  If `handler` raises an exception, then this function doesn’t do anything special to catch it – so by default the exception will propagate out and crash your server. If you don’t want this, then catch exceptions inside your `handler`, or use a `handler_nursery` object that responds to exceptions in some other way.

  Parameters:

    - handler – An async callable, that will be invoked like `handler_nursery.start_soon(handler, stream)` for each incoming connection.

    - listeners – A list of `Listener` objects. `serve_listeners()` takes responsibility for closing them.

    - handler_nursery – The nursery used to start handlers, or any object with a `start_soon` method. If `None` (the default), then `serve_listeners()` will create a new nursery internally and use that.

    - task_status – This function can be used with `nursery.start`, which will return `listeners`.

  Returns:

    This function never returns unless cancelled.

  Resource handling:

  > If `handler` neglects to close the `stream`, then it will be closed using `trio.aclose_forcefully()`.

  Error handling:

  > Most errors coming from `accept()` are allowed to propagate out (crashing the server in the process). However, some errors – those which indicate that the server is temporarily overloaded – are handled specially. These are `OSError`s with one of the following errnos:

  > - `EMFILE`: process is out of file descriptors

  > - `ENFILE`: system is out of file descriptors

  > - `ENOBUFS`, `ENOMEM`: the kernel hit some sort of memory limitation when trying to create a socket object

  > When `serve_listeners()` gets one of these errors, then it:

  > - Logs the error to the standard library logger `trio.serve_listeners` (level = ERROR, with exception information included). By default this causes it to be printed to stderr.

  > - Waits 100 ms before calling `accept` again, in hopes that the system will recover.

class trio.StapledStream(send_stream: SendStreamT, receive_stream: ReceiveStreamT)

  Bases: `HalfCloseableStream`, `Generic`[`SendStreamT`, `ReceiveStreamT`]

  This class staples together two unidirectional streams to make single bidirectional stream.

  Parameters:

    - send_stream (SendStream) – The stream to use for sending.

    - receive_stream (ReceiveStream) – The stream to use for receiving.

  Example

  A silly way to make a stream that echoes back whatever you write to it:

      left, right = trio.testing.memory_stream_pair()
      echo_stream = StapledStream(SocketStream(left), SocketStream(right))
      await echo_stream.send_all(b"x")
      assert await echo_stream.receive_some() == b"x"

  `StapledStream` objects implement the methods in the `HalfCloseableStream` interface. They also have two additional public attributes:

  send_stream

    The underlying `SendStream`. `send_all()` and `wait_send_all_might_not_block()` are delegated to this object.

  receive_stream

    The underlying `ReceiveStream`. `receive_some()` is delegated to this object.

  await aclose() → None

    Calls `aclose` on both underlying streams.

  await receive_some(max_bytes: int | None = None) → bytes

    Calls `self.receive_stream.receive_some`.

  await send_all(data: bytes | bytearray | memoryview) → None

    Calls `self.send_stream.send_all`.

  await send_eof() → None

    Shuts down the send side of the stream.

    If `self.send_stream.send_eof()` exists, then this calls it. Otherwise, this calls `self.send_stream.aclose()`.

  await wait_send_all_might_not_block() → None

    Calls `self.send_stream.wait_send_all_might_not_block`.

### Sockets and networking

The high-level network interface is built on top of our stream abstraction.

await trio.open_tcp_stream(host: str | bytes, port: int, *, happy_eyeballs_delay: float | None = 0.25, local_address: str | None = None) → SocketStream

  Connect to the given host and port over TCP.

  If the given `host` has multiple IP addresses associated with it, then we have a problem: which one do we use?

  One approach would be to attempt to connect to the first one, and then if that fails, attempt to connect to the second one … until we’ve tried all of them. But the problem with this is that if the first IP address is unreachable (for example, because it’s an IPv6 address and our network discards IPv6 packets), then we might end up waiting tens of seconds for the first connection attempt to timeout before we try the second address.

  Another approach would be to attempt to connect to all of the addresses at the same time, in parallel, and then use whichever connection succeeds first, abandoning the others. This would be fast, but create a lot of unnecessary load on the network and the remote server.

  This function strikes a balance between these two extremes: it works its way through the available addresses one at a time, like the first approach; but, if `happy_eyeballs_delay` seconds have passed and it’s still waiting for an attempt to succeed or fail, then it gets impatient and starts the next connection attempt in parallel. As soon as any one connection attempt succeeds, all the other attempts are cancelled. This avoids unnecessary load because most connections will succeed after just one or two attempts, but if one of the addresses is unreachable then it doesn’t slow us down too much.

  This is known as a “happy eyeballs” algorithm, and our particular variant is modelled after how Chrome connects to webservers; see RFC 6555 for more details.

  Parameters:

    - host (str or bytes) – The host to connect to. Can be an IPv4 address, IPv6 address, or a hostname.

    - port (int) – The port to connect to.

    - happy_eyeballs_delay (float or None) – How many seconds to wait for each connection attempt to succeed or fail before getting impatient and starting another one in parallel. Set to `None` if you want to limit to only one connection attempt at a time (like `socket.create_connection()`). Default: 0.25 (250 ms).

    - local_address (None or str) –

      The local IP address or hostname to use as the source for outgoing connections. If `None`, we let the OS pick the source IP.

      This is useful in some exotic networking configurations where your host has multiple IP addresses, and you want to force the use of a specific one.

      Note that if you pass an IPv4 `local_address`, then you won’t be able to connect to IPv6 hosts, and vice-versa. If you want to take advantage of this to force the use of IPv4 or IPv6 without specifying an exact source address, you can use the IPv4 wildcard address `local_address="0.0.0.0"`, or the IPv6 wildcard address `local_address="::"`.

  Returns:

    a `Stream` connected to the given server.

  Return type:

    SocketStream

  Raises:

    OSError – if the connection fails.

  See also

  open_ssl_over_tcp_stream

await trio.serve_tcp(handler: Callable[[trio.SocketStream], Awaitable[object]], port: int, *, host: str | bytes | None = None, backlog: int | None = None, handler_nursery: trio.Nursery | None = None, task_status: TaskStatus[list[trio.SocketListener]] = TASK_STATUS_IGNORED) → None

  Listen for incoming TCP connections, and for each one start a task running `handler(stream)`.

  This is a thin convenience wrapper around `open_tcp_listeners()` and `serve_listeners()` – see them for full details.

  Warning

  If `handler` raises an exception, then this function doesn’t do anything special to catch it – so by default the exception will propagate out and crash your server. If you don’t want this, then catch exceptions inside your `handler`, or use a `handler_nursery` object that responds to exceptions in some other way.

  When used with `nursery.start` you get back the newly opened listeners. So, for example, if you want to start a server in your test suite and then connect to it to check that it’s working properly, you can use something like:

      from trio import SocketListener, SocketStream
      from trio.testing import open_stream_to_socket_listener

      async with trio.open_nursery() as nursery:
          listeners: list[SocketListener] = await nursery.start(serve_tcp, handler, 0)
          client_stream: SocketStream = await open_stream_to_socket_listener(listeners[0])

          # Then send and receive data on 'client_stream', for example:
          await client_stream.send_all(b"GET / HTTP/1.0\r\n\r\n")

  This avoids several common pitfalls:

  1. It lets the kernel pick a random open port, so your test suite doesn’t depend on any particular port being open.

  2. It waits for the server to be accepting connections on that port before `start` returns, so there’s no race condition where the incoming connection arrives before the server is ready.

  3. It uses the Listener object to find out which port was picked, so it can connect to the right place.

  Parameters:

    - handler – The handler to start for each incoming connection. Passed to `serve_listeners()`.

    - port – The port to listen on. Use 0 to let the kernel pick an open port. Passed to `open_tcp_listeners()`.

    - host (str, bytes, or None) – The host interface to listen on; use `None` to bind to the wildcard address. Passed to `open_tcp_listeners()`.

    - backlog – The listen backlog, or None to have a good default picked. Passed to `open_tcp_listeners()`.

    - handler_nursery – The nursery to start handlers in, or None to use an internal nursery. Passed to `serve_listeners()`.

    - task_status – This function can be used with `nursery.start`.

  Returns:

    This function only returns when cancelled.

await trio.open_ssl_over_tcp_stream(host: str | bytes, port: int, *, https_compatible: bool = False, ssl_context: ssl.SSLContext | None = None, happy_eyeballs_delay: float | None = 0.25) → trio.SSLStream[SocketStream]

  Make a TLS-encrypted Connection to the given host and port over TCP.

  This is a convenience wrapper that calls `open_tcp_stream()` and wraps the result in an `SSLStream`.

  This function does not perform the TLS handshake; you can do it manually by calling `do_handshake()`, or else it will be performed automatically the first time you send or receive data.

  Parameters:

    - host (bytes or str) – The host to connect to. We require the server to have a TLS certificate valid for this hostname.

    - port (int) – The port to connect to.

    - https_compatible (bool) – Set this to True if you’re connecting to a web server. See `SSLStream` for details. Default: False.

    - ssl_context (`SSLContext` or None) – The SSL context to use. If None (the default), `ssl.create_default_context()` will be called to create a context.

    - happy_eyeballs_delay (float) – See `open_tcp_stream()`.

  Returns:

    the encrypted connection to the server.

  Return type:

    trio.SSLStream

await trio.serve_ssl_over_tcp(handler: Callable[[trio.SSLStream[SocketStream]], Awaitable[object]], port: int, ssl_context: ssl.SSLContext, *, host: str | bytes | None = None, https_compatible: bool = False, backlog: int | None = None, handler_nursery: trio.Nursery | None = None, task_status: trio.TaskStatus[list[trio.SSLListener[SocketStream]]] = TASK_STATUS_IGNORED) → NoReturn

  Listen for incoming TCP connections, and for each one start a task running `handler(stream)`.

  This is a thin convenience wrapper around `open_ssl_over_tcp_listeners()` and `serve_listeners()` – see them for full details.

  Warning

  If `handler` raises an exception, then this function doesn’t do anything special to catch it – so by default the exception will propagate out and crash your server. If you don’t want this, then catch exceptions inside your `handler`, or use a `handler_nursery` object that responds to exceptions in some other way.

  When used with `nursery.start` you get back the newly opened listeners. See the documentation for `serve_tcp()` for an example where this is useful.

  Parameters:

    - handler – The handler to start for each incoming connection. Passed to `serve_listeners()`.

    - port (int) – The port to listen on. Use 0 to let the kernel pick an open port. Ultimately passed to `open_tcp_listeners()`.

    - ssl_context (SSLContext) – The SSL context to use for all incoming connections. Passed to `open_ssl_over_tcp_listeners()`.

    - host (str, bytes, or None) – The address to bind to; use `None` to bind to the wildcard address. Ultimately passed to `open_tcp_listeners()`.

    - https_compatible (bool) – Set this to True if you want to use “HTTPS-style” TLS. See `SSLStream` for details.

    - backlog (int or None) – See `SSLStream` for details.

    - handler_nursery – The nursery to start handlers in, or None to use an internal nursery. Passed to `serve_listeners()`.

    - task_status – This function can be used with `nursery.start`.

  Returns:

    This function only returns when cancelled.

await trio.open_unix_socket(filename: str | bytes | PathLike[str] | PathLike[bytes]) → SocketStream

  Opens a connection to the specified Unix domain socket.

  You must have read/write permission on the specified file to connect.

  Parameters:

    filename (str or bytes) – The filename to open the connection to.

  Returns:

    a `Stream` connected to the given file.

  Return type:

    SocketStream

  Raises:

    - OSError – If the socket file could not be connected to.

    - RuntimeError – If AF_UNIX sockets are not supported.

class trio.SocketStream(socket: SocketType)

  Bases: `HalfCloseableStream`

  An implementation of the `trio.abc.HalfCloseableStream` interface based on a raw network socket.

  Parameters:

    socket – The Trio socket object to wrap. Must have type `SOCK_STREAM`, and be connected.

  By default for TCP sockets, `SocketStream` enables `TCP_NODELAY`, and (on platforms where it’s supported) enables `TCP_NOTSENT_LOWAT` with a reasonable buffer size (currently 16 KiB) – see issue #72 for discussion. You can of course override these defaults by calling `setsockopt()`.

  Once a `SocketStream` object is constructed, it implements the full `trio.abc.HalfCloseableStream` interface. In addition, it provides a few extra features:

  socket

    The Trio socket object that this stream wraps.

  await aclose() → None
  getsockopt(level: int, option: int, buffersize: int = 0) → int | bytes

    Check the current value of an option on the underlying socket.

    See `socket.socket.getsockopt()` for details.

  await receive_some(max_bytes: int | None = None) → bytes
  await send_all(data: bytes | bytearray | memoryview) → None
  await send_eof() → None
  setsockopt(level: int, option: int, value: int | Buffer | None, length: int | None = None) → None

    Set an option on the underlying socket.

    See `socket.socket.setsockopt()` for details.

  await wait_send_all_might_not_block() → None

class trio.SocketListener(socket: SocketType)

  Bases: `Listener`[`SocketStream`]

  A `Listener` that uses a listening socket to accept incoming connections as `SocketStream` objects.

  Parameters:

    socket – The Trio socket object to wrap. Must have type `SOCK_STREAM`, and be listening.

  Note that the `SocketListener` “takes ownership” of the given socket; closing the `SocketListener` will also close the socket.

  socket

    The Trio socket object that this stream wraps.

  await accept() → SocketStream

    Accept an incoming connection.

    Returns:

      `SocketStream`

    Raises:

      - OSError – if the underlying call to `accept` raises an unexpected error.

      - ClosedResourceError – if you already closed the socket.

    This method handles routine errors like `ECONNABORTED`, but passes other errors on to its caller. In particular, it does not make any special effort to handle resource exhaustion errors like `EMFILE`, `ENFILE`, `ENOBUFS`, `ENOMEM`.

  await aclose() → None

    Close this listener and its underlying socket.

await trio.open_tcp_listeners(port: int, *, host: str | bytes | None = None, backlog: int | None = None) → list[SocketListener]

  Create `SocketListener` objects to listen for TCP connections.

  Parameters:

    - port (int) –

      The port to listen on.

      If you use 0 as your port, then the kernel will automatically pick an arbitrary open port. But be careful: if you use this feature when binding to multiple IP addresses, then each IP address will get its own random port, and the returned listeners will probably be listening on different ports. In particular, this will happen if you use `host=None` – which is the default – because in this case `open_tcp_listeners()` will bind to both the IPv4 wildcard address (`0.0.0.0`) and also the IPv6 wildcard address (`::`).

    - host (str, bytes, or None) –

      The local interface to bind to. This is passed to `getaddrinfo()` with the `AI_PASSIVE` flag set.

      If you want to bind to the wildcard address on both IPv4 and IPv6, in order to accept connections on all available interfaces, then pass `None`. This is the default.

      If you have a specific interface you want to bind to, pass its IP address or hostname here. If a hostname resolves to multiple IP addresses, this function will open one listener on each of them.

      If you want to use only IPv4, or only IPv6, but want to accept on all interfaces, pass the family-specific wildcard address: `"0.0.0.0"` for IPv4-only and `"::"` for IPv6-only.

    - backlog (int or None) – The listen backlog to use. If you leave this as `None` then Trio will pick a good default. (Currently: whatever your system has configured as the maximum backlog.)

  Returns:

    list of `SocketListener`

  Raises:

    TypeError –

await trio.open_ssl_over_tcp_listeners(port: int, ssl_context: ssl.SSLContext, *, host: str | bytes | None = None, https_compatible: bool = False, backlog: int | None = None) → list[trio.SSLListener[SocketStream]]

  Start listening for SSL/TLS-encrypted TCP connections to the given port.

  Parameters:

    - port (int) – The port to listen on. See `open_tcp_listeners()`.

    - ssl_context (SSLContext) – The SSL context to use for all incoming connections.

    - host (str, bytes, or None) – The address to bind to; use `None` to bind to the wildcard address. See `open_tcp_listeners()`.

    - https_compatible (bool) – See `SSLStream` for details.

    - backlog (int or None) – See `open_tcp_listeners()` for details.

### SSL / TLS support

Trio provides SSL/TLS support based on the standard library `ssl` module. Trio’s `SSLStream` and `SSLListener` take their configuration from a `ssl.SSLContext`, which you can create using `ssl.create_default_context()` and customize using the other constants and functions in the `ssl` module.

Warning

Avoid instantiating `ssl.SSLContext` directly. A newly constructed `SSLContext` has less secure defaults than one returned by `ssl.create_default_context()`.

Instead of using `ssl.SSLContext.wrap_socket()`, you create a `SSLStream`:

class trio.SSLStream(transport_stream: T_Stream, ssl_context: SSLContext, *, server_hostname: str | bytes | None = None, server_side: bool = False, https_compatible: bool = False)

  Bases: `Stream`, `Generic`[`T_Stream`]

  Encrypted communication using SSL/TLS.

  `SSLStream` wraps an arbitrary `Stream`, and allows you to perform encrypted communication over it using the usual `Stream` interface. You pass regular data to `send_all()`, then it encrypts it and sends the encrypted data on the underlying `Stream`; `receive_some()` takes encrypted data out of the underlying `Stream` and decrypts it before returning it.

  You should read the standard library’s `ssl` documentation carefully before attempting to use this class, and probably other general documentation on SSL/TLS as well. SSL/TLS is subtle and quick to anger. Really. I’m not kidding.

  Parameters:

    - transport_stream (Stream) – The stream used to transport encrypted data. Required.

    - ssl_context (SSLContext) – The `SSLContext` used for this connection. Required. Usually created by calling `ssl.create_default_context()`.

    - server_hostname (str, bytes, or None) – The name of the server being connected to. Used for SNI and for validating the server’s certificate (if hostname checking is enabled). This is effectively mandatory for clients, and actually mandatory if `ssl_context.check_hostname` is `True`.

    - server_side (bool) – Whether this stream is acting as a client or server. Defaults to False, i.e. client mode.

    - https_compatible (bool) –

      There are two versions of SSL/TLS commonly encountered in the wild: the standard version, and the version used for HTTPS (HTTP-over-SSL/TLS).

      Standard-compliant SSL/TLS implementations always send a cryptographically signed `close_notify` message before closing the connection. This is important because if the underlying transport were simply closed, then there wouldn’t be any way for the other side to know whether the connection was intentionally closed by the peer that they negotiated a cryptographic connection to, or by some man-in-the-middle attacker who can’t manipulate the cryptographic stream, but can manipulate the transport layer (a so-called “truncation attack”).

      However, this part of the standard is widely ignored by real-world HTTPS implementations, which means that if you want to interoperate with them, then you NEED to ignore it too.

      Fortunately this isn’t as bad as it sounds, because the HTTP protocol already includes its own equivalent of `close_notify`, so doing this again at the SSL/TLS level is redundant. But not all protocols do! Therefore, by default Trio implements the safer standard-compliant version (`https_compatible=False`). But if you’re speaking HTTPS or some other protocol where `close_notify`s are commonly skipped, then you should set `https_compatible=True`; with this setting, Trio will neither expect nor send `close_notify` messages.

      If you have code that was written to use `ssl.SSLSocket` and now you’re porting it to Trio, then it may be useful to know that a difference between `SSLStream` and `ssl.SSLSocket` is that `SSLSocket` implements the `https_compatible=True` behavior by default.

  transport_stream

    The underlying transport stream that was passed to `__init__`. An example of when this would be useful is if you’re using `SSLStream` over a `SocketStream` and want to call the `SocketStream`’s `setsockopt()` method.

    Type:

      trio.abc.Stream

  Internally, this class is implemented using an instance of `ssl.SSLObject`, and all of `SSLObject`’s methods and attributes are re-exported as methods and attributes on this class. However, there is one difference: `SSLObject` has several methods that return information about the encrypted connection, like `cipher()` or `selected_alpn_protocol()`. If you call them before the handshake, when they can’t possibly return useful data, then `ssl.SSLObject` returns None, but `trio.SSLStream` raises `NeedHandshakeError`.

  This also means that if you register a SNI callback using `sni_callback`, then the first argument your callback receives will be a `ssl.SSLObject`.

  await aclose() → None

    Gracefully shut down this connection, and close the underlying transport.

    If `https_compatible` is False (the default), then this attempts to first send a `close_notify` and then close the underlying stream by calling its `aclose()` method.

    If `https_compatible` is set to True, then this simply closes the underlying stream and marks this stream as closed.

  await do_handshake() → None

    Ensure that the initial handshake has completed.

    The SSL protocol requires an initial handshake to exchange certificates, select cryptographic keys, and so forth, before any actual data can be sent or received. You don’t have to call this method; if you don’t, then `SSLStream` will automatically perform the handshake as needed, the first time you try to send or receive data. But if you want to trigger it manually – for example, because you want to look at the peer’s certificate before you start talking to them – then you can call this method.

    If the initial handshake is already in progress in another task, this waits for it to complete and then returns.

    If the initial handshake has already completed, this returns immediately without doing anything (except executing a checkpoint).

    Warning

    If this method is cancelled, then it may leave the `SSLStream` in an unusable state. If this happens then any future attempt to use the object will raise `trio.BrokenResourceError`.

  await receive_some(max_bytes: int | None = None) → bytes | bytearray

    Read some data from the underlying transport, decrypt it, and return it.

    See `trio.abc.ReceiveStream.receive_some()` for details.

    Warning

    If this method is cancelled while the initial handshake or a renegotiation are in progress, then it may leave the `SSLStream` in an unusable state. If this happens then any future attempt to use the object will raise `trio.BrokenResourceError`.

  await send_all(data: bytes | bytearray | memoryview) → None

    Encrypt some data and then send it on the underlying transport.

    See `trio.abc.SendStream.send_all()` for details.

    Warning

    If this method is cancelled, then it may leave the `SSLStream` in an unusable state. If this happens then any attempt to use the object will raise `trio.BrokenResourceError`.

  await unwrap() → tuple[Stream, bytes | bytearray]

    Cleanly close down the SSL/TLS encryption layer, allowing the underlying stream to be used for unencrypted communication.

    You almost certainly don’t need this.

    Returns:

      A pair `(transport_stream, trailing_bytes)`, where `transport_stream` is the underlying transport stream, and `trailing_bytes` is a byte string. Since `SSLStream` doesn’t necessarily know where the end of the encrypted data will be, it can happen that it accidentally reads too much from the underlying stream. `trailing_bytes` contains this extra data; you should process it as if it was returned from a call to `transport_stream.receive_some(...)`.

  await wait_send_all_might_not_block() → None

    See `trio.abc.SendStream.wait_send_all_might_not_block()`.

And if you’re implementing a server, you can use `SSLListener`:

class trio.SSLListener(transport_listener: Listener[T_Stream], ssl_context: SSLContext, *, https_compatible: bool = False)

  Bases: `Listener`[`SSLStream`[`T_Stream`]]

  A `Listener` for SSL/TLS-encrypted servers.

  `SSLListener` wraps around another Listener, and converts all incoming connections to encrypted connections by wrapping them in a `SSLStream`.

  Parameters:

    - transport_listener (Listener) – The listener whose incoming connections will be wrapped in `SSLStream`.

    - ssl_context (SSLContext) – The `SSLContext` that will be used for incoming connections.

    - https_compatible (bool) – Passed on to `SSLStream`.

  transport_listener

    The underlying listener that was passed to `__init__`.

    Type:

      trio.abc.Listener

  await accept() → SSLStream[T_Stream]

    Accept the next connection and wrap it in an `SSLStream`.

    See `trio.abc.Listener.accept()` for details.

  await aclose() → None

    Close the transport listener.

Some methods on `SSLStream` raise `NeedHandshakeError` if you call them before the handshake completes:

exception trio.NeedHandshakeError

  Some `SSLStream` methods can’t return any meaningful data until after the handshake. If you call them before the handshake, they raise this error.

### Datagram TLS support

Trio also has support for Datagram TLS (DTLS), which is like TLS but for unreliable UDP connections. This can be useful for applications where TCP’s reliable in-order delivery is problematic, like teleconferencing, latency-sensitive games, and VPNs.

Currently, using DTLS with Trio requires PyOpenSSL. We hope to eventually allow the use of the stdlib `ssl` module as well, but unfortunately that’s not yet possible.

Warning

Note that PyOpenSSL is in many ways lower-level than the `ssl` module – in particular, it currently HAS NO BUILT-IN MECHANISM TO VALIDATE CERTIFICATES. We strongly recommend that you use the service-identity library to validate hostnames and certificates.

class trio.DTLSEndpoint(socket: SocketType, *, incoming_packets_buffer: int = 10)

  A DTLS endpoint.

  A single UDP socket can handle arbitrarily many DTLS connections simultaneously, acting as a client or server as needed. A `DTLSEndpoint` object holds a UDP socket and manages these connections, which are represented as `DTLSChannel` objects.

  Parameters:

    - socket – (trio.socket.SocketType): A `SOCK_DGRAM` socket. If you want to accept incoming connections in server mode, then you should probably bind the socket to some known port.

    - incoming_packets_buffer (int) – Each `DTLSChannel` using this socket has its own buffer that holds incoming packets until you call `receive` to read them. This lets you adjust the size of this buffer. `statistics` lets you check if the buffer has overflowed.

  socket
  incoming_packets_buffer

    Both constructor arguments are also exposed as attributes, in case you need to access them later.

  connect(address: tuple[str, int], ssl_context: OpenSSL.SSL.Context) → DTLSChannel

    Initiate an outgoing DTLS connection.

    Notice that this is a synchronous method. That’s because it doesn’t actually initiate any I/O – it just sets up a `DTLSChannel` object. The actual handshake doesn’t occur until you start using the `DTLSChannel`. This gives you a chance to do further configuration first, like setting MTU etc.

    Parameters:

      - address – The address to connect to. Usually a (host, port) tuple, like `("127.0.0.1", 12345)`.

      - ssl_context (OpenSSL.SSL.Context) – The PyOpenSSL context object to use for this connection.

    Returns:

      DTLSChannel

  await serve(ssl_context: OpenSSL.SSL.Context, async_fn: Callable[[DTLSChannel, Unpack[PosArgsT]], Awaitable[object]], *args: Unpack[PosArgsT], task_status: trio.TaskStatus[None] = TASK_STATUS_IGNORED) → None

    Listen for incoming connections, and spawn a handler for each using an internal nursery.

    Similar to `serve_tcp`, this function never returns until cancelled, or the `DTLSEndpoint` is closed and all handlers have exited.

    Usage commonly looks like:

        async def handler(dtls_channel):
            ...

        async with trio.open_nursery() as nursery:
            await nursery.start(dtls_endpoint.serve, ssl_context, handler)
            # ... do other things here ...

    The `dtls_channel` passed into the handler function has already performed the “cookie exchange” part of the DTLS handshake, so the peer address is trustworthy. But the actual cryptographic handshake doesn’t happen until you start using it, giving you a chance for any last minute configuration, and the option to catch and handle handshake errors.

    Parameters:

      - ssl_context (OpenSSL.SSL.Context) – The PyOpenSSL context object to use for incoming connections.

      - async_fn – The handler function that will be invoked for each incoming connection.

      - *args – Additional arguments to pass to the handler function.

  close() → None

    Close this socket, and all associated DTLS connections.

    This object can also be used as a context manager.

class trio.DTLSChannel(*args: object, **kwargs: object)

  Bases: `Channel`[`bytes`]

  A DTLS connection.

  This class has no public constructor – you get instances by calling `DTLSEndpoint.serve` or `connect`.

  endpoint

    The `DTLSEndpoint` that this connection is using.

  peer_address

    The IP/port of the remote peer that this connection is associated with.

  await do_handshake(*, initial_retransmit_timeout: float = 1.0) → None

    Perform the handshake.

    Calling this is optional – if you don’t, then it will be automatically called the first time you call `send` or `receive`. But calling it explicitly can be useful in case you want to control the retransmit timeout, use a cancel scope to place an overall timeout on the handshake, or catch errors from the handshake specifically.

    It’s safe to call this multiple times, or call it simultaneously from multiple tasks – the first call will perform the handshake, and the rest will be no-ops.

    Parameters:

      initial_retransmit_timeout (float) –

      Since UDP is an unreliable protocol, it’s possible that some of the packets we send during the handshake will get lost. To handle this, DTLS uses a timer to automatically retransmit handshake packets that don’t receive a response. This lets you set the timeout we use to detect packet loss. Ideally, it should be set to ~1.5 times the round-trip time to your peer, but 1 second is a reasonable default. There’s some useful guidance here.

      This is the initial timeout, because if packets keep being lost then Trio will automatically back off to longer values, to avoid overloading the network.

  await send(data: bytes) → None

    Send a packet of data, securely.

  await receive() → bytes

    Fetch the next packet of data from this connection’s peer, waiting if necessary.

    This is safe to call from multiple tasks simultaneously, in case you have some reason to do that. And more importantly, it’s cancellation-safe, meaning that cancelling a call to `receive` will never cause a packet to be lost or corrupt the underlying connection.

  close() → None

    Close this connection.

    `DTLSChannel`s don’t actually own any OS-level resources – the socket is owned by the `DTLSEndpoint`, not the individual connections. So you don’t really have to call this. But it will interrupt any other tasks calling `receive` with a `ClosedResourceError`, and cause future attempts to use this connection to fail.

    You can also use this object as a synchronous or asynchronous context manager.

  await aclose() → None

    Close this connection, but asynchronously.

    This is included to satisfy the `trio.abc.Channel` contract. It’s identical to `close`, but async.

  set_ciphertext_mtu(new_mtu: int) → None

    Tells Trio the largest amount of data that can be sent in a single packet to this peer.

    Trio doesn’t actually enforce this limit – if you pass a huge packet to `send`, then we’ll dutifully encrypt it and attempt to send it. But calling this method does have two useful effects:

    - If called before the handshake is performed, then Trio will automatically fragment handshake messages to fit within the given MTU. It also might fragment them even smaller, if it detects signs of packet loss, so setting this should never be necessary to make a successful connection. But, the packet loss detection only happens after multiple timeouts have expired, so if you have reason to believe that a smaller MTU is required, then you can set this to skip those timeouts and establish the connection more quickly.

    - It changes the value returned from `get_cleartext_mtu`. So if you have some kind of estimate of the network-level MTU, then you can use this to figure out how much overhead DTLS will need for hashes/padding/etc., and how much space you have left for your application data.

    The MTU here is measuring the largest UDP payload you think can be sent, the amount of encrypted data that can be handed to the operating system in a single call to `send`. It should not include IP/UDP headers. Note that OS estimates of the MTU often are link-layer MTUs, so you have to subtract off 28 bytes on IPv4 and 48 bytes on IPv6 to get the ciphertext MTU.

    By default, Trio assumes an MTU of 1472 bytes on IPv4, and 1452 bytes on IPv6, which correspond to the common Ethernet MTU of 1500 bytes after accounting for IP/UDP overhead.

  get_cleartext_mtu() → int

    Returns the largest number of bytes that you can pass in a single call to `send` while still fitting within the network-level MTU.

    See `set_ciphertext_mtu` for more details.

  statistics() → DTLSChannelStatistics

    Returns a `DTLSChannelStatistics` object with statistics about this connection.

class trio.DTLSChannelStatistics(incoming_packets_dropped_in_trio: int)

  Currently this has only one attribute:

  - `incoming_packets_dropped_in_trio` (`int`): Gives a count of the number of incoming packets from this peer that Trio successfully received from the network, but then got dropped because the internal channel buffer was full. If this is non-zero, then you might want to call `receive` more often, or use a larger `incoming_packets_buffer`, or just not worry about it because your UDP-based protocol should be able to handle the occasional lost packet, right?

## Low-level networking with `trio.socket`

The `trio.socket` module provides Trio’s basic low-level networking API. If you’re doing ordinary things with stream-oriented connections over IPv4/IPv6/Unix domain sockets, then you probably want to stick to the high-level API described above. If you want to use UDP, or exotic address families like `AF_BLUETOOTH`, or otherwise get direct access to all the quirky bits of your system’s networking API, then you’re in the right place.

### Top-level exports

Generally, the API exposed by `trio.socket` mirrors that of the standard library `socket` module. Most constants (like `SOL_SOCKET`) and simple utilities (like `inet_aton()`) are simply re-exported unchanged. But there are also some differences, which are described here.

First, Trio provides analogues to all the standard library functions that return socket objects; their interface is identical, except that they’re modified to return Trio socket objects instead:

trio.socket.socket(family=-1, type=-1, proto=-1, fileno=None)

  Create a new Trio socket, like `socket.socket`.

  This function’s behavior can be customized using `set_custom_socket_factory()`.

trio.socket.socketpair(family=None, type=SocketKind.SOCK_STREAM, proto=0)

  Like `socket.socketpair()`, but returns a pair of Trio socket objects.

trio.socket.fromfd(fd, family, type, proto=0)

  Like `socket.fromfd()`, but returns a Trio socket object.

trio.socket.fromshare(data)

  Like `socket.fromshare()`, but returns a Trio socket object.

In addition, there is a new function to directly convert a standard library socket into a Trio socket:

trio.socket.from_stdlib_socket(sock: socket) → SocketType

  Convert a standard library `socket.socket` object into a Trio socket object.

Unlike `socket.socket`, `trio.socket.socket()` is a function, not a class; if you want to check whether an object is a Trio socket, use `isinstance(obj, trio.socket.SocketType)`.

For name lookup, Trio provides the standard functions, but with some changes:

await trio.socket.getaddrinfo(host: bytes | str | None, port: bytes | str | int | None, family: int = 0, type: int = 0, proto: int = 0, flags: int = 0) → list[tuple[AddressFamily, SocketKind, int, str, tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes]]]

  Look up a numeric address given a name.

  Arguments and return values are identical to `socket.getaddrinfo()`, except that this version is async.

  Also, `trio.socket.getaddrinfo()` correctly uses IDNA 2008 to process non-ASCII domain names. (`socket.getaddrinfo()` uses IDNA 2003, which can give the wrong result in some cases and cause you to connect to a different host than the one you intended; see bpo-17305.)

  This function’s behavior can be customized using `set_custom_hostname_resolver()`.

await trio.socket.getnameinfo(sockaddr: tuple[str, int] | tuple[str, int, int, int], flags: int) → tuple[str, str]

  Look up a name given a numeric address.

  Arguments and return values are identical to `socket.getnameinfo()`, except that this version is async.

  This function’s behavior can be customized using `set_custom_hostname_resolver()`.

await trio.socket.getprotobyname(name: str) → int

  Look up a protocol number by name. (Rarely used.)

  Like `socket.getprotobyname()`, but async.

Trio intentionally DOES NOT include some obsolete, redundant, or broken features:

- `gethostbyname()`, `gethostbyname_ex()`, `gethostbyaddr()`: obsolete; use `getaddrinfo()` and `getnameinfo()` instead.

- `getservbyport()`: obsolete and buggy; instead, do:

      _, service_name = await getnameinfo(('127.0.0.1', port), NI_NUMERICHOST)

- `getservbyname()`: obsolete and buggy; instead, do:

      await getaddrinfo(None, service_name)

- `getfqdn()`: obsolete; use `getaddrinfo()` with the `AI_CANONNAME` flag.

- `getdefaulttimeout()`, `setdefaulttimeout()`: instead, use Trio’s standard support for Cancellation and timeouts.

- On Windows, `SO_REUSEADDR` is not exported, because it’s a trap: the name is the same as Unix `SO_REUSEADDR`, but the semantics are different and extremely broken. In the very rare cases where you actually want `SO_REUSEADDR` on Windows, then it can still be accessed from the standard library’s `socket` module.

### Socket objects

class trio.socket.SocketType

  Note

  `trio.socket.SocketType` is an abstract class and cannot be instantiated directly; you get concrete socket objects by calling constructors like `trio.socket.socket()`. However, you can use it to check if an object is a Trio socket via `isinstance(obj, trio.socket.SocketType)`.

  Trio socket objects are overall very similar to the standard library socket objects, with a few important differences:

  First, and most obviously, everything is made “Trio-style”: blocking methods become async methods, and the following attributes are not supported:

  - `setblocking()`: Trio sockets always act like blocking sockets; if you need to read/write from multiple sockets at once, then create multiple tasks.

  - `settimeout()`: see Cancellation and timeouts instead.

  - `makefile()`: Python’s file-like API is synchronous, so it can’t be implemented on top of an async socket.

  - `sendall()`: Could be supported, but you’re better off using the higher-level `SocketStream`, and specifically its `send_all()` method, which also does additional error checking.

  In addition, the following methods are similar to the equivalents in `socket.socket`, but have some Trio-specific quirks:

  await connect()

    Connect the socket to a remote address.

    Similar to `socket.socket.connect()`, except async.

    Warning

    Due to limitations of the underlying operating system APIs, it is not always possible to properly cancel a connection attempt once it has begun. If `connect()` is cancelled, and is unable to abort the connection attempt, then it will:

    1. forcibly close the socket to prevent accidental reuse

    2. raise `Cancelled`.

    tl;dr: if `connect()` is cancelled then the socket is left in an unknown state – possibly open, and possibly closed. The only reasonable thing to do is to close it.

  is_readable()

    Check whether the socket is readable or not.

  sendfile()

    Not implemented yet!

  We also keep track of an extra bit of state, because it turns out to be useful for `trio.SocketStream`:

  did_shutdown_SHUT_WR

    This `bool` attribute is True if you’ve called `sock.shutdown(SHUT_WR)` or `sock.shutdown(SHUT_RDWR)`, and False otherwise.

  The following methods are identical to their equivalents in `socket.socket`, except async, and the ones that take address arguments require pre-resolved addresses:

  - `accept()`

  - `bind()`

  - `recv()`

  - `recv_into()`

  - `recvfrom()`

  - `recvfrom_into()`

  - `recvmsg()` (if available)

  - `recvmsg_into()` (if available)

  - `send()`

  - `sendto()`

  - `sendmsg()` (if available)

  All methods and attributes not mentioned above are identical to their equivalents in `socket.socket`:

  - `family`

  - `type`

  - `proto`

  - `fileno()`

  - `listen()`

  - `getpeername()`

  - `getsockname()`

  - `close()`

  - `shutdown()`

  - `setsockopt()`

  - `getsockopt()`

  - `dup()`

  - `detach()`

  - `share()`

  - `set_inheritable()`

  - `get_inheritable()`

## Asynchronous filesystem I/O

Trio provides built-in facilities for performing asynchronous filesystem operations like reading or renaming a file. Generally, we recommend that you use these instead of Python’s normal synchronous file APIs. But the tradeoffs here are somewhat subtle: sometimes people switch to async I/O, and then they’re surprised and confused when they find it doesn’t speed up their program. The next section explains the theory behind async file I/O, to help you better understand your code’s behavior. Or, if you just want to get started, you can jump down to the API overview.

### Background: Why is async file I/O useful? The answer may surprise you

Many people expect that switching from synchronous file I/O to async file I/O will always make their program faster. This is not true! If we just look at total throughput, then async file I/O might be faster, slower, or about the same, and it depends in a complicated way on things like your exact patterns of disk access, or how much RAM you have. The main motivation for async file I/O is not to improve throughput, but to reduce the frequency of latency glitches.

To understand why, you need to know two things.

First, right now no mainstream operating system offers a generic, reliable, native API for async file or filesystem operations, so we have to fake it by using threads (specifically, `trio.to_thread.run_sync()`). This is cheap but isn’t free: on a typical PC, dispatching to a worker thread adds something like ~100 µs of overhead to each operation. (“µs” is pronounced “microseconds”, and there are 1,000,000 µs in a second. Note that all the numbers here are going to be rough orders of magnitude to give you a sense of scale; if you need precise numbers for your environment, measure!)

And second, the cost of a disk operation is incredibly bimodal. Sometimes, the data you need is already cached in RAM, and then accessing it is very, very fast – calling `io.FileIO`'s `read` method on a cached file takes on the order of ~1 µs. But when the data isn’t cached, then accessing it is much, much slower: the average is ~100 µs for SSDs and ~10,000 µs for spinning disks, and if you look at tail latencies then for both types of storage you’ll see cases where occasionally some operation will be 10x or 100x slower than average. And that’s assuming your program is the only thing trying to use that disk – if you’re on some oversold cloud VM fighting for I/O with other tenants then who knows what will happen. And some operations can require multiple disk accesses.

Putting these together: if your data is in RAM then it should be clear that using a thread is a terrible idea – if you add 100 µs of overhead to a 1 µs operation, then that’s a 100x slowdown! On the other hand, if your data’s on a spinning disk, then using a thread is great – instead of blocking the main thread and all tasks for 10,000 µs, we only block them for 100 µs and can spend the rest of that time running other tasks to get useful work done, which can effectively be a 100x speedup.

But here’s the problem: for any individual I/O operation, there’s no way to know in advance whether it’s going to be one of the fast ones or one of the slow ones, so you can’t pick and choose. When you switch to async file I/O, it makes all the fast operations slower, and all the slow operations faster. Is that a win? In terms of overall speed, it’s hard to say: it depends what kind of disks you’re using and your kernel’s disk cache hit rate, which in turn depends on your file access patterns, how much spare RAM you have, the load on your service, … all kinds of things. If the answer is important to you, then there’s no substitute for measuring your code’s actual behavior in your actual deployment environment. But what we can say is that async disk I/O makes performance much more predictable across a wider range of runtime conditions.

If you’re not sure what to do, then we recommend that you use async disk I/O by default, because it makes your code more robust when conditions are bad, especially with regards to tail latencies; this improves the chances that what your users see matches what you saw in testing. Blocking the main thread stops all tasks from running for that time. 10,000 µs is 10 ms, and it doesn’t take many 10 ms glitches to start adding up to real money; async disk I/O can help prevent those. Just don’t expect it to be magic, and be aware of the tradeoffs.

### API overview

If you want to perform general filesystem operations like creating and listing directories, renaming files, or checking file metadata – or if you just want a friendly way to work with filesystem paths – then you want `trio.Path`. It’s an asyncified replacement for the standard library’s `pathlib.Path`, and provides the same comprehensive set of operations.

For reading and writing to files and file-like objects, Trio also provides a mechanism for wrapping any synchronous file-like object into an asynchronous interface. If you have a `trio.Path` object you can get one of these by calling its `open()` method; or if you know the file’s name you can open it directly with `trio.open_file()`. Alternatively, if you already have an open file-like object, you can wrap it with `trio.wrap_file()` – one case where this is especially useful is to wrap `io.BytesIO` or `io.StringIO` when writing tests.

### Asynchronous path objects

class trio.Path(*args: str | os.PathLike[str])

  An async `pathlib.Path` that executes blocking methods in `trio.to_thread.run_sync()`.

  Instantiating `Path` returns a concrete platform-specific subclass, one of `PosixPath` or `WindowsPath`.

  await absolute()

    Like `absolute()`, but async.

    Return an absolute version of this path No normalization or symlink resolution is performed.

    Use resolve() to resolve symlinks and remove ‘..’ segments.

  property anchor

    The concatenation of the drive and root, or ‘’.

  as_posix()

    Return the string representation of the path with forward (/) slashes.

  as_uri()

    Return the path as a URI.

  await chmod(mode, *, follow_symlinks=True)

    Like `chmod()`, but async.

    Change the permissions of the path, like os.chmod().

  classmethod await cwd()

    Like `cwd()`, but async.

    Return a new path pointing to the current working directory.

  property drive

    The drive prefix (letter or UNC path), if any.

  await exists(*, follow_symlinks=True)

    Like `exists()`, but async.

    Whether this path exists.

    This method normally follows symlinks; to check whether a symlink exists, add the argument follow_symlinks=False.

  await expanduser()

    Like `expanduser()`, but async.

    Return a new path with expanded ~ and ~user constructs (as returned by os.path.expanduser)

  await full_match(pattern, *, case_sensitive=None)

    Like `full_match()`, but async.

    Return True if this path matches the given glob-style pattern. The pattern is matched against the entire path.

  await glob(pattern, *, case_sensitive=None, recurse_symlinks=False)

    Like `glob()`, but async.

    Iterate over this subtree and yield all existing files (of any kind, including directories) matching the given relative pattern.

    This is an async method that returns a synchronous iterator, so you use it like:

        for subpath in await mypath.glob():
            ...

    Note

    The iterator is loaded into memory immediately during the initial call (see issue #501 for discussion).

  await group(*, follow_symlinks=True)

    Like `group()`, but async.

    Return the group name of the file gid.

  await hardlink_to(target)

    Like `hardlink_to()`, but async.

    Make this path a hard link pointing to the same file as target.

    Note the order of arguments (self, target) is the reverse of os.link’s.

  classmethod await home()

    Like `home()`, but async.

    Return a new path pointing to expanduser(‘~’).

  is_absolute()

    True if the path is absolute (has both a root and, if applicable, a drive).

  await is_block_device()

    Like `is_block_device()`, but async.

    Whether this path is a block device.

  await is_char_device()

    Like `is_char_device()`, but async.

    Whether this path is a character device.

  await is_dir(*, follow_symlinks=True)

    Like `is_dir()`, but async.

    Whether this path is a directory.

  await is_fifo()

    Like `is_fifo()`, but async.

    Whether this path is a FIFO.

  await is_file(*, follow_symlinks=True)

    Like `is_file()`, but async.

    Whether this path is a regular file (also True for symlinks pointing to regular files).

  await is_junction()

    Like `is_junction()`, but async.

    Whether this path is a junction.

  await is_mount()

    Like `is_mount()`, but async.

    Check if this path is a mount point

  is_relative_to(other, /, *_deprecated)

    Return True if the path is relative to another path or False.

  is_reserved()

    Return True if the path contains one of the special names reserved by the system, if any.

  await is_socket()

    Like `is_socket()`, but async.

    Whether this path is a socket.

  await is_symlink()

    Like `is_symlink()`, but async.

    Whether this path is a symbolic link.

  await iterdir()

    Like `iterdir()`, but async.

    Yield path objects of the directory contents.

    The children are yielded in arbitrary order, and the special entries ‘.’ and ‘..’ are not included.

    This is an async method that returns a synchronous iterator, so you use it like:

        for subpath in await mypath.iterdir():
            ...

    Note

    The iterator is loaded into memory immediately during the initial call (see issue #501 for discussion).

  joinpath(*pathsegments)

    Combine this path with one or several arguments, and return a new path representing either a subpath (if all arguments are relative paths) or a totally different path (if one of the arguments is anchored).

  await lchmod(mode)

    Like `lchmod()`, but async.

    Like chmod(), except if the path points to a symlink, the symlink’s permissions are changed, rather than its target’s.

  await lstat()

    Like `lstat()`, but async.

    Like stat(), except if the path points to a symlink, the symlink’s status information is returned, rather than its target’s.

  match(path_pattern, *, case_sensitive=None)

    Return True if this path matches the given pattern. If the pattern is relative, matching is done from the right; otherwise, the entire path is matched. The recursive wildcard ‘**’ is not supported by this method.

  await mkdir(mode=511, parents=False, exist_ok=False)

    Like `mkdir()`, but async.

    Create a new directory at this given path.

  property name

    The final path component, if any.

  await open(mode='r', buffering=-1, encoding=None, errors=None, newline=None)

    Like `open()`, but async.

    Open the file pointed to by this path and return a file object, as the built-in open() function does.

  await owner(*, follow_symlinks=True)

    Like `owner()`, but async.

    Return the login name of the file owner.

  property parent

    The logical parent of the path.

  property parents

    A sequence of this path’s logical parents.

  parser = <module 'posixpath' (frozen)>
  property parts

    An object providing sequence-like access to the components in the filesystem path.

  await read_bytes()

    Like `read_bytes()`, but async.

    Open the file in bytes mode, read it, and close the file.

  await read_text(encoding=None, errors=None, newline=None)

    Like `read_text()`, but async.

    Open the file in text mode, read it, and close the file.

  await readlink()

    Like `readlink()`, but async.

    Return the path to which the symbolic link points.

  relative_to(other, /, *_deprecated, walk_up=False)

    Return the relative path to another path identified by the passed arguments. If the operation is not possible (because this is not related to the other path), raise ValueError.

    The walk_up parameter controls whether `` may be used to resolve the path.

  await rename(target)

    Like `rename()`, but async.

    Rename this path to the target path.

    The target path may be absolute or relative. Relative paths are interpreted relative to the current working directory, not the directory of the Path object.

    Returns the new Path instance pointing to the target path.

  await replace(target)

    Like `replace()`, but async.

    Rename this path to the target path, overwriting if that path exists.

    The target path may be absolute or relative. Relative paths are interpreted relative to the current working directory, not the directory of the Path object.

    Returns the new Path instance pointing to the target path.

  await resolve(strict=False)

    Like `resolve()`, but async.

    Make the path absolute, resolving all symlinks on the way and also normalizing it.

  await rglob(pattern, *, case_sensitive=None, recurse_symlinks=False)

    Like `rglob()`, but async.

    Recursively yield all existing files (of any kind, including directories) matching the given relative pattern, anywhere in this subtree.

    This is an async method that returns a synchronous iterator, so you use it like:

        for subpath in await mypath.rglob():
            ...

    Note

    The iterator is loaded into memory immediately during the initial call (see issue #501 for discussion).

  await rmdir()

    Like `rmdir()`, but async.

    Remove this directory. The directory must be empty.

  property root

    The root of the path, if any.

  await samefile(other_path)

    Like `samefile()`, but async.

    Return whether other_path is the same or not as this file (as returned by os.path.samefile()).

  await stat(*, follow_symlinks=True)

    Like `stat()`, but async.

    Return the result of the stat() system call on this path, like os.stat() does.

  property stem

    The final path component, minus its last suffix.

  property suffix

    The final component’s last suffix, if any.

    This includes the leading period. For example: ‘.txt’

  property suffixes

    A list of the final component’s suffixes, if any.

    These include the leading periods. For example: [‘.tar’, ‘.gz’]

  await symlink_to(target, target_is_directory=False)

    Like `symlink_to()`, but async.

    Make this path a symlink pointing to the target path. Note the order of arguments (link, target) is the reverse of os.symlink.

  await touch(mode=438, exist_ok=True)

    Like `touch()`, but async.

    Create this file with the given access mode, if it doesn’t exist.

  await unlink(missing_ok=False)

    Like `unlink()`, but async.

    Remove this file or link. If the path is a directory, use rmdir() instead.

  with_name(name)

    Return a new path with the file name changed.

  with_segments(*pathsegments)

    Construct a new path object from any number of path-like objects. Subclasses may override this method to customize how new path objects are created from methods like `iterdir()`.

  with_stem(stem)

    Return a new path with the stem changed.

  with_suffix(suffix)

    Return a new path with the file suffix changed. If the path has no suffix, add given suffix. If the given suffix is an empty string, remove the suffix from the path.

  await write_bytes(data)

    Like `write_bytes()`, but async.

    Open the file in bytes mode, write to it, and close the file.

  await write_text(data, encoding=None, errors=None, newline=None)

    Like `write_text()`, but async.

    Open the file in text mode, write to it, and close the file.

class trio.PosixPath(*args: str | os.PathLike[str])

  An async `pathlib.PosixPath` that executes blocking methods in `trio.to_thread.run_sync()`.

class trio.WindowsPath(*args: str | os.PathLike[str])

  An async `pathlib.WindowsPath` that executes blocking methods in `trio.to_thread.run_sync()`.

### Asynchronous file objects

await trio.open_file(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=None, opener=None)

  Asynchronous version of `open()`.

  Returns:

    An asynchronous file object

  Example:

      async with await trio.open_file(filename) as f:
          async for line in f:
              pass

      assert f.closed

  See also

  `trio.Path.open()`

trio.wrap_file(file)

  This wraps any file object in a wrapper that provides an asynchronous file object interface.

  Parameters:

    file – a file object

  Returns:

    An asynchronous file object that wraps `file`

  Example:

      async_file = trio.wrap_file(StringIO('asdf'))

      assert await async_file.read() == 'asdf'

Asynchronous file interface

  Trio’s asynchronous file objects have an interface that automatically adapts to the object being wrapped. Intuitively, you can mostly treat them like a regular file object, except adding an `await` in front of any of methods that do I/O. The definition of file object is a little vague in Python though, so here are the details:

  - Synchronous attributes/methods: if any of the following attributes or methods are present, then they’re re-exported unchanged: `closed`, `encoding`, `errors`, `fileno`, `isatty`, `newlines`, `readable`, `seekable`, `writable`, `buffer`, `raw`, `line_buffering`, `closefd`, `name`, `mode`, `getvalue`, `getbuffer`.

  - Async methods: if any of the following methods are present, then they’re re-exported as an async method: `flush`, `read`, `read1`, `readall`, `readinto`, `readline`, `readlines`, `seek`, `tell`, `truncate`, `write`, `writelines`, `readinto1`, `peek`, `detach`.

  Special notes:

  - Async file objects implement Trio’s `AsyncResource` interface: you close them by calling `aclose()` instead of `close` (!!), and they can be used as async context managers. Like all `aclose()` methods, the `aclose` method on async file objects is guaranteed to close the file before returning, even if it is cancelled or otherwise raises an error.

  - Using the same async file object from multiple tasks simultaneously: because the async methods on async file objects are implemented using threads, it’s only safe to call two of them at the same time from different tasks IF the underlying synchronous file object is thread-safe. You should consult the documentation for the object you’re wrapping. For objects returned from `trio.open_file()` or `trio.Path.open()`, it depends on whether you open the file in binary mode or text mode: binary mode files are task-safe/thread-safe, text mode files are not.

  - Async file objects can be used as async iterators to iterate over the lines of the file:

        async with await trio.open_file(...) as f:
            async for line in f:
                print(line)

  - The `detach` method, if present, returns an async file object.

  This should include all the attributes exposed by classes in `io`. But if you’re wrapping an object that has other attributes that aren’t on the list above, then you can access them via the `.wrapped` attribute:

  wrapped

    The underlying synchronous file object.

## Spawning subprocesses

Trio provides support for spawning other programs as subprocesses, communicating with them via pipes, sending them signals, and waiting for them to exit.

Most of the time, this is done through our high-level interface, `trio.run_process`. It lets you either run a process to completion while optionally capturing the output, or else run it in a background task and interact with it while it’s running:

await trio.run_process(command: str | bytes | os.PathLike | Sequence[str | bytes | os.PathLike], *, stdin: bytes | bytearray | memoryview | int | HasFileno | None = b'', capture_stdout: bool = False, capture_stderr: bool = False, check: bool = True, deliver_cancel: Callable[[Process], Awaitable[object]] | None = None, task_status: TaskStatus[Process] = TASK_STATUS_IGNORED, **options: object) → subprocess.CompletedProcess[bytes]

  Run `command` in a subprocess and wait for it to complete.

  This function can be called in two different ways.

  One option is a direct call, like:

      completed_process_info = await trio.run_process(...)

  In this case, it returns a `subprocess.CompletedProcess` instance describing the results. Use this if you want to treat a process like a function call.

  The other option is to run it as a task using `Nursery.start` – the enhanced version of `start_soon` that lets a task pass back a value during startup:

      process = await nursery.start(trio.run_process, ...)

  In this case, `start` returns a `Process` object that you can use to interact with the process while it’s running. Use this if you want to treat a process like a background task.

  Either way, `run_process` makes sure that the process has exited before returning, handles cancellation, optionally checks for errors, and provides some convenient shorthands for dealing with the child’s input/output.

  Input: `run_process` supports all the same `stdin=` arguments as `subprocess.Popen`. In addition, if you simply want to pass in some fixed data, you can pass a plain `bytes` object, and `run_process` will take care of setting up a pipe, feeding in the data you gave, and then sending end-of-file. The default is `b""`, which means that the child will receive an empty stdin. If you want the child to instead read from the parent’s stdin, use `stdin=None`.

  Output: By default, any output produced by the subprocess is passed through to the standard output and error streams of the parent Trio process.

  When calling `run_process` directly, you can capture the subprocess’s output by passing `capture_stdout=True` to capture the subprocess’s standard output, and/or `capture_stderr=True` to capture its standard error. Captured data is collected up by Trio into an in-memory buffer, and then provided as the `stdout` and/or `stderr` attributes of the returned `CompletedProcess` object. The value for any stream that was not captured will be `None`.

  If you want to capture both stdout and stderr while keeping them separate, pass `capture_stdout=True, capture_stderr=True`.

  If you want to capture both stdout and stderr but mixed together in the order they were printed, use: `capture_stdout=True, stderr=subprocess.STDOUT`. This directs the child’s stderr into its stdout, so the combined output will be available in the `stdout` attribute.

  If you’re using `await nursery.start(trio.run_process, ...)` and want to capture the subprocess’s output for further processing, then use `stdout=subprocess.PIPE` and then make sure to read the data out of the `Process.stdout` stream. If you want to capture stderr separately, use `stderr=subprocess.PIPE`. If you want to capture both, but mixed together in the correct order, use `stdout=subprocess.PIPE, stderr=subprocess.STDOUT`.

  Error checking: If the subprocess exits with a nonzero status code, indicating failure, `run_process()` raises a `subprocess.CalledProcessError` exception rather than returning normally. The captured outputs are still available as the `stdout` and `stderr` attributes of that exception. To disable this behavior, so that `run_process()` returns normally even if the subprocess exits abnormally, pass `check=False`.

  Note that this can make the `capture_stdout` and `capture_stderr` arguments useful even when starting `run_process` as a task: if you only care about the output if the process fails, then you can enable capturing and then read the output off of the `CalledProcessError`.

  Cancellation: If cancelled, `run_process` sends a termination request to the subprocess, then waits for it to fully exit. The `deliver_cancel` argument lets you control how the process is terminated.

  Note

  `run_process` is intentionally similar to the standard library `subprocess.run`, but some of the defaults are different. Specifically, we default to:

  - `check=True`, because “errors should never pass silently / unless explicitly silenced”.

  - `stdin=b""`, because it produces less-confusing results if a subprocess unexpectedly tries to read from stdin.

  To get the `subprocess.run` semantics, use `check=False, stdin=None`.

  Parameters:

    - command (list or str) – The command to run. Typically this is a sequence of strings such as `['ls', '-l', 'directory with spaces']`, where the first element names the executable to invoke and the other elements specify its arguments. With `shell=True` in the `**options`, or on Windows, `command` may alternatively be a string, which will be parsed following platform-dependent quoting rules.

    - stdin (`bytes`, subprocess.PIPE, file descriptor, or None) –

      The bytes to provide to the subprocess on its standard input stream, or `None` if the subprocess’s standard input should come from the same place as the parent Trio process’s standard input. As is the case with the `subprocess` module, you can also pass a file descriptor or an object with a `fileno()` method, in which case the subprocess’s standard input will come from that file.

      When starting `run_process` as a background task, you can also use `stdin=subprocess.PIPE`, in which case `Process.stdin` will be a `SendStream` that you can use to send data to the child.

    - capture_stdout (bool) – If true, capture the bytes that the subprocess writes to its standard output stream and return them in the `stdout` attribute of the returned `subprocess.CompletedProcess` or `subprocess.CalledProcessError`.

    - capture_stderr (bool) – If true, capture the bytes that the subprocess writes to its standard error stream and return them in the `stderr` attribute of the returned `CompletedProcess` or `subprocess.CalledProcessError`.

    - check (bool) – If false, don’t validate that the subprocess exits successfully. You should be sure to check the `returncode` attribute of the returned object if you pass `check=False`, so that errors don’t pass silently.

    - deliver_cancel (async function or None) –

      If `run_process` is cancelled, then it needs to kill the child process. There are multiple ways to do this, so we let you customize it.

      If you pass None (the default), then the behavior depends on the platform:

      - On Windows, Trio calls `TerminateProcess`, which should kill the process immediately.

      - On Unix-likes, the default behavior is to send a `SIGTERM`, wait 5 seconds, and send a `SIGKILL`.

      Alternatively, you can customize this behavior by passing in an arbitrary async function, which will be called with the `Process` object as an argument. For example, the default Unix behavior could be implemented like this:

          async def my_deliver_cancel(process):
              process.send_signal(signal.SIGTERM)
              await trio.sleep(5)
              process.send_signal(signal.SIGKILL)

      When the process actually exits, the `deliver_cancel` function will automatically be cancelled – so if the process exits after `SIGTERM`, then we’ll never reach the `SIGKILL`.

      In any case, `run_process` will always wait for the child process to exit before raising `Cancelled`.

    - **options – `run_process()` also accepts any general subprocess options and passes them on to the `Process` constructor. This includes the `stdout` and `stderr` options, which provide additional redirection possibilities such as `stderr=subprocess.STDOUT`, `stdout=subprocess.DEVNULL`, or file descriptors.

  Returns:

    When called normally – a `subprocess.CompletedProcess` instance describing the return code and outputs.

    When called via `Nursery.start` – a `trio.Process` instance.

  Raises:

    - UnicodeError – if `stdin` is specified as a Unicode string, rather than bytes

    - ValueError – if multiple redirections are specified for the same stream, e.g., both `capture_stdout=True` and `stdout=subprocess.DEVNULL`

    - subprocess.CalledProcessError – if `check=False` is not passed and the process exits with a nonzero exit status

    - OSError – if an error is encountered starting or communicating with the process

    - ExceptionGroup – if exceptions occur in `deliver_cancel`, or when exceptions occur when communicating with the subprocess. If strict_exception_groups is set to false in the global context, which is deprecated, then single exceptions will be collapsed.

  Note

  The child process runs in the same process group as the parent Trio process, so a Ctrl+C will be delivered simultaneously to both parent and child. If you don’t want this behavior, consult your platform’s documentation for starting child processes in a different process group.

class trio._subprocess.HasFileno(Protocol)

  Represents any file-like object that has a file descriptor.

  fileno() → int

trio._subprocess.StrOrBytesPath

  alias of `str` | `bytes` | `PathLike`[`str`] | `PathLike`[`bytes`]

class trio.Process

  A child process. Like `subprocess.Popen`, but async.

  This class has no public constructor. The most common way to get a `Process` object is to combine `Nursery.start` with `run_process`:

      process_object = await nursery.start(run_process, ...)

  This way, `run_process` supervises the process and makes sure that it is cleaned up properly, while optionally checking the return value, feeding it input, and so on.

  If you need more control – for example, because you want to spawn a child process that outlives your program – then another option is to use `trio.lowlevel.open_process`:

      process_object = await trio.lowlevel.open_process(...)

  args

    The `command` passed at construction time, specifying the process to execute and its arguments.

    Type:

      str or list

  pid

    The process ID of the child process managed by this object.

    Type:

      int

  stdin

    A stream connected to the child’s standard input stream: when you write bytes here, they become available for the child to read. Only available if the `Process` was constructed using `stdin=PIPE`; otherwise this will be None.

    Type:

      trio.abc.SendStream or None

  stdout

    A stream connected to the child’s standard output stream: when the child writes to standard output, the written bytes become available for you to read here. Only available if the `Process` was constructed using `stdout=PIPE`; otherwise this will be None.

    Type:

      trio.abc.ReceiveStream or None

  stderr

    A stream connected to the child’s standard error stream: when the child writes to standard error, the written bytes become available for you to read here. Only available if the `Process` was constructed using `stderr=PIPE`; otherwise this will be None.

    Type:

      trio.abc.ReceiveStream or None

  stdio

    A stream that sends data to the child’s standard input and receives from the child’s standard output. Only available if both `stdin` and `stdout` are available; otherwise this will be None.

    Type:

      trio.StapledStream or None

  returncode

    The exit status of the process (an integer), or `None` if it’s still running.

    By convention, a return code of zero indicates success. On UNIX, negative values indicate termination due to a signal, e.g., -11 if terminated by signal 11 (`SIGSEGV`). On Windows, a process that exits due to a call to `Process.terminate()` will have an exit status of 1.

    Unlike the standard library `subprocess.Popen.returncode`, you don’t have to call `poll` or `wait` to update this attribute; it’s automatically updated as needed, and will always give you the latest information.

  await wait() → int

    Block until the process exits.

    Returns:

      The exit status of the process; see `returncode`.

  poll() → int | None

    Returns the exit status of the process (an integer), or `None` if it’s still running.

    Note that on Trio (unlike the standard library `subprocess.Popen`), `process.poll()` and `process.returncode` always give the same result. See `returncode` for more details. This method is only included to make it easier to port code from `subprocess`.

  kill() → None

    Immediately terminate the process.

    On UNIX, this is equivalent to `send_signal(signal.SIGKILL)`. On Windows, it calls `TerminateProcess`. In both cases, the process cannot prevent itself from being killed, but the termination will be delivered asynchronously; use `wait()` if you want to ensure the process is actually dead before proceeding.

  terminate() → None

    Terminate the process, politely if possible.

    On UNIX, this is equivalent to `send_signal(signal.SIGTERM)`; by convention this requests graceful termination, but a misbehaving or buggy process might ignore it. On Windows, `terminate()` forcibly terminates the process in the same manner as `kill()`.

  send_signal(sig: signal.Signals | int) → None

    Send signal `sig` to the process.

    On UNIX, `sig` may be any signal defined in the `signal` module, such as `signal.SIGINT` or `signal.SIGTERM`. On Windows, it may be anything accepted by the standard library `subprocess.Popen.send_signal()`.

  Note

  `communicate()` is not provided as a method on `Process` objects; call `run_process()` normally for simple capturing, or write the loop yourself if you have unusual needs. `communicate()` has quite unusual cancellation behavior in the standard library (on some platforms it spawns a background thread which continues to read from the child process even after the timeout has expired) and we wanted to provide an interface with fewer surprises.

If `trio.run_process` is too limiting, we also offer a low-level API, `trio.lowlevel.open_process`. For example, if you want to spawn a child process that will outlive the parent process and be orphaned, then `run_process` can’t do that, but `open_process` can.

### Options for starting subprocesses

All of Trio’s subprocess APIs accept the numerous keyword arguments used by the standard `subprocess` module to control the environment in which a process starts and the mechanisms used for communicating with it. These may be passed wherever you see `**options` in the documentation below. See the full list or just the frequently used ones in the `subprocess` documentation. (You may need to `import subprocess` in order to access constants such as `PIPE` or `DEVNULL`.)

Currently, Trio always uses unbuffered byte streams for communicating with a process, so it does not support the `encoding`, `errors`, `universal_newlines` (alias `text`), and `bufsize` options.

### Quoting: more than you wanted to know

The command to run and its arguments usually must be passed to Trio’s subprocess APIs as a sequence of strings, where the first element in the sequence specifies the command to run and the remaining elements specify its arguments, one argument per element. This form is used because it avoids potential quoting pitfalls; for example, you can run `["cp", "-f", source_file, dest_file]` without worrying about whether `source_file` or `dest_file` contains spaces.

If you only run subprocesses without `shell=True` and on UNIX, that’s all you need to know about specifying the command. If you use `shell=True` or run on Windows, you probably should read the rest of this section to be aware of potential pitfalls.

With `shell=True` on UNIX, you must specify the command as a single string, which will be passed to the shell as if you’d entered it at an interactive prompt. The advantage of this option is that it lets you use shell features like pipes and redirection without writing code to handle them. For example, you can write `Process("ls | grep some_string", shell=True)`. The disadvantage is that you must account for the shell’s quoting rules, generally by wrapping in `shlex.quote()` any argument that might contain spaces, quotes, or other shell metacharacters. If you don’t do that, your safe-looking `f"ls | grep {some_string}"` might end in disaster when invoked with `some_string = "foo; rm -rf /"`.

On Windows, the fundamental API for process spawning (the `CreateProcess()` system call) takes a string, not a list, and it’s actually up to the child process to decide how it wants to split that string into individual arguments. Since the C language specifies that `main()` should take a list of arguments, most programs you encounter will follow the rules used by the Microsoft C/C++ runtime. `subprocess.Popen`, and thus also Trio, uses these rules when it converts an argument sequence to a string, and they are documented alongside the `subprocess` module. There is no documented Python standard library function that can directly perform that conversion, so even on Windows, you almost always want to pass an argument sequence rather than a string. But if the program you’re spawning doesn’t split its command line back into individual arguments in the standard way, you might need to pass a string to work around this. (Or you might just be out of luck: as far as I can tell, there’s simply no way to pass an argument containing a double-quote to a Windows batch file.)

On Windows with `shell=True`, things get even more chaotic. Now there are two separate sets of quoting rules applied, one by the Windows command shell `CMD.EXE` and one by the process being spawned, and they’re different. (And there’s no `shlex.quote()` to save you: it uses UNIX-style quoting rules, even on Windows.) Most special characters interpreted by the shell `&<>()^|` are not treated as special if the shell thinks they’re inside double quotes, but `%FOO%` environment variable substitutions still are, and the shell doesn’t provide any way to write a double quote inside a double-quoted string. Outside double quotes, any character (including a double quote) can be escaped using a leading `^`. But since a pipeline is processed by running each command in the pipeline in a subshell, multiple layers of escaping can be needed:

    echo ^^^&x | find "x" | find "x"          # prints: &x

And if you combine pipelines with () grouping, you can need even more levels of escaping:

    (echo ^^^^^^^&x | find "x") | find "x"    # prints: &x

Since process creation takes a single arguments string, `CMD.EXE`'s quoting does not influence word splitting, and double quotes are not removed during CMD.EXE’s expansion pass. Double quotes are troublesome because CMD.EXE handles them differently from the MSVC runtime rules; in:

    prog.exe "foo \"bar\" baz"

the program will see one argument `foo "bar" baz` but CMD.EXE thinks `bar\` is not quoted while `foo \` and `baz` are. All of this makes it a formidable task to reliably interpolate anything into a `shell=True` command line on Windows, and Trio falls back on the `subprocess` behavior: If you pass a sequence with `shell=True`, it’s quoted in the same way as a sequence with `shell=False`, and had better not contain any shell metacharacters you weren’t planning on.

Further reading:

- https://stackoverflow.com/questions/30620876/how-to-properly-escape-filenames-in-windows-cmd-exe

- https://stackoverflow.com/questions/4094699/how-does-the-windows-command-interpreter-cmd-exe-parse-scripts

## Signals

with trio.open_signal_receiver(*signals: signal.Signals | int) → Generator[AsyncIterator[int], None, None] as signal_aiter

  A context manager for catching signals.

  Entering this context manager starts listening for the given signals and returns an async iterator; exiting the context manager stops listening.

  The async iterator blocks until a signal arrives, and then yields it.

  Note that if you leave the `with` block while the iterator has unextracted signals still pending inside it, then they will be re-delivered using Python’s regular signal handling logic. This avoids a race condition when signals arrives just before we exit the `with` block.

  Parameters:

    signals – the signals to listen for.

  Raises:

    - TypeError – if no signals were provided.

    - RuntimeError – if you try to use this anywhere except Python’s main thread. (This is a Python limitation.)

  Example

  A common convention for Unix daemons is that they should reload their configuration when they receive a `SIGHUP`. Here’s a sketch of what that might look like using `open_signal_receiver()`:

      with trio.open_signal_receiver(signal.SIGHUP) as signal_aiter:
          async for signum in signal_aiter:
              assert signum == signal.SIGHUP
              reload_configuration()