From 1920edd95922307324f322280f0f635bcbff369c Mon Sep 17 00:00:00 2001 From: Spencer Brown Date: Tue, 15 Aug 2023 15:08:53 +1000 Subject: [PATCH 01/11] Type _highlevel_open_unix_stream --- trio/_highlevel_open_unix_stream.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/trio/_highlevel_open_unix_stream.py b/trio/_highlevel_open_unix_stream.py index c2c3a3ca7c..c05b8f3fc8 100644 --- a/trio/_highlevel_open_unix_stream.py +++ b/trio/_highlevel_open_unix_stream.py @@ -1,9 +1,22 @@ +from __future__ import annotations + import os +from collections.abc import Generator from contextlib import contextmanager +from typing import Protocol, TypeVar import trio from trio.socket import SOCK_STREAM, socket + +class Closable(Protocol): + def close(self) -> None: + ... + + +CloseT = TypeVar("CloseT", bound=Closable) + + try: from trio.socket import AF_UNIX @@ -13,7 +26,7 @@ @contextmanager -def close_on_error(obj): +def close_on_error(obj: CloseT) -> Generator[CloseT, None, None]: try: yield obj except: @@ -21,7 +34,9 @@ def close_on_error(obj): raise -async def open_unix_socket(filename): +async def open_unix_socket( + filename: str | bytes | os.PathLike[str] | os.PathLike[bytes], +) -> trio.SocketStream: """Opens a connection to the specified `Unix domain socket `__. From 4ffae61932610e25fc522980ed65d4937ef7ce8d Mon Sep 17 00:00:00 2001 From: Spencer Brown Date: Tue, 15 Aug 2023 15:37:52 +1000 Subject: [PATCH 02/11] Add types to _highlevel_socket --- trio/_highlevel_socket.py | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/trio/_highlevel_socket.py b/trio/_highlevel_socket.py index ce96153805..d91ce6fb80 100644 --- a/trio/_highlevel_socket.py +++ b/trio/_highlevel_socket.py @@ -2,8 +2,9 @@ from __future__ import annotations import errno +from collections.abc import Generator from contextlib import contextmanager -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, overload import trio @@ -13,6 +14,7 @@ if TYPE_CHECKING: from ._socket import _SocketType as SocketType + from typing_extensions import Buffer # XX TODO: this number was picked arbitrarily. We should do experiments to # tune it. (Or make it dynamic -- one idea is to start small and increase it @@ -29,7 +31,7 @@ @contextmanager -def _translate_socket_errors_to_stream_errors(): +def _translate_socket_errors_to_stream_errors() -> Generator[None, None, None]: try: yield except OSError as exc: @@ -97,7 +99,7 @@ def __init__(self, socket: SocketType): except OSError: pass - async def send_all(self, data): + async def send_all(self, data: bytes | bytearray | memoryview) -> None: if self.socket.did_shutdown_SHUT_WR: raise trio.ClosedResourceError("can't send data after sending EOF") with self._send_conflict_detector: @@ -145,15 +147,38 @@ async def aclose(self) -> None: # __aenter__, __aexit__ inherited from HalfCloseableStream are OK - def setsockopt(self, level, option, value): + @overload + def setsockopt(self, level: int, option: int, value: int | Buffer) -> None: + ... + + @overload + def setsockopt(self, level: int, option: int, value: None, length: int) -> None: + ... + + def setsockopt( + self, + level: int, + option: int, + value: int | Buffer | None, + length: int | None = None, + ) -> None: """Set an option on the underlying socket. See :meth:`socket.socket.setsockopt` for details. """ - return self.socket.setsockopt(level, option, value) + # Delegate checking argument types to _SocketType. + return self.socket.setsockopt(level, option, value, length) # type: ignore[arg-type] - def getsockopt(self, level, option, buffersize=0): + @overload + def getsockopt(self, level: int, option: int) -> int: + ... + + @overload + def getsockopt(self, level: int, option: int, buffersize: int) -> bytes: + ... + + def getsockopt(self, level: int, option: int, buffersize: int = 0) -> int | bytes: """Check the current value of an option on the underlying socket. See :meth:`socket.socket.getsockopt` for details. @@ -311,7 +336,7 @@ def getsockopt(self, level, option, buffersize=0): ] # Not all errnos are defined on all platforms -_ignorable_accept_errnos = set() +_ignorable_accept_errnos: set[int] = set() for name in _ignorable_accept_errno_names: try: _ignorable_accept_errnos.add(getattr(errno, name)) From e59d7c081cbf5cc52afaf1aca26f1c573a25d3c3 Mon Sep 17 00:00:00 2001 From: Spencer Brown Date: Tue, 15 Aug 2023 15:49:06 +1000 Subject: [PATCH 03/11] Add types to _highlevel_serve_listeners / _ssl_helpers --- trio/_highlevel_serve_listeners.py | 28 +++++++++++++++++--- trio/_highlevel_ssl_helpers.py | 42 ++++++++++++++++++------------ 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/trio/_highlevel_serve_listeners.py b/trio/_highlevel_serve_listeners.py index 0585fa516f..20379b7180 100644 --- a/trio/_highlevel_serve_listeners.py +++ b/trio/_highlevel_serve_listeners.py @@ -1,6 +1,9 @@ +from __future__ import annotations + import errno import logging import os +from typing import TypeVar, Callable, Awaitable import trio @@ -20,14 +23,23 @@ LOGGER = logging.getLogger("trio.serve_listeners") -async def _run_handler(stream, handler): +StreamT = TypeVar("StreamT", bound=trio.abc.AsyncResource) +ListenerT = TypeVar("ListenerT", bound=trio.abc.Listener) +Handler = Callable[[StreamT], Awaitable[object]] + + +async def _run_handler(stream: StreamT, handler: Handler[StreamT]) -> None: try: await handler(stream) finally: await trio.aclose_forcefully(stream) -async def _serve_one_listener(listener, handler_nursery, handler): +async def _serve_one_listener( + listener: trio.abc.Listener[StreamT], + handler_nursery: trio.Nursery, + handler: Handler[StreamT], +) -> None: async with listener: while True: try: @@ -48,9 +60,17 @@ async def _serve_one_listener(listener, handler_nursery, handler): handler_nursery.start_soon(_run_handler, stream, handler) +# This cannot be typed correctly, we need generic typevar bounds / HKT to indicate the +# relationship between StreamT & ListenerT. +# https://github.com/python/typing/issues/1226 +# https://github.com/python/typing/issues/548 async def serve_listeners( - handler, listeners, *, handler_nursery=None, task_status=trio.TASK_STATUS_IGNORED -): + handler: Handler[StreamT], + listeners: list[ListenerT], + *, + handler_nursery: trio.Nursery | None = None, + task_status: trio.TaskStatus[list[ListenerT]] = trio.TASK_STATUS_IGNORED, +) -> None: r"""Listen for incoming connections on ``listeners``, and for each one start a task running ``handler(stream)``. diff --git a/trio/_highlevel_ssl_helpers.py b/trio/_highlevel_ssl_helpers.py index ad77a302f0..7c145f075f 100644 --- a/trio/_highlevel_ssl_helpers.py +++ b/trio/_highlevel_ssl_helpers.py @@ -1,4 +1,7 @@ +from __future__ import annotations + import ssl +from collections.abc import Awaitable, Callable import trio @@ -15,13 +18,13 @@ # So... let's punt on that for now. Hopefully we'll be getting a new Python # TLS API soon and can revisit this then. async def open_ssl_over_tcp_stream( - host, - port, + host: str | bytes, + port: int, *, - https_compatible=False, - ssl_context=None, - happy_eyeballs_delay=DEFAULT_DELAY, -): + https_compatible: bool = False, + ssl_context: ssl.SSLContext | None = None, + happy_eyeballs_delay: float | None = DEFAULT_DELAY, +) -> trio.SSLStream: """Make a TLS-encrypted Connection to the given host and port over TCP. This is a convenience wrapper that calls :func:`open_tcp_stream` and @@ -63,8 +66,13 @@ async def open_ssl_over_tcp_stream( async def open_ssl_over_tcp_listeners( - port, ssl_context, *, host=None, https_compatible=False, backlog=None -): + port: int, + ssl_context: ssl.SSLContext, + *, + host: str | bytes | None = None, + https_compatible: bool = False, + backlog: int | float | None = None, +) -> list[trio.SSLListener]: """Start listening for SSL/TLS-encrypted TCP connections to the given port. Args: @@ -86,16 +94,16 @@ async def open_ssl_over_tcp_listeners( async def serve_ssl_over_tcp( - handler, - port, - ssl_context, + handler: Callable[[trio.SSLStream], Awaitable[object]], + port: int, + ssl_context: ssl.SSLContext, *, - host=None, - https_compatible=False, - backlog=None, - handler_nursery=None, - task_status=trio.TASK_STATUS_IGNORED, -): + host: str | bytes | None = None, + https_compatible: bool = False, + backlog: int | float | None = None, + handler_nursery: trio.Nursery | None = None, + task_status: trio.TaskStatus[list[trio.SSLListener]] = trio.TASK_STATUS_IGNORED, +) -> None: """Listen for incoming TCP connections, and for each one start a task running ``handler(stream)``. From e69733dfeeee45b450f3d84df930292faa93e4fa Mon Sep 17 00:00:00 2001 From: Spencer Brown Date: Tue, 15 Aug 2023 15:56:47 +1000 Subject: [PATCH 04/11] Update verify_types.json --- trio/_tests/verify_types.json | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/trio/_tests/verify_types.json b/trio/_tests/verify_types.json index 16acc7f39b..0f08a51159 100644 --- a/trio/_tests/verify_types.json +++ b/trio/_tests/verify_types.json @@ -7,11 +7,11 @@ "warningCount": 0 }, "typeCompleteness": { - "completenessScore": 0.9490445859872612, + "completenessScore": 0.9585987261146497, "exportedSymbolCounts": { "withAmbiguousType": 0, - "withKnownType": 596, - "withUnknownType": 32 + "withKnownType": 602, + "withUnknownType": 26 }, "ignoreUnknownTypesFromImports": true, "missingClassDocStringCount": 1, @@ -46,14 +46,11 @@ ], "otherSymbolCounts": { "withAmbiguousType": 3, - "withKnownType": 627, - "withUnknownType": 50 + "withKnownType": 631, + "withUnknownType": 46 }, "packageName": "trio", "symbols": [ - "trio._highlevel_socket.SocketStream.getsockopt", - "trio._highlevel_socket.SocketStream.send_all", - "trio._highlevel_socket.SocketStream.setsockopt", "trio._ssl.SSLListener.__init__", "trio._ssl.SSLListener.accept", "trio._ssl.SSLListener.aclose", @@ -90,12 +87,7 @@ "trio.lowlevel.temporarily_detach_coroutine_object", "trio.lowlevel.wait_readable", "trio.lowlevel.wait_writable", - "trio.open_ssl_over_tcp_listeners", - "trio.open_ssl_over_tcp_stream", - "trio.open_unix_socket", "trio.run_process", - "trio.serve_listeners", - "trio.serve_ssl_over_tcp", "trio.testing._memory_streams.MemoryReceiveStream.__init__", "trio.testing._memory_streams.MemoryReceiveStream.aclose", "trio.testing._memory_streams.MemoryReceiveStream.close", From 68736f6535571016394ce0099fab4f44d5b6887d Mon Sep 17 00:00:00 2001 From: Spencer Brown Date: Tue, 15 Aug 2023 16:36:08 +1000 Subject: [PATCH 05/11] Mark these functions as never returning --- trio/_highlevel_serve_listeners.py | 11 +++++++---- trio/_highlevel_socket.py | 3 ++- trio/_highlevel_ssl_helpers.py | 3 ++- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/trio/_highlevel_serve_listeners.py b/trio/_highlevel_serve_listeners.py index 20379b7180..7bce91684e 100644 --- a/trio/_highlevel_serve_listeners.py +++ b/trio/_highlevel_serve_listeners.py @@ -3,7 +3,7 @@ import errno import logging import os -from typing import TypeVar, Callable, Awaitable +from typing import Awaitable, Callable, NoReturn, TypeVar import trio @@ -39,7 +39,7 @@ async def _serve_one_listener( listener: trio.abc.Listener[StreamT], handler_nursery: trio.Nursery, handler: Handler[StreamT], -) -> None: +) -> NoReturn: async with listener: while True: try: @@ -64,13 +64,16 @@ async def _serve_one_listener( # relationship between StreamT & ListenerT. # https://github.com/python/typing/issues/1226 # https://github.com/python/typing/issues/548 -async def serve_listeners( + +# It does never return (since _serve_one_listener never completes), but type checkers can't +# understand nurseries. +async def serve_listeners( # type: ignore[misc] handler: Handler[StreamT], listeners: list[ListenerT], *, handler_nursery: trio.Nursery | None = None, task_status: trio.TaskStatus[list[ListenerT]] = trio.TASK_STATUS_IGNORED, -) -> None: +) -> NoReturn: r"""Listen for incoming connections on ``listeners``, and for each one start a task running ``handler(stream)``. diff --git a/trio/_highlevel_socket.py b/trio/_highlevel_socket.py index d91ce6fb80..f50686eb05 100644 --- a/trio/_highlevel_socket.py +++ b/trio/_highlevel_socket.py @@ -13,9 +13,10 @@ from .abc import HalfCloseableStream, Listener if TYPE_CHECKING: - from ._socket import _SocketType as SocketType from typing_extensions import Buffer + from ._socket import _SocketType as SocketType + # XX TODO: this number was picked arbitrarily. We should do experiments to # tune it. (Or make it dynamic -- one idea is to start small and increase it # if we observe single reads filling up the whole buffer, at least within some diff --git a/trio/_highlevel_ssl_helpers.py b/trio/_highlevel_ssl_helpers.py index 7c145f075f..1647f373c2 100644 --- a/trio/_highlevel_ssl_helpers.py +++ b/trio/_highlevel_ssl_helpers.py @@ -2,6 +2,7 @@ import ssl from collections.abc import Awaitable, Callable +from typing import NoReturn import trio @@ -103,7 +104,7 @@ async def serve_ssl_over_tcp( backlog: int | float | None = None, handler_nursery: trio.Nursery | None = None, task_status: trio.TaskStatus[list[trio.SSLListener]] = trio.TASK_STATUS_IGNORED, -) -> None: +) -> NoReturn: """Listen for incoming TCP connections, and for each one start a task running ``handler(stream)``. From 78efb8e3723fba88abddba691fc5ead535d5d0e8 Mon Sep 17 00:00:00 2001 From: Spencer Brown Date: Tue, 15 Aug 2023 16:57:06 +1000 Subject: [PATCH 06/11] Add the same TypeErrors to SocketStream.setsockopt() --- trio/_highlevel_serve_listeners.py | 1 + trio/_highlevel_socket.py | 13 +++++++++++-- trio/_socket.py | 2 +- trio/_tests/test_highlevel_socket.py | 3 +++ trio/_tests/test_socket.py | 29 ++++++++++++++++------------ 5 files changed, 33 insertions(+), 15 deletions(-) diff --git a/trio/_highlevel_serve_listeners.py b/trio/_highlevel_serve_listeners.py index 7bce91684e..fc9bf29a0a 100644 --- a/trio/_highlevel_serve_listeners.py +++ b/trio/_highlevel_serve_listeners.py @@ -65,6 +65,7 @@ async def _serve_one_listener( # https://github.com/python/typing/issues/1226 # https://github.com/python/typing/issues/548 + # It does never return (since _serve_one_listener never completes), but type checkers can't # understand nurseries. async def serve_listeners( # type: ignore[misc] diff --git a/trio/_highlevel_socket.py b/trio/_highlevel_socket.py index f50686eb05..f8d01cd755 100644 --- a/trio/_highlevel_socket.py +++ b/trio/_highlevel_socket.py @@ -168,8 +168,17 @@ def setsockopt( See :meth:`socket.socket.setsockopt` for details. """ - # Delegate checking argument types to _SocketType. - return self.socket.setsockopt(level, option, value, length) # type: ignore[arg-type] + if length is None: + if value is None: + raise TypeError( + "invalid value for argument 'value', must not be None when specifying length" + ) + return self.socket.setsockopt(level, option, value) + if value is not None: + raise TypeError( + f"invalid value for argument 'value': {value!r}, must be None when specifying optlen" + ) + return self.socket.setsockopt(level, option, value, length) @overload def getsockopt(self, level: int, option: int) -> int: diff --git a/trio/_socket.py b/trio/_socket.py index b0ec1d480d..b6d5966397 100644 --- a/trio/_socket.py +++ b/trio/_socket.py @@ -599,7 +599,7 @@ def setsockopt( return self._sock.setsockopt(level, optname, value) if value is not None: raise TypeError( - "invalid value for argument 'value': {value!r}, must be None when specifying optlen" + f"invalid value for argument 'value': {value!r}, must be None when specifying optlen" ) # Note: PyPy may crash here due to setsockopt only supporting diff --git a/trio/_tests/test_highlevel_socket.py b/trio/_tests/test_highlevel_socket.py index 14143affe2..1a987df3f3 100644 --- a/trio/_tests/test_highlevel_socket.py +++ b/trio/_tests/test_highlevel_socket.py @@ -11,6 +11,7 @@ check_half_closeable_stream, wait_all_tasks_blocked, ) +from .test_socket import setsockopt_tests async def test_SocketStream_basics(): @@ -50,6 +51,8 @@ async def test_SocketStream_basics(): b = s.getsockopt(tsocket.IPPROTO_TCP, tsocket.TCP_NODELAY, 1) assert isinstance(b, bytes) + setsockopt_tests(s) + async def test_SocketStream_send_all(): BIG = 10000000 diff --git a/trio/_tests/test_socket.py b/trio/_tests/test_socket.py index e9baff436a..4fd8173855 100644 --- a/trio/_tests/test_socket.py +++ b/trio/_tests/test_socket.py @@ -363,21 +363,26 @@ async def test_SocketType_basics(): async def test_SocketType_setsockopt(): sock = tsocket.socket() with sock as _: - # specifying optlen. Not supported on pypy, and I couldn't find - # valid calls on darwin or win32. - if hasattr(tsocket, "SO_BINDTODEVICE"): - sock.setsockopt(tsocket.SOL_SOCKET, tsocket.SO_BINDTODEVICE, None, 0) + setsockopt_tests(sock) - # specifying value - sock.setsockopt(tsocket.IPPROTO_TCP, tsocket.TCP_NODELAY, False) - # specifying both - with pytest.raises(TypeError, match="invalid value for argument 'value'"): - sock.setsockopt(tsocket.IPPROTO_TCP, tsocket.TCP_NODELAY, False, 5) # type: ignore[call-overload] +def setsockopt_tests(sock): + """Extract these out, to be reused for SocketStream also.""" + # specifying optlen. Not supported on pypy, and I couldn't find + # valid calls on darwin or win32. + if hasattr(tsocket, "SO_BINDTODEVICE"): + sock.setsockopt(tsocket.SOL_SOCKET, tsocket.SO_BINDTODEVICE, None, 0) + + # specifying value + sock.setsockopt(tsocket.IPPROTO_TCP, tsocket.TCP_NODELAY, False) + + # specifying both + with pytest.raises(TypeError, match="invalid value for argument 'value'"): + sock.setsockopt(tsocket.IPPROTO_TCP, tsocket.TCP_NODELAY, False, 5) # type: ignore[call-overload] - # specifying neither - with pytest.raises(TypeError, match="invalid value for argument 'value'"): - sock.setsockopt(tsocket.IPPROTO_TCP, tsocket.TCP_NODELAY, None) # type: ignore[call-overload] + # specifying neither + with pytest.raises(TypeError, match="invalid value for argument 'value'"): + sock.setsockopt(tsocket.IPPROTO_TCP, tsocket.TCP_NODELAY, None) # type: ignore[call-overload] async def test_SocketType_dup(): From 15a3c0d1f3612c0a08c7a8e4950ef296e495d0ee Mon Sep 17 00:00:00 2001 From: Spencer Brown Date: Tue, 15 Aug 2023 17:28:40 +1000 Subject: [PATCH 07/11] Fix docs build --- docs/source/conf.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/source/conf.py b/docs/source/conf.py index 06e4a7e6be..60133e7ccf 100755 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -65,11 +65,13 @@ ("py:class", "trio._core._run.StatusT"), ("py:class", "trio._core._run.StatusT_co"), ("py:class", "trio._core._run.StatusT_contra"), + ("py:class", "trio._highlevel_serve_listeners.StreamT"), ("py:class", "trio._core._run.RetT"), ("py:class", "trio._threads.T"), ("py:class", "P.args"), ("py:class", "P.kwargs"), ("py:class", "RetT"), + ("py:class", "ListenerT"), # why aren't these found in stdlib? ("py:class", "types.FrameType"), # TODO: figure out if you can link this to SSL @@ -79,6 +81,7 @@ # these are not defined in https://docs.python.org/3/objects.inv ("py:class", "socket.AddressFamily"), ("py:class", "socket.SocketKind"), + ("py:class", "Buffer"), # collections.abc.Buffer, in 3.12 ] autodoc_inherit_docstrings = False default_role = "obj" From 547bf059db00f8a1caf73423eaa4fb3bad0aab56 Mon Sep 17 00:00:00 2001 From: Spencer Brown Date: Thu, 17 Aug 2023 18:05:36 +1000 Subject: [PATCH 08/11] Enable strict options for highlevel modules --- pyproject.toml | 6 ++++++ trio/_highlevel_serve_listeners.py | 5 +++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index d93cb382ba..90a16fe8a4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -64,7 +64,13 @@ module = [ "trio._deprecate", "trio._dtls", "trio._file_io", + "trio._highlevel_generic", + "trio._highlevel_open_tcp_listeners", "trio._highlevel_open_tcp_stream", + "trio._highlevel_open_unix_stream", + "trio._highlevel_serve_listeners", + "trio._highlevel_socket", + "trio._highlevel_ssl_helpers", "trio._ki", "trio._socket", "trio._sync", diff --git a/trio/_highlevel_serve_listeners.py b/trio/_highlevel_serve_listeners.py index fc9bf29a0a..1599b80db2 100644 --- a/trio/_highlevel_serve_listeners.py +++ b/trio/_highlevel_serve_listeners.py @@ -3,7 +3,8 @@ import errno import logging import os -from typing import Awaitable, Callable, NoReturn, TypeVar +from collections.abc import Sequence +from typing import Any, Awaitable, Callable, NoReturn, TypeVar import trio @@ -24,7 +25,7 @@ StreamT = TypeVar("StreamT", bound=trio.abc.AsyncResource) -ListenerT = TypeVar("ListenerT", bound=trio.abc.Listener) +ListenerT = TypeVar("ListenerT", bound=trio.abc.Listener[Any]) Handler = Callable[[StreamT], Awaitable[object]] From e27403f64a66dde77ac081a247bffed8e76c5a5e Mon Sep 17 00:00:00 2001 From: Spencer Brown Date: Thu, 17 Aug 2023 18:30:24 +1000 Subject: [PATCH 09/11] Fix some type issues --- trio/_highlevel_serve_listeners.py | 1 - trio/_subprocess.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/trio/_highlevel_serve_listeners.py b/trio/_highlevel_serve_listeners.py index 1599b80db2..d5c7a3bdad 100644 --- a/trio/_highlevel_serve_listeners.py +++ b/trio/_highlevel_serve_listeners.py @@ -3,7 +3,6 @@ import errno import logging import os -from collections.abc import Sequence from typing import Any, Awaitable, Callable, NoReturn, TypeVar import trio diff --git a/trio/_subprocess.py b/trio/_subprocess.py index 1f8d0a8253..be09b46de4 100644 --- a/trio/_subprocess.py +++ b/trio/_subprocess.py @@ -123,7 +123,7 @@ def __init__(self, popen, stdin, stdout, stderr): self.stdout: Optional[ReceiveStream] = stdout self.stderr: Optional[ReceiveStream] = stderr - self.stdio: Optional[StapledStream] = None + self.stdio: Optional[StapledStream[SendStream, ReceiveStream]] = None if self.stdin is not None and self.stdout is not None: self.stdio = StapledStream(self.stdin, self.stdout) From daa6db1f838b3c33f2f49bd3af00a54dcbc7b8fe Mon Sep 17 00:00:00 2001 From: Spencer Brown Date: Fri, 18 Aug 2023 10:40:37 +1000 Subject: [PATCH 10/11] Remove generics here --- trio/_subprocess.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trio/_subprocess.py b/trio/_subprocess.py index 978f7e6188..7cf990fa53 100644 --- a/trio/_subprocess.py +++ b/trio/_subprocess.py @@ -149,7 +149,7 @@ def __init__( self.stdout = stdout self.stderr = stderr - self.stdio: StapledStream[SendStream, ReceiveStream] | None = None + self.stdio: StapledStream | None = None if self.stdin is not None and self.stdout is not None: self.stdio = StapledStream(self.stdin, self.stdout) From 680b5660150214c41f8889fd9147f8d2bdf11942 Mon Sep 17 00:00:00 2001 From: Spencer Brown Date: Sat, 19 Aug 2023 16:03:33 +1000 Subject: [PATCH 11/11] Remove unused type: ignores --- trio/_tests/test_socket.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trio/_tests/test_socket.py b/trio/_tests/test_socket.py index e725918ad7..036098b8e5 100644 --- a/trio/_tests/test_socket.py +++ b/trio/_tests/test_socket.py @@ -378,11 +378,11 @@ def setsockopt_tests(sock): # specifying both with pytest.raises(TypeError, match="invalid value for argument 'value'"): - sock.setsockopt(tsocket.IPPROTO_TCP, tsocket.TCP_NODELAY, False, 5) # type: ignore[call-overload] + sock.setsockopt(tsocket.IPPROTO_TCP, tsocket.TCP_NODELAY, False, 5) # specifying neither with pytest.raises(TypeError, match="invalid value for argument 'value'"): - sock.setsockopt(tsocket.IPPROTO_TCP, tsocket.TCP_NODELAY, None) # type: ignore[call-overload] + sock.setsockopt(tsocket.IPPROTO_TCP, tsocket.TCP_NODELAY, None) async def test_SocketType_dup():