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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ repos:
hooks:
- id: black
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.17.1
rev: v0.17.2
hooks:
- id: ruff-check
types: [file]
Expand Down Expand Up @@ -69,7 +69,7 @@ repos:
additional_dependencies: ["pyyaml"]
files: ^(test-requirements\.txt)|(\.pre-commit-config\.yaml)$
- repo: https://github.com/astral-sh/uv-pre-commit
rev: 0.13.1
rev: 0.13.5
hooks:
# Compile requirements
- id: pip-compile
Expand Down
21 changes: 15 additions & 6 deletions docs-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ babel==2.18.0
# via sphinx
beautifulsoup4==4.15.0
# via sphinx-codeautolink
certifi==2026.7.22
certifi==2026.10.23
# via requests
cffi==2.1.1 ; os_name == 'nt' or platform_python_implementation != 'PyPy'
# via
Expand Down Expand Up @@ -43,13 +43,13 @@ jinja2==3.1.6
# -r docs-requirements.in
# sphinx
# towncrier
markupsafe==3.0.3
markupsafe==3.0.4
# via jinja2
outcome==1.3.0.post0
# via -r docs-requirements.in
packaging==26.3
# via sphinx
pycparser==3.0 ; (implementation_name != 'PyPy' and os_name == 'nt') or (implementation_name != 'PyPy' and platform_python_implementation != 'PyPy')
pycparser==3.12 ; (implementation_name != 'PyPy' and os_name == 'nt') or (implementation_name != 'PyPy' and platform_python_implementation != 'PyPy')
# via cffi
pygments==2.21.0
# via sphinx
Expand All @@ -65,7 +65,9 @@ snowballstemmer==3.1.1
# via sphinx
sortedcontainers==2.4.0
# via -r docs-requirements.in
soupsieve==2.10
soupsieve==2.10 ; python_full_version < '3.11.5'
# via beautifulsoup4
soupsieve==3.0.4 ; python_full_version >= '3.11.5'
# via beautifulsoup4
sphinx==9.0.4 ; python_full_version < '3.12'
# via
Expand All @@ -74,7 +76,14 @@ sphinx==9.0.4 ; python_full_version < '3.12'
# sphinx-rtd-theme
# sphinxcontrib-jquery
# sphinxcontrib-trio
sphinx==9.1.0 ; python_full_version >= '3.12'
sphinx==9.1.1 ; python_full_version == '3.12.*'
# via
# -r docs-requirements.in
# sphinx-codeautolink
# sphinx-rtd-theme
# sphinxcontrib-jquery
# sphinxcontrib-trio
sphinx==9.2.0 ; python_full_version >= '3.13'
# via
# -r docs-requirements.in
# sphinx-codeautolink
Expand All @@ -95,7 +104,7 @@ sphinxcontrib-jquery==4.1
# via
# -r docs-requirements.in
# sphinx-rtd-theme
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-jsmath==2.0.0
# via sphinx
sphinxcontrib-qthelp==2.0.0
# via sphinx
Expand Down
14 changes: 11 additions & 3 deletions src/trio/_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import socket
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Generic, TypeVar
from typing import TYPE_CHECKING, Generic, Literal, TypeVar

import trio

