From dbc3d6b7e8b08224297dd0352b00cfbd949bc60b Mon Sep 17 00:00:00 2001
From: jakkdl
Date: Mon, 26 Jun 2023 14:08:36 +0200
Subject: [PATCH 01/11] Add --full-output-file to check_type_completeness.py
for use when developing
---
trio/_tests/check_type_completeness.py | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/trio/_tests/check_type_completeness.py b/trio/_tests/check_type_completeness.py
index d67d11958e..417c06af6e 100755
--- a/trio/_tests/check_type_completeness.py
+++ b/trio/_tests/check_type_completeness.py
@@ -75,6 +75,11 @@ def main(args: argparse.Namespace) -> int:
if res.stderr:
print(res.stderr)
+ if args.full_output_file is not None:
+ with open(args.full_output_file, "w") as file:
+ print(f"Writing full output to {args.full_output_file}")
+ json.dump(current_result, file, sort_keys=True, indent=2)
+
last_result = json.loads(RESULT_FILE.read_text())
for key in "errorCount", "warningCount", "informationCount":
@@ -153,6 +158,7 @@ def main(args: argparse.Namespace) -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--overwrite-file", action="store_true", default=False)
+parser.add_argument("--full-output-file", type=Path, default=None)
args = parser.parse_args()
assert __name__ == "__main__", "This script should be run standalone"
From 42a45cfdccceb55aec2e2bc2a1daa4e68c8dc3fb Mon Sep 17 00:00:00 2001
From: jakkdl
Date: Mon, 26 Jun 2023 14:12:05 +0200
Subject: [PATCH 02/11] _timeouts.py is now type complete
---
trio/_tests/verify_types.json | 10 +++-------
trio/_timeouts.py | 15 ++++++++-------
2 files changed, 11 insertions(+), 14 deletions(-)
diff --git a/trio/_tests/verify_types.json b/trio/_tests/verify_types.json
index 7b0c39d20d..569cba20dd 100644
--- a/trio/_tests/verify_types.json
+++ b/trio/_tests/verify_types.json
@@ -7,11 +7,11 @@
"warningCount": 0
},
"typeCompleteness": {
- "completenessScore": 0.8155339805825242,
+ "completenessScore": 0.8220064724919094,
"exportedSymbolCounts": {
"withAmbiguousType": 1,
- "withKnownType": 504,
- "withUnknownType": 113
+ "withKnownType": 508,
+ "withUnknownType": 109
},
"ignoreUnknownTypesFromImports": true,
"missingClassDocStringCount": 1,
@@ -77,10 +77,6 @@
"trio._core._run.Nursery.__del__",
"trio.move_on_at",
"trio.move_on_after",
- "trio.sleep_forever",
- "trio.sleep_until",
- "trio.sleep",
- "trio.fail_after",
"trio._sync.Event",
"trio._sync.Event.is_set",
"trio._sync.Event.wait",
diff --git a/trio/_timeouts.py b/trio/_timeouts.py
index ad31e78404..911eb16a56 100644
--- a/trio/_timeouts.py
+++ b/trio/_timeouts.py
@@ -1,10 +1,11 @@
import math
from contextlib import contextmanager
+from typing import Iterator, ContextManager
import trio
-def move_on_at(deadline):
+def move_on_at(deadline: float) -> trio.CancelScope:
"""Use as a context manager to create a cancel scope with the given
absolute deadline.
@@ -20,7 +21,7 @@ def move_on_at(deadline):
return trio.CancelScope(deadline=deadline)
-def move_on_after(seconds):
+def move_on_after(seconds: float) -> trio.CancelScope:
"""Use as a context manager to create a cancel scope whose deadline is
set to now + *seconds*.
@@ -36,7 +37,7 @@ def move_on_after(seconds):
return move_on_at(trio.current_time() + seconds)
-async def sleep_forever():
+async def sleep_forever() -> None:
"""Pause execution of the current task forever (or until cancelled).
Equivalent to calling ``await sleep(math.inf)``.
@@ -45,7 +46,7 @@ async def sleep_forever():
await trio.lowlevel.wait_task_rescheduled(lambda _: trio.lowlevel.Abort.SUCCEEDED)
-async def sleep_until(deadline):
+async def sleep_until(deadline: float) -> None:
"""Pause execution of the current task until the given time.
The difference between :func:`sleep` and :func:`sleep_until` is that the
@@ -65,7 +66,7 @@ async def sleep_until(deadline):
await sleep_forever()
-async def sleep(seconds):
+async def sleep(seconds: float) -> None:
"""Pause execution of the current task for the given number of seconds.
Args:
@@ -92,7 +93,7 @@ class TooSlowError(Exception):
@contextmanager
-def fail_at(deadline):
+def fail_at(deadline: float) -> Iterator[trio.CancelScope]:
"""Creates a cancel scope with the given deadline, and raises an error if it
is actually cancelled.
@@ -120,7 +121,7 @@ def fail_at(deadline):
raise TooSlowError
-def fail_after(seconds):
+def fail_after(seconds: float) -> ContextManager[trio.CancelScope]:
"""Creates a cancel scope with the given timeout, and raises an error if
it is actually cancelled.
From 2b9185fe961a33d2c652ef61ec55be1cd79582bc Mon Sep 17 00:00:00 2001
From: jakkdl
Date: Mon, 26 Jun 2023 14:29:33 +0200
Subject: [PATCH 03/11] trio/_core and trio/_tests now type complete
---
trio/_core/_exceptions.py | 2 +-
trio/_tests/verify_types.json | 29 +++++------------------------
trio/_util.py | 7 +++++--
3 files changed, 11 insertions(+), 27 deletions(-)
diff --git a/trio/_core/_exceptions.py b/trio/_core/_exceptions.py
index 6189c484b4..3d5c1d831d 100644
--- a/trio/_core/_exceptions.py
+++ b/trio/_core/_exceptions.py
@@ -61,7 +61,7 @@ class Cancelled(BaseException, metaclass=NoPublicConstructor):
"""
- def __str__(self):
+ def __str__(self) -> str:
return "Cancelled"
diff --git a/trio/_tests/verify_types.json b/trio/_tests/verify_types.json
index 569cba20dd..2023b59885 100644
--- a/trio/_tests/verify_types.json
+++ b/trio/_tests/verify_types.json
@@ -7,11 +7,11 @@
"warningCount": 0
},
"typeCompleteness": {
- "completenessScore": 0.8220064724919094,
+ "completenessScore": 0.8252427184466019,
"exportedSymbolCounts": {
"withAmbiguousType": 1,
- "withKnownType": 508,
- "withUnknownType": 109
+ "withKnownType": 510,
+ "withUnknownType": 107
},
"ignoreUnknownTypesFromImports": true,
"missingClassDocStringCount": 1,
@@ -46,19 +46,13 @@
],
"otherSymbolCounts": {
"withAmbiguousType": 15,
- "withKnownType": 231,
- "withUnknownType": 236
+ "withKnownType": 238,
+ "withUnknownType": 229
},
"packageName": "trio",
"symbols": [
- "trio._core._exceptions.Cancelled",
- "trio._core._exceptions.Cancelled.__str__",
- "trio._util.NoPublicConstructor",
- "trio._util.NoPublicConstructor.__call__",
- "trio._util.Final.__new__",
"trio.run",
"trio.open_nursery",
- "trio._core._run.CancelScope",
"trio._core._run.CancelScope.cancelled_caught",
"trio._core._run.CancelScope.__exit__",
"trio._core._run.CancelScope.__repr__",
@@ -68,7 +62,6 @@
"trio._core._run._TaskStatusIgnored.__repr__",
"trio._core._run._TaskStatusIgnored.started",
"trio.current_time",
- "trio._core._run.Nursery",
"trio._core._run.Nursery.__init__",
"trio._core._run.Nursery.child_tasks",
"trio._core._run.Nursery.parent_task",
@@ -77,18 +70,15 @@
"trio._core._run.Nursery.__del__",
"trio.move_on_at",
"trio.move_on_after",
- "trio._sync.Event",
"trio._sync.Event.is_set",
"trio._sync.Event.wait",
"trio._sync.Event.statistics",
- "trio._sync.CapacityLimiter",
"trio._sync.CapacityLimiter.__init__",
"trio._sync.CapacityLimiter.__repr__",
"trio._sync.CapacityLimiter.total_tokens",
"trio._sync.CapacityLimiter.borrowed_tokens",
"trio._sync.CapacityLimiter.available_tokens",
"trio._sync.CapacityLimiter.statistics",
- "trio._sync.Semaphore",
"trio._sync.Semaphore.__init__",
"trio._sync.Semaphore.__repr__",
"trio._sync.Semaphore.value",
@@ -99,7 +89,6 @@
"trio._sync._LockImpl.locked",
"trio._sync._LockImpl.statistics",
"trio._sync.StrictFIFOLock",
- "trio._sync.Condition",
"trio._sync.Condition.__init__",
"trio._sync.Condition.locked",
"trio._sync.Condition.acquire_nowait",
@@ -161,7 +150,6 @@
"trio._path.Path.__bytes__",
"trio._path.Path.__truediv__",
"trio._path.Path.__rtruediv__",
- "trio._path.AsyncAutoWrapperType",
"trio._path.AsyncAutoWrapperType.__init__",
"trio._path.AsyncAutoWrapperType.generate_forwards",
"trio._path.AsyncAutoWrapperType.generate_wraps",
@@ -199,7 +187,6 @@
"trio._ssl.SSLListener.__init__",
"trio._ssl.SSLListener.accept",
"trio._ssl.SSLListener.aclose",
- "trio._dtls.DTLSEndpoint",
"trio._dtls.DTLSEndpoint.__init__",
"trio._dtls.DTLSEndpoint.__del__",
"trio._dtls.DTLSEndpoint.close",
@@ -250,7 +237,6 @@
"trio.from_thread.run_sync",
"trio.lowlevel.cancel_shielded_checkpoint",
"trio.lowlevel.currently_ki_protected",
- "trio._core._run.Task",
"trio._core._run.Task.coro",
"trio._core._run.Task.name",
"trio._core._run.Task.context",
@@ -262,13 +248,11 @@
"trio._core._run.Task.iter_await_frames",
"trio.lowlevel.checkpoint",
"trio.lowlevel.current_task",
- "trio._core._parking_lot.ParkingLot",
"trio._core._parking_lot.ParkingLot.__len__",
"trio._core._parking_lot.ParkingLot.__bool__",
"trio._core._parking_lot.ParkingLot.unpark_all",
"trio._core._parking_lot.ParkingLot.repark_all",
"trio._core._parking_lot.ParkingLot.statistics",
- "trio._core._unbounded_queue.UnboundedQueue",
"trio._core._unbounded_queue.UnboundedQueue.__repr__",
"trio._core._unbounded_queue.UnboundedQueue.qsize",
"trio._core._unbounded_queue.UnboundedQueue.empty",
@@ -277,12 +261,10 @@
"trio._core._unbounded_queue.UnboundedQueue.statistics",
"trio._core._unbounded_queue.UnboundedQueue.__aiter__",
"trio._core._unbounded_queue.UnboundedQueue.__anext__",
- "trio._core._local.RunVar",
"trio._core._local.RunVar.get",
"trio._core._local.RunVar.set",
"trio._core._local.RunVar.reset",
"trio._core._local.RunVar.__repr__",
- "trio._core._entry_queue.TrioToken",
"trio._core._entry_queue.TrioToken.run_sync_soon",
"trio.lowlevel.current_trio_token",
"trio.lowlevel.temporarily_detach_coroutine_object",
@@ -325,7 +307,6 @@
"trio.testing.trio_test",
"trio.testing.assert_checkpoints",
"trio.testing.assert_no_checkpoints",
- "trio.testing._sequencer.Sequencer",
"trio.testing.check_one_way_stream",
"trio.testing.check_two_way_stream",
"trio.testing.check_half_closeable_stream",
diff --git a/trio/_util.py b/trio/_util.py
index b60e0104e8..bd8ee2c341 100644
--- a/trio/_util.py
+++ b/trio/_util.py
@@ -1,4 +1,5 @@
# Little utilities we use internally
+from __future__ import annotations
from abc import ABCMeta
import os
@@ -280,7 +281,9 @@ class SomeClass(metaclass=Final):
- TypeError if a subclass is created
"""
- def __new__(cls, name, bases, cls_namespace):
+ def __new__(
+ cls, name: str, bases: tuple[type, ...], cls_namespace: dict[str, t.Any]
+ ) -> Final:
for base in bases:
if isinstance(base, Final):
raise TypeError(
@@ -312,7 +315,7 @@ class SomeClass(metaclass=NoPublicConstructor):
- TypeError if a subclass or an instance is created.
"""
- def __call__(cls, *args, **kwargs):
+ def __call__(cls, *args: t.Any, **kwargs: t.Any) -> None:
raise TypeError(
f"{cls.__module__}.{cls.__qualname__} has no public constructor"
)
From 0964edd76fc04282c66124ec7aacc0e9268b4713 Mon Sep 17 00:00:00 2001
From: jakkdl
Date: Mon, 26 Jun 2023 15:03:47 +0200
Subject: [PATCH 04/11] open_nursery, move_on_at, move_on_after and CancelScope
now type complete
---
trio/_core/_run.py | 44 +++++++++++++++-----------
trio/_tests/check_type_completeness.py | 12 +++++--
trio/_tests/verify_types.json | 20 ++++--------
3 files changed, 42 insertions(+), 34 deletions(-)
diff --git a/trio/_core/_run.py b/trio/_core/_run.py
index c07e29ab97..f73a7330da 100644
--- a/trio/_core/_run.py
+++ b/trio/_core/_run.py
@@ -16,7 +16,8 @@
from heapq import heapify, heappop, heappush
from math import inf
from time import perf_counter
-from typing import TYPE_CHECKING, Any, NoReturn, TypeVar
+from typing import TYPE_CHECKING, Any, NoReturn, TypeVar, AsyncContextManager, Iterator
+from types import TracebackType
import attr
from outcome import Error, Outcome, Value, capture
@@ -475,15 +476,15 @@ class CancelScope(metaclass=Final):
has been entered yet, and changes take immediate effect.
"""
- _cancel_status = attr.ib(default=None, init=False)
- _has_been_entered = attr.ib(default=False, init=False)
- _registered_deadline = attr.ib(default=inf, init=False)
- _cancel_called = attr.ib(default=False, init=False)
- cancelled_caught = attr.ib(default=False, init=False)
+ _cancel_status: CancelStatus | None = attr.ib(default=None, init=False)
+ _has_been_entered: bool = attr.ib(default=False, init=False)
+ _registered_deadline: float = attr.ib(default=inf, init=False)
+ _cancel_called: bool = attr.ib(default=False, init=False)
+ cancelled_caught: bool = attr.ib(default=False, init=False)
# Constructor arguments:
- _deadline = attr.ib(default=inf, kw_only=True)
- _shield = attr.ib(default=False, kw_only=True)
+ _deadline: float = attr.ib(default=inf, kw_only=True)
+ _shield: bool = attr.ib(default=False, kw_only=True)
@enable_ki_protection
def __enter__(self):
@@ -573,7 +574,12 @@ def _close(self, exc):
self._cancel_status = None
return exc
- def __exit__(self, etype, exc, tb):
+ def __exit__(
+ self,
+ etype: type[BaseException] | None,
+ exc: BaseException | None,
+ tb: TracebackType | None,
+ ) -> bool:
# NB: NurseryManager calls _close() directly rather than __exit__(),
# so __exit__() must be just _close() plus this logic for adapting
# the exception-filtering result to the context manager API.
@@ -607,7 +613,7 @@ def __exit__(self, etype, exc, tb):
# TODO: check if PEP558 changes the need for this call
# https://github.com/python/cpython/pull/3640
- def __repr__(self):
+ def __repr__(self) -> str:
if self._cancel_status is not None:
binding = "active"
elif self._has_been_entered:
@@ -634,7 +640,7 @@ def __repr__(self):
@contextmanager
@enable_ki_protection
- def _might_change_registered_deadline(self):
+ def _might_change_registered_deadline(self) -> Iterator[None]:
try:
yield
finally:
@@ -658,7 +664,7 @@ def _might_change_registered_deadline(self):
runner.force_guest_tick_asap()
@property
- def deadline(self):
+ def deadline(self) -> float:
"""Read-write, :class:`float`. An absolute time on the current
run's clock at which this scope will automatically become
cancelled. You can adjust the deadline by modifying this
@@ -684,12 +690,12 @@ def deadline(self):
return self._deadline
@deadline.setter
- def deadline(self, new_deadline):
+ def deadline(self, new_deadline: float) -> None:
with self._might_change_registered_deadline():
self._deadline = float(new_deadline)
@property
- def shield(self):
+ def shield(self) -> bool:
"""Read-write, :class:`bool`, default :data:`False`. So long as
this is set to :data:`True`, then the code inside this scope
will not receive :exc:`~trio.Cancelled` exceptions from scopes
@@ -714,7 +720,7 @@ def shield(self):
@shield.setter
@enable_ki_protection
- def shield(self, new_value):
+ def shield(self, new_value: bool) -> None:
if not isinstance(new_value, bool):
raise TypeError("shield must be a bool")
self._shield = new_value
@@ -722,7 +728,7 @@ def shield(self, new_value):
self._cancel_status.recalculate()
@enable_ki_protection
- def cancel(self):
+ def cancel(self) -> None:
"""Cancels this scope immediately.
This method is idempotent, i.e., if the scope was already
@@ -736,7 +742,7 @@ def cancel(self):
self._cancel_status.recalculate()
@property
- def cancel_called(self):
+ def cancel_called(self) -> bool:
"""Readonly :class:`bool`. Records whether cancellation has been
requested for this scope, either by an explicit call to
:meth:`cancel` or by the deadline expiring.
@@ -890,7 +896,9 @@ def __exit__(self): # pragma: no cover
assert False, """Never called, but should be defined"""
-def open_nursery(strict_exception_groups=None):
+def open_nursery(
+ strict_exception_groups: bool | None = None,
+) -> AsyncContextManager[Nursery]:
"""Returns an async context manager which must be used to create a
new `Nursery`.
diff --git a/trio/_tests/check_type_completeness.py b/trio/_tests/check_type_completeness.py
index 417c06af6e..65d1383b91 100755
--- a/trio/_tests/check_type_completeness.py
+++ b/trio/_tests/check_type_completeness.py
@@ -77,8 +77,16 @@ def main(args: argparse.Namespace) -> int:
if args.full_output_file is not None:
with open(args.full_output_file, "w") as file:
- print(f"Writing full output to {args.full_output_file}")
- json.dump(current_result, file, sort_keys=True, indent=2)
+ json.dump(
+ [
+ sym
+ for sym in current_result["typeCompleteness"]["symbols"]
+ if sym["diagnostics"]
+ ],
+ file,
+ sort_keys=True,
+ indent=2,
+ )
last_result = json.loads(RESULT_FILE.read_text())
diff --git a/trio/_tests/verify_types.json b/trio/_tests/verify_types.json
index 2023b59885..e54af12444 100644
--- a/trio/_tests/verify_types.json
+++ b/trio/_tests/verify_types.json
@@ -7,11 +7,11 @@
"warningCount": 0
},
"typeCompleteness": {
- "completenessScore": 0.8252427184466019,
+ "completenessScore": 0.8317152103559871,
"exportedSymbolCounts": {
"withAmbiguousType": 1,
- "withKnownType": 510,
- "withUnknownType": 107
+ "withKnownType": 514,
+ "withUnknownType": 103
},
"ignoreUnknownTypesFromImports": true,
"missingClassDocStringCount": 1,
@@ -45,19 +45,13 @@
}
],
"otherSymbolCounts": {
- "withAmbiguousType": 15,
- "withKnownType": 238,
- "withUnknownType": 229
+ "withAmbiguousType": 14,
+ "withKnownType": 244,
+ "withUnknownType": 224
},
"packageName": "trio",
"symbols": [
"trio.run",
- "trio.open_nursery",
- "trio._core._run.CancelScope.cancelled_caught",
- "trio._core._run.CancelScope.__exit__",
- "trio._core._run.CancelScope.__repr__",
- "trio._core._run.CancelScope.deadline",
- "trio._core._run.CancelScope.cancel_called",
"trio.current_effective_deadline",
"trio._core._run._TaskStatusIgnored.__repr__",
"trio._core._run._TaskStatusIgnored.started",
@@ -68,8 +62,6 @@
"trio._core._run.Nursery.start_soon",
"trio._core._run.Nursery.start",
"trio._core._run.Nursery.__del__",
- "trio.move_on_at",
- "trio.move_on_after",
"trio._sync.Event.is_set",
"trio._sync.Event.wait",
"trio._sync.Event.statistics",
From 0ffbb368e5130645f98b37ac3e69a8a7ca836e16 Mon Sep 17 00:00:00 2001
From: jakkdl
Date: Mon, 26 Jun 2023 15:09:40 +0200
Subject: [PATCH 05/11] rename --full-output-file to --full-diagnostics-file
---
trio/_tests/check_type_completeness.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/trio/_tests/check_type_completeness.py b/trio/_tests/check_type_completeness.py
index 65d1383b91..15b2da2d94 100755
--- a/trio/_tests/check_type_completeness.py
+++ b/trio/_tests/check_type_completeness.py
@@ -75,8 +75,8 @@ def main(args: argparse.Namespace) -> int:
if res.stderr:
print(res.stderr)
- if args.full_output_file is not None:
- with open(args.full_output_file, "w") as file:
+ if args.full_diagnostics_file is not None:
+ with open(args.full_diagnostics_file, "w") as file:
json.dump(
[
sym
@@ -166,7 +166,7 @@ def main(args: argparse.Namespace) -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--overwrite-file", action="store_true", default=False)
-parser.add_argument("--full-output-file", type=Path, default=None)
+parser.add_argument("--full-diagnostics-file", type=Path, default=None)
args = parser.parse_args()
assert __name__ == "__main__", "This script should be run standalone"
From c75db152d9cc539f0aec531df9307aef56473420 Mon Sep 17 00:00:00 2001
From: jakkdl
Date: Mon, 26 Jun 2023 18:10:29 +0200
Subject: [PATCH 06/11] Any -> object
---
trio/_util.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/trio/_util.py b/trio/_util.py
index bd8ee2c341..89a2dea7de 100644
--- a/trio/_util.py
+++ b/trio/_util.py
@@ -282,7 +282,7 @@ class SomeClass(metaclass=Final):
"""
def __new__(
- cls, name: str, bases: tuple[type, ...], cls_namespace: dict[str, t.Any]
+ cls, name: str, bases: tuple[type, ...], cls_namespace: dict[str, object]
) -> Final:
for base in bases:
if isinstance(base, Final):
@@ -315,12 +315,12 @@ class SomeClass(metaclass=NoPublicConstructor):
- TypeError if a subclass or an instance is created.
"""
- def __call__(cls, *args: t.Any, **kwargs: t.Any) -> None:
+ def __call__(cls, *args: object, **kwargs: object) -> None:
raise TypeError(
f"{cls.__module__}.{cls.__qualname__} has no public constructor"
)
- def _create(cls: t.Type[T], *args: t.Any, **kwargs: t.Any) -> T:
+ def _create(cls: t.Type[T], *args: object, **kwargs: object) -> T:
return super().__call__(*args, **kwargs) # type: ignore
From 61bbadb15a996510688065c304499e01ccee9423 Mon Sep 17 00:00:00 2001
From: jakkdl
Date: Mon, 26 Jun 2023 18:14:02 +0200
Subject: [PATCH 07/11] import Iterator from collections.abc
---
trio/_core/_run.py | 3 ++-
trio/_timeouts.py | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/trio/_core/_run.py b/trio/_core/_run.py
index f73a7330da..58ee1b4543 100644
--- a/trio/_core/_run.py
+++ b/trio/_core/_run.py
@@ -16,8 +16,9 @@
from heapq import heapify, heappop, heappush
from math import inf
from time import perf_counter
-from typing import TYPE_CHECKING, Any, NoReturn, TypeVar, AsyncContextManager, Iterator
+from typing import TYPE_CHECKING, Any, NoReturn, TypeVar, AsyncContextManager
from types import TracebackType
+from collections.abc import Iterator
import attr
from outcome import Error, Outcome, Value, capture
diff --git a/trio/_timeouts.py b/trio/_timeouts.py
index 911eb16a56..b9fbbe38b0 100644
--- a/trio/_timeouts.py
+++ b/trio/_timeouts.py
@@ -1,6 +1,7 @@
import math
from contextlib import contextmanager
-from typing import Iterator, ContextManager
+from typing import ContextManager
+from collections.abc import Iterator
import trio
From 88fecfc8a035d4eecea9a1eacc062caf36d43826 Mon Sep 17 00:00:00 2001
From: jakkdl
Date: Mon, 26 Jun 2023 18:18:23 +0200
Subject: [PATCH 08/11] typing.[Async]ContextManager ->
contextlib.Abstract[Async]ContextManager
---
trio/_core/_run.py | 5 +++--
trio/_timeouts.py | 6 +++---
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/trio/_core/_run.py b/trio/_core/_run.py
index 58ee1b4543..2727fe1e89 100644
--- a/trio/_core/_run.py
+++ b/trio/_core/_run.py
@@ -16,9 +16,10 @@
from heapq import heapify, heappop, heappush
from math import inf
from time import perf_counter
-from typing import TYPE_CHECKING, Any, NoReturn, TypeVar, AsyncContextManager
+from typing import TYPE_CHECKING, Any, NoReturn, TypeVar
from types import TracebackType
from collections.abc import Iterator
+from contextlib import AbstractAsyncContextManager
import attr
from outcome import Error, Outcome, Value, capture
@@ -899,7 +900,7 @@ def __exit__(self): # pragma: no cover
def open_nursery(
strict_exception_groups: bool | None = None,
-) -> AsyncContextManager[Nursery]:
+) -> AbstractAsyncContextManager[Nursery]:
"""Returns an async context manager which must be used to create a
new `Nursery`.
diff --git a/trio/_timeouts.py b/trio/_timeouts.py
index b9fbbe38b0..5cc0d48475 100644
--- a/trio/_timeouts.py
+++ b/trio/_timeouts.py
@@ -1,6 +1,6 @@
+from __future__ import annotations
import math
-from contextlib import contextmanager
-from typing import ContextManager
+from contextlib import contextmanager, AbstractContextManager
from collections.abc import Iterator
import trio
@@ -122,7 +122,7 @@ def fail_at(deadline: float) -> Iterator[trio.CancelScope]:
raise TooSlowError
-def fail_after(seconds: float) -> ContextManager[trio.CancelScope]:
+def fail_after(seconds: float) -> AbstractContextManager[trio.CancelScope]:
"""Creates a cancel scope with the given timeout, and raises an error if
it is actually cancelled.
From fb21df861e31030fc5b1fda04265ef8c0174eade Mon Sep 17 00:00:00 2001
From: jakkdl
Date: Sat, 1 Jul 2023 12:20:12 +0200
Subject: [PATCH 09/11] workaround for PyCharm
---
trio/_timeouts.py | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/trio/_timeouts.py b/trio/_timeouts.py
index 5cc0d48475..738f2652d7 100644
--- a/trio/_timeouts.py
+++ b/trio/_timeouts.py
@@ -1,7 +1,9 @@
from __future__ import annotations
+
import math
-from contextlib import contextmanager, AbstractContextManager
from collections.abc import Iterator
+from contextlib import AbstractContextManager, contextmanager
+from typing import TYPE_CHECKING
import trio
@@ -94,7 +96,7 @@ class TooSlowError(Exception):
@contextmanager
-def fail_at(deadline: float) -> Iterator[trio.CancelScope]:
+def _fail_at(deadline: float) -> Iterator[trio.CancelScope]:
"""Creates a cancel scope with the given deadline, and raises an error if it
is actually cancelled.
@@ -122,6 +124,17 @@ def fail_at(deadline: float) -> Iterator[trio.CancelScope]:
raise TooSlowError
+# workaround for PyCharm not being able to infer return type from @contextmanager
+# see https://youtrack.jetbrains.com/issue/PY-36444/PyCharm-doesnt-infer-types-when-using-contextlib.contextmanager-decorator
+if TYPE_CHECKING:
+
+ def fail_at(deadline: float) -> AbstractContextManager[trio.CancelScope]:
+ return _fail_at(deadline)
+
+else:
+ fail_at = _fail_at
+
+
def fail_after(seconds: float) -> AbstractContextManager[trio.CancelScope]:
"""Creates a cancel scope with the given timeout, and raises an error if
it is actually cancelled.
From 5195433ca57e50fde741d6090ba49a6494ca4b26 Mon Sep 17 00:00:00 2001
From: jakkdl
Date: Sat, 1 Jul 2023 12:46:18 +0200
Subject: [PATCH 10/11] different workaround
---
trio/_timeouts.py | 17 +++++------------
1 file changed, 5 insertions(+), 12 deletions(-)
diff --git a/trio/_timeouts.py b/trio/_timeouts.py
index 738f2652d7..44dfc7be0f 100644
--- a/trio/_timeouts.py
+++ b/trio/_timeouts.py
@@ -95,8 +95,9 @@ class TooSlowError(Exception):
"""
-@contextmanager
-def _fail_at(deadline: float) -> Iterator[trio.CancelScope]:
+# workaround for PyCharm not being able to infer return type from @contextmanager
+# see https://youtrack.jetbrains.com/issue/PY-36444/PyCharm-doesnt-infer-types-when-using-contextlib.contextmanager-decorator
+def fail_at(deadline: float) -> AbstractContextManager[trio.CancelScope]: # type: ignore[misc]
"""Creates a cancel scope with the given deadline, and raises an error if it
is actually cancelled.
@@ -117,22 +118,14 @@ def _fail_at(deadline: float) -> Iterator[trio.CancelScope]:
ValueError: if deadline is NaN.
"""
-
with move_on_at(deadline) as scope:
yield scope
if scope.cancelled_caught:
raise TooSlowError
-# workaround for PyCharm not being able to infer return type from @contextmanager
-# see https://youtrack.jetbrains.com/issue/PY-36444/PyCharm-doesnt-infer-types-when-using-contextlib.contextmanager-decorator
-if TYPE_CHECKING:
-
- def fail_at(deadline: float) -> AbstractContextManager[trio.CancelScope]:
- return _fail_at(deadline)
-
-else:
- fail_at = _fail_at
+if not TYPE_CHECKING:
+ fail_at = contextmanager(fail_at)
def fail_after(seconds: float) -> AbstractContextManager[trio.CancelScope]:
From 2773e5475866ef107223348df2eed3a6438475eb Mon Sep 17 00:00:00 2001
From: jakkdl
Date: Mon, 3 Jul 2023 13:37:04 +0200
Subject: [PATCH 11/11] fix f401 unused import
---
trio/_timeouts.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/trio/_timeouts.py b/trio/_timeouts.py
index 44dfc7be0f..1d03b2f2e3 100644
--- a/trio/_timeouts.py
+++ b/trio/_timeouts.py
@@ -1,7 +1,6 @@
from __future__ import annotations
import math
-from collections.abc import Iterator
from contextlib import AbstractContextManager, contextmanager
from typing import TYPE_CHECKING