Expand Down Expand Up @@ -173,12 +173,20 @@ async def getaddrinfo(
proto: int = 0,
flags: int = 0,
) -> list[
# copied from _GetAddrInfoEntry
tuple[
socket.AddressFamily,
Literal[socket.AddressFamily.AF_INET],
socket.SocketKind,
int,
str,
tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes],
tuple[str, int],
]
| tuple[
Literal[socket.AddressFamily.AF_INET6],
socket.SocketKind,
int,
str,
tuple[str, int, int, int] | tuple[int, bytes],
]
]:
"""A custom implementation of :func:`~trio.socket.getaddrinfo`.
Expand Down
2 changes: 1 addition & 1 deletion src/trio/_dtls.py
Original file line number Diff line number Diff line change
Expand Up @@ -841,7 +841,7 @@ def __init__(
self.endpoint = endpoint
self.peer_address = peer_address
self._packets_dropped_in_trio = 0
self._client_hello = None
self._client_hello: tuple[bytes, bytes] | None = None
self._did_handshake = False
self._ssl = SSL.Connection(ctx)
self._handshake_mtu = 0
Expand Down
8 changes: 4 additions & 4 deletions src/trio/_highlevel_open_tcp_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import sys
from contextlib import contextmanager, suppress
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING

import trio
from trio.socket import SOCK_STREAM, SocketType, getaddrinfo, socket
Expand All @@ -11,7 +11,7 @@
from collections.abc import Generator, MutableSequence
from socket import AddressFamily, SocketKind

from trio._socket import AddressFormat
from trio._socket import AddressFormat, _GetAddrInfoEntry

if sys.version_info < (3, 11):
from exceptiongroup import BaseExceptionGroup, ExceptionGroup
Expand Down Expand Up @@ -134,8 +134,8 @@ def close_all() -> Generator[set[SocketType], None, None]:
raise BaseExceptionGroup("", errs)


def reorder_for_rfc_6555_section_5_4( # type: ignore[explicit-any]
targets: MutableSequence[tuple[AddressFamily, SocketKind, int, str, Any]],
def reorder_for_rfc_6555_section_5_4(
targets: MutableSequence[_GetAddrInfoEntry],
) -> None:
# RFC 6555 section 5.4 says that if getaddrinfo returns multiple address
# families (e.g. IPv4 and IPv6), then you should make sure that your first
Expand Down
32 changes: 30 additions & 2 deletions src/trio/_socket.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
TYPE_CHECKING,
Any,
Concatenate,
Literal,
SupportsIndex,
TypeAlias,
TypeVar,
Expand Down Expand Up @@ -49,6 +50,25 @@
# but instead we simply do:
AddressFormat: TypeAlias = Any # type: ignore[explicit-any]

# typeshed defines _GetAddrInfoResult but we would rather manipulate the inner
# entry type... as well as use a type defined at runtime!
_GetAddrInfoEntry: TypeAlias = ( # noqa: PYI047
tuple[
Literal[AddressFamily.AF_INET],
SocketKind,
int,
str,
tuple[str, int],
]
| tuple[
Literal[AddressFamily.AF_INET6],
SocketKind,
int,
str,
tuple[str, int, int, int] | tuple[int, bytes],
]
)


# Usage:
#
Expand Down Expand Up @@ -180,12 +200,20 @@ async def getaddrinfo(
proto: int = 0,
flags: int = 0,
) -> list[
# copied from _GetAddrInfoEntry
tuple[
AddressFamily,
Literal[AddressFamily.AF_INET],
SocketKind,
int,
str,
tuple[str, int],
]
| tuple[
Literal[AddressFamily.AF_INET6],
SocketKind,
int,
str,
tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes],
tuple[str, int, int, int] | tuple[int, bytes],
]
]:
"""Look up a numeric address given a name.
Expand Down
2 changes: 1 addition & 1 deletion src/trio/_tests/test_exports.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
try: # If installed, check both versions of this class.
from typing_extensions import Protocol as Protocol_ext
except ImportError: # pragma: no cover
Protocol_ext = Protocol
Protocol_ext = Protocol # type: ignore[assignment]


def _ensure_mypy_cache_updated() -> None:
Expand Down
30 changes: 16 additions & 14 deletions src/trio/_tests/test_highlevel_open_tcp_listeners.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import socket as stdlib_socket
import sys
from socket import AddressFamily, SocketKind
from typing import TYPE_CHECKING, cast, overload
from typing import TYPE_CHECKING, Literal, cast, overload

import attrs
import pytest
Expand All @@ -30,7 +30,7 @@

from typing_extensions import Buffer

from trio._socket import AddressFormat
from trio._socket import AddressFormat, _GetAddrInfoEntry


async def test_open_tcp_listeners_basic() -> None:
Expand Down Expand Up @@ -242,7 +242,9 @@ def socket(

@attrs.define(slots=False)
class FakeHostnameResolver(HostnameResolver):
family_addr_pairs: Sequence[tuple[AddressFamily, str]]
family_addr_pairs: Sequence[
tuple[Literal[AddressFamily.AF_INET, AddressFamily.AF_INET6], str]
]

async def getaddrinfo(
self,
Expand All @@ -252,18 +254,14 @@ async def getaddrinfo(
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],
]
]:
) -> list[_GetAddrInfoEntry]:
assert isinstance(port, int)
return [
(family, tsocket.SOCK_STREAM, 0, "", (addr, port))
(
(family, tsocket.SOCK_STREAM, 0, "", (addr, port))
if family is AddressFamily.AF_INET
else (family, tsocket.SOCK_STREAM, 0, "", (addr, port, 0, 0))
)
for family, addr in self.family_addr_pairs
]

Expand Down Expand Up @@ -333,7 +331,7 @@ async def handler(stream: SendStream) -> None:
[{tsocket.AF_INET}, {tsocket.AF_INET6}, {tsocket.AF_INET, tsocket.AF_INET6}],
)
async def test_open_tcp_listeners_some_address_families_unavailable(
try_families: set[AddressFamily],
try_families: set[Literal[AddressFamily.AF_INET, AddressFamily.AF_INET6]],
fail_families: set[AddressFamily],
) -> None:
fsf = FakeSocketFactory(
Expand All @@ -360,6 +358,10 @@ async def test_open_tcp_listeners_some_address_families_unavailable(
else:
listeners = await open_tcp_listeners(80)
for listener in listeners:
assert (
listener.socket.family is AddressFamily.AF_INET
or listener.socket.family is AddressFamily.AF_INET6
)
should_succeed.remove(listener.socket.family)
assert not should_succeed

Expand Down
47 changes: 21 additions & 26 deletions src/trio/_tests/test_highlevel_open_tcp_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import socket
import sys
from socket import AddressFamily, SocketKind
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Literal

import attrs
import pytest
Expand All @@ -20,6 +20,7 @@
if TYPE_CHECKING:
from collections.abc import Sequence

from trio._socket import _GetAddrInfoEntry
from trio.testing import MockClock

if sys.version_info < (3, 11):
Expand Down Expand Up @@ -60,7 +61,7 @@ def close(self) -> None:
def test_reorder_for_rfc_6555_section_5_4() -> None:
def fake4(
i: int,
) -> tuple[socket.AddressFamily, socket.SocketKind, int, str, tuple[str, int]]:
) -> _GetAddrInfoEntry:
return (
AF_INET,
SOCK_STREAM,
Expand All @@ -71,8 +72,14 @@ def fake4(

def fake6(
i: int,
) -> tuple[socket.AddressFamily, socket.SocketKind, int, str, tuple[str, int]]:
return (AF_INET6, SOCK_STREAM, IPPROTO_TCP, "", (f"::{i}", 80))
) -> tuple[
Literal[AddressFamily.AF_INET6],
SocketKind,
int,
str,
tuple[str, int, int, int] | tuple[int, bytes],
]:
return (AF_INET6, SOCK_STREAM, IPPROTO_TCP, "", (f"::{i}", 80, 0, 0))

for fake in fake4, fake6:
# No effect on homogeneous lists
Expand Down Expand Up @@ -281,21 +288,17 @@ def socket(
self.socket_count += 1
return FakeSocket(self, family, type_, proto)

def _ip_to_gai_entry(self, ip: str) -> tuple[
AddressFamily,
SocketKind,
int,
str,
tuple[str, int, int, int] | tuple[str, int] | tuple[int, bytes],
]:
sockaddr: tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes]
def _ip_to_gai_entry(self, ip: str) -> _GetAddrInfoEntry:
if ":" in ip:
family = trio.socket.AF_INET6
sockaddr = (ip, self.port, 0, 0)
return (
trio.socket.AF_INET6,
SOCK_STREAM,
IPPROTO_TCP,
"",
(ip, self.port, 0, 0),
)
else:
family = trio.socket.AF_INET
sockaddr = (ip, self.port)
return (family, SOCK_STREAM, IPPROTO_TCP, "", sockaddr)
return (trio.socket.AF_INET, SOCK_STREAM, IPPROTO_TCP, "", (ip, self.port))

async def getaddrinfo(
self,
Expand All @@ -305,15 +308,7 @@ async def getaddrinfo(
type: int = -1,
proto: int = -1,
flags: int = -1,
) -> list[
tuple[
AddressFamily,
SocketKind,
int,
str,
tuple[str, int, int, int] | tuple[str, int] | tuple[int, bytes],
]
]:
) -> list[_GetAddrInfoEntry]:
assert host == b"test.example.com"
assert port == self.port
assert family == trio.socket.AF_UNSPEC
Expand Down
Loading
Loading