From 5a344649497d3c7da194640a4f2a570f2126fa5a Mon Sep 17 00:00:00 2001 From: Agnes Natasya Date: Fri, 26 Jul 2024 23:13:27 +0800 Subject: [PATCH 01/10] move_on_ and fail_ context managers accepts shield arg --- docs/.DS_Store | Bin 0 -> 6148 bytes docs/source/reference-core.rst | 3 +- newsfragments/3040.feature.rst | 1 + src/trio/_tests/test_timeouts.py | 60 +++++++++++++++++++++++++++++++ src/trio/_timeouts.py | 22 +++++++----- 5 files changed, 76 insertions(+), 10 deletions(-) create mode 100644 docs/.DS_Store create mode 100644 newsfragments/3040.feature.rst diff --git a/docs/.DS_Store b/docs/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..ebffb0716ea3dfe208129a2a6daa03d378dcd241 GIT binary patch literal 6148 zcmeHK%}T>S5Z<+|O({YS3Oz1(E!ZC^6fYsx7cim+m70*E!I&*gVh^Q|v%Zi|;`2DO zyMY#iM-e*%yWi~m>}Ed5{xHV4n}>bIY{r-c4UwZ#A!x32?U`UiuI31XWjYUH8B|R3 zH%<8M4HmGRMJ#5U-~SQJ<0#E~y-&VZt2g$WR?})*_ui9SdYPZ)sp~IpadahR9F)2r zTt~Cz)IL0yN#;k%Y@rgOa0VfFH&GJGr7QC!OjWL@9ahU~P3_KVH5iY&VmR)vyJ9sS z^t$47I9jh;*3t3F+2!;(eo5q;CXxf=N)8N`@D9pGMX%l>iDmK#)-t1vBqRoi0b+m{ z*i8n^d0@47vwW(W7$63IU;y_A0S(bHSZGvR2XuISMt>a<1$2B%APR$y!9pW=K)6l? z)T!J&F}O|#yD)K%!9t@>XI!le^O%*(#|u}hgI%a_#vP5+69dG+HUl+1wDJ7EfM2Ha zk-wcnBVvFU_-738`ox>KP?R}azm None: await check_takes_about(sleep_3, TARGET) +@slow +async def test_move_on_after_shields_from_outer() -> None: + duration = 0.1 + + async def task() -> None: + with _core.CancelScope() as outer, move_on_after(TARGET, shield=True) as inner: + outer.cancel() + # The outer scope is cancelled, but this task is protected by the + # shield, so it manages to get to sleep for 'duration' seconds + await trio.sleep(duration) + # now when we unshield, it should abort the sleep. + inner.shield = False + + # Check that the task takes only about 'duration' seconds + await check_takes_about(task, duration) + + +@slow +async def test_move_on_after_moves_on_even_if_shielded() -> None: + async def task() -> None: + with _core.CancelScope() as outer, move_on_after(TARGET, shield=True): + outer.cancel() + # The outer scope is cancelled, but this task is protected by the + # shield, so it manages to get to sleep until deadline is met + await sleep_forever() + + await check_takes_about(task, TARGET) + + +@slow +async def test_fail_after_exits_shields_from_outer() -> None: + duration = 0.1 + + async def task() -> None: + with _core.CancelScope() as outer, fail_after(TARGET, shield=True) as inner: + outer.cancel() + # The outer scope is cancelled, but this task is protected by the + # shield, so it manages to get to sleep for 'duration' seconds + await trio.sleep(duration) + # now when we unshield, it should abort the sleep. + inner.shield = False + + # Check that the task takes only about 'duration' seconds + await check_takes_about(task, duration) + + +@slow +async def test_fail_after_fails_even_if_shielded() -> None: + async def task() -> None: + with pytest.raises(TooSlowError), _core.CancelScope() as outer, fail_after( + TARGET, shield=True + ): + outer.cancel() + # The outer scope is cancelled, but this task is protected by the + # shield, so it manages to get to sleep until deadline is met + await sleep_forever() + + await check_takes_about(task, TARGET) + + @slow async def test_fail() -> None: async def sleep_4() -> None: diff --git a/src/trio/_timeouts.py b/src/trio/_timeouts.py index 1d03b2f2e3..9384345561 100644 --- a/src/trio/_timeouts.py +++ b/src/trio/_timeouts.py @@ -7,12 +7,13 @@ import trio -def move_on_at(deadline: float) -> trio.CancelScope: +def move_on_at(deadline: float, shield: bool = False) -> trio.CancelScope: """Use as a context manager to create a cancel scope with the given absolute deadline. Args: deadline (float): The deadline. + shield (bool): Whether the cancel scope created is shielded. Raises: ValueError: if deadline is NaN. @@ -20,15 +21,16 @@ def move_on_at(deadline: float) -> trio.CancelScope: """ if math.isnan(deadline): raise ValueError("deadline must not be NaN") - return trio.CancelScope(deadline=deadline) + return trio.CancelScope(deadline=deadline, shield=shield) -def move_on_after(seconds: float) -> trio.CancelScope: +def move_on_after(seconds: float, shield: bool = False) -> trio.CancelScope: """Use as a context manager to create a cancel scope whose deadline is set to now + *seconds*. Args: seconds (float): The timeout. + shield (bool): Whether the cancel scope created is shielded. Raises: ValueError: if timeout is less than zero or NaN. @@ -36,7 +38,7 @@ def move_on_after(seconds: float) -> trio.CancelScope: """ if seconds < 0: raise ValueError("timeout must be non-negative") - return move_on_at(trio.current_time() + seconds) + return move_on_at(trio.current_time() + seconds, shield=shield) async def sleep_forever() -> None: @@ -96,7 +98,7 @@ class TooSlowError(Exception): # 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] +def fail_at(deadline: float, shield: bool = False) -> AbstractContextManager[trio.CancelScope]: # type: ignore[misc] """Creates a cancel scope with the given deadline, and raises an error if it is actually cancelled. @@ -110,6 +112,7 @@ def fail_at(deadline: float) -> AbstractContextManager[trio.CancelScope]: # typ Args: deadline (float): The deadline. + shield (bool): Whether the cancel scope created is shielded. Raises: TooSlowError: if a :exc:`Cancelled` exception is raised in this scope @@ -117,7 +120,7 @@ def fail_at(deadline: float) -> AbstractContextManager[trio.CancelScope]: # typ ValueError: if deadline is NaN. """ - with move_on_at(deadline) as scope: + with move_on_at(deadline, shield=shield) as scope: yield scope if scope.cancelled_caught: raise TooSlowError @@ -127,7 +130,9 @@ def fail_at(deadline: float) -> AbstractContextManager[trio.CancelScope]: # typ fail_at = contextmanager(fail_at) -def fail_after(seconds: float) -> AbstractContextManager[trio.CancelScope]: +def fail_after( + seconds: float, shield: bool = False +) -> AbstractContextManager[trio.CancelScope]: """Creates a cancel scope with the given timeout, and raises an error if it is actually cancelled. @@ -140,6 +145,7 @@ def fail_after(seconds: float) -> AbstractContextManager[trio.CancelScope]: Args: seconds (float): The timeout. + shield (bool): Whether the cancel scope created is shielded. Raises: TooSlowError: if a :exc:`Cancelled` exception is raised in this scope @@ -149,4 +155,4 @@ def fail_after(seconds: float) -> AbstractContextManager[trio.CancelScope]: """ if seconds < 0: raise ValueError("timeout must be non-negative") - return fail_at(trio.current_time() + seconds) + return fail_at(trio.current_time() + seconds, shield=shield) From 1d46a88b3787d686c98db3672f9454022b1e3e50 Mon Sep 17 00:00:00 2001 From: Agnes Natasya Date: Sat, 27 Jul 2024 08:37:56 +0800 Subject: [PATCH 02/10] make it a kwarg --- docs/.DS_Store | Bin 6148 -> 0 bytes newsfragments/3040.feature.rst | 2 +- src/trio/_timeouts.py | 8 ++++---- 3 files changed, 5 insertions(+), 5 deletions(-) delete mode 100644 docs/.DS_Store diff --git a/docs/.DS_Store b/docs/.DS_Store deleted file mode 100644 index ebffb0716ea3dfe208129a2a6daa03d378dcd241..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}T>S5Z<+|O({YS3Oz1(E!ZC^6fYsx7cim+m70*E!I&*gVh^Q|v%Zi|;`2DO zyMY#iM-e*%yWi~m>}Ed5{xHV4n}>bIY{r-c4UwZ#A!x32?U`UiuI31XWjYUH8B|R3 zH%<8M4HmGRMJ#5U-~SQJ<0#E~y-&VZt2g$WR?})*_ui9SdYPZ)sp~IpadahR9F)2r zTt~Cz)IL0yN#;k%Y@rgOa0VfFH&GJGr7QC!OjWL@9ahU~P3_KVH5iY&VmR)vyJ9sS z^t$47I9jh;*3t3F+2!;(eo5q;CXxf=N)8N`@D9pGMX%l>iDmK#)-t1vBqRoi0b+m{ z*i8n^d0@47vwW(W7$63IU;y_A0S(bHSZGvR2XuISMt>a<1$2B%APR$y!9pW=K)6l? z)T!J&F}O|#yD)K%!9t@>XI!le^O%*(#|u}hgI%a_#vP5+69dG+HUl+1wDJ7EfM2Ha zk-wcnBVvFU_-738`ox>KP?R}azm trio.CancelScope: +def move_on_at(deadline: float, *, shield: bool = False) -> trio.CancelScope: """Use as a context manager to create a cancel scope with the given absolute deadline. @@ -24,7 +24,7 @@ def move_on_at(deadline: float, shield: bool = False) -> trio.CancelScope: return trio.CancelScope(deadline=deadline, shield=shield) -def move_on_after(seconds: float, shield: bool = False) -> trio.CancelScope: +def move_on_after(seconds: float, *, shield: bool = False) -> trio.CancelScope: """Use as a context manager to create a cancel scope whose deadline is set to now + *seconds*. @@ -98,7 +98,7 @@ class TooSlowError(Exception): # 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, shield: bool = False) -> AbstractContextManager[trio.CancelScope]: # type: ignore[misc] +def fail_at(deadline: float, *, shield: bool = False) -> AbstractContextManager[trio.CancelScope]: # type: ignore[misc] """Creates a cancel scope with the given deadline, and raises an error if it is actually cancelled. @@ -131,7 +131,7 @@ def fail_at(deadline: float, shield: bool = False) -> AbstractContextManager[tri def fail_after( - seconds: float, shield: bool = False + seconds: float, *, shield: bool = False ) -> AbstractContextManager[trio.CancelScope]: """Creates a cancel scope with the given timeout, and raises an error if it is actually cancelled. From bdb5ae6cedb96a510b462d991bd491bc82ae5999 Mon Sep 17 00:00:00 2001 From: Agnes Natasya Date: Sat, 27 Jul 2024 08:51:34 +0800 Subject: [PATCH 03/10] news rst --- newsfragments/3040.feature.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/newsfragments/3040.feature.rst b/newsfragments/3040.feature.rst index 87c9bb142a..a0cd0dcfbb 100644 --- a/newsfragments/3040.feature.rst +++ b/newsfragments/3040.feature.rst @@ -1 +1 @@ -- `trio.move_on_at`, `trio.move_on_after`, `trio.fail_at` and `trio.fail_after` now accepts shield as a kwarg. +`trio.move_on_at`, `trio.move_on_after`, `trio.fail_at` and `trio.fail_after` now accepts shield as a kwarg. From 396ffba0eec968df78eae3d23e83a59eb074fb5b Mon Sep 17 00:00:00 2001 From: Agnes Natasya Date: Sat, 27 Jul 2024 08:51:34 +0800 Subject: [PATCH 04/10] news rst --- newsfragments/{3040.feature.rst => 3049.feature.rst} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename newsfragments/{3040.feature.rst => 3049.feature.rst} (100%) diff --git a/newsfragments/3040.feature.rst b/newsfragments/3049.feature.rst similarity index 100% rename from newsfragments/3040.feature.rst rename to newsfragments/3049.feature.rst From bd2646c8146eb07bf0e508359287ce9fc593e5d8 Mon Sep 17 00:00:00 2001 From: Agnes Natasya Date: Sat, 3 Aug 2024 11:04:45 +0800 Subject: [PATCH 05/10] better docstring and parametrize test --- .DS_Store | Bin 0 -> 6148 bytes a.py | 50 +++++++++++++++++++++++++++ newsfragments/3049.feature.rst | 2 +- src/trio/_tests/test_timeouts.py | 57 ++++++++++++------------------- src/trio/_timeouts.py | 16 ++++++--- 5 files changed, 85 insertions(+), 40 deletions(-) create mode 100644 .DS_Store create mode 100755 a.py diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..6a45c87a23abf24cbf7cc8641820dbd89cfee9c2 GIT binary patch literal 6148 zcmeHK%SyvQ6rHirrW7Fyg)Rr&7VJX`#Z8Fy2aM=Kr6#6mFlI`VnnfvOtv}?K_&we` zGZBk*D`M}3nRA~rnFE;zV~l(AsLPnc7_*@va#Yp`y4QxbOfn+JF~TC7hKUTpelxMZ z4*2aBiCSivhOpX+({XK5nSd+=5HRURQRKnxHA#K7h< zV9o@)xw#b3%83DD;0Fe9e-O|RU4x}YwRJ#;*Jq4dh$x`rTLMuSbPbjoAp*j6DWERp z=83^|IrxRia}Aanbvff|W*EoJTs>a6njQQ?r8Dkoq@EZc238rUY16^;{}g_iwU7MO z60(Q^V&I=Kz^#!#@?cTsZ2h)8JZlBCTWBblSE2#}`pP8$4BSUrDyZWEb;xrKmKt#s S^s90}x(Fyjs3Qh`fq@SnMoLxy literal 0 HcmV?d00001 diff --git a/a.py b/a.py new file mode 100755 index 0000000000..434e16caf5 --- /dev/null +++ b/a.py @@ -0,0 +1,50 @@ +from contextlib import AsyncExitStack, asynccontextmanager +# import trio_asyncio +import trio + +@asynccontextmanager +async def yielder(): + try: + await trio.sleep(0) + yield None + finally: + print("exiting from yielder") + await trio.sleep(3) + print("done exiting from yielder") + +class Context: + def __init__(self): + self._stack = AsyncExitStack() + self.nursery = None + async def __aenter__(self): + async with AsyncExitStack() as stack: + self.nursery = await stack.enter_async_context(trio.open_nursery()) + await stack.enter_async_context(yielder()) + self.nursery.start_soon(some_async_fn) + self._stack = stack.pop_all() + return self + + async def __aexit__(self, *exc): + with trio.CancelScope(shield=True): + await self._stack.__aexit__(*exc) + + +async def some_async_fn(): + raise RuntimeError() + +@asynccontextmanager +async def ContextF(): + try: + async with trio.open_nursery() as nursery, yielder(): + nursery.start_soon(some_async_fn) + yield + finally: + print("exiting from contextf") + await trio.sleep(3) + print("done exiting from contextf") + +async def main2(): + async with Context() as context: + pass + +trio.run(main2) \ No newline at end of file diff --git a/newsfragments/3049.feature.rst b/newsfragments/3049.feature.rst index a0cd0dcfbb..d693e52bf1 100644 --- a/newsfragments/3049.feature.rst +++ b/newsfragments/3049.feature.rst @@ -1 +1 @@ -`trio.move_on_at`, `trio.move_on_after`, `trio.fail_at` and `trio.fail_after` now accepts shield as a kwarg. +`trio.move_on_at`, `trio.move_on_after`, `trio.fail_at` and `trio.fail_after` now accept *shield* as a keyword argument. If specified, it provides an initial value for the `~trio.CancelScope.shield` attribute of the `trio.CancelScope` object created by the context manager. \ No newline at end of file diff --git a/src/trio/_tests/test_timeouts.py b/src/trio/_tests/test_timeouts.py index 9fd384baf0..224159970d 100644 --- a/src/trio/_tests/test_timeouts.py +++ b/src/trio/_tests/test_timeouts.py @@ -1,5 +1,5 @@ import time -from typing import Awaitable, Callable, TypeVar +from typing import Awaitable, Callable, TypeVar, Protocol import outcome import pytest @@ -74,22 +74,27 @@ async def sleep_3() -> None: await check_takes_about(sleep_3, TARGET) - -@slow -async def test_move_on_after_shields_from_outer() -> None: - duration = 0.1 - - async def task() -> None: - with _core.CancelScope() as outer, move_on_after(TARGET, shield=True) as inner: - outer.cancel() - # The outer scope is cancelled, but this task is protected by the - # shield, so it manages to get to sleep for 'duration' seconds - await trio.sleep(duration) - # now when we unshield, it should abort the sleep. - inner.shield = False - - # Check that the task takes only about 'duration' seconds - await check_takes_about(task, duration) +class TimeoutScope(Protocol): + def __call__(self, seconds: float, *, shield: bool) -> trio.CancelScope: + ... + +@pytest.mark.parametrize( + "scope", + [ + move_on_after, + fail_after + ] +) +async def test_context_shields_from_outer(scope: TimeoutScope) -> None: + with _core.CancelScope() as outer, scope(TARGET, shield=True) as inner: + outer.cancel() + try: + await trio.lowlevel.checkpoint() + except trio.Cancelled: + pytest.fail("shield didn't work") + inner.shield = False + with pytest.raises(trio.Cancelled): + await trio.lowlevel.checkpoint() @slow @@ -103,24 +108,6 @@ async def task() -> None: await check_takes_about(task, TARGET) - -@slow -async def test_fail_after_exits_shields_from_outer() -> None: - duration = 0.1 - - async def task() -> None: - with _core.CancelScope() as outer, fail_after(TARGET, shield=True) as inner: - outer.cancel() - # The outer scope is cancelled, but this task is protected by the - # shield, so it manages to get to sleep for 'duration' seconds - await trio.sleep(duration) - # now when we unshield, it should abort the sleep. - inner.shield = False - - # Check that the task takes only about 'duration' seconds - await check_takes_about(task, duration) - - @slow async def test_fail_after_fails_even_if_shielded() -> None: async def task() -> None: diff --git a/src/trio/_timeouts.py b/src/trio/_timeouts.py index 70e063aeca..ddc5f8c7d9 100644 --- a/src/trio/_timeouts.py +++ b/src/trio/_timeouts.py @@ -13,7 +13,9 @@ def move_on_at(deadline: float, *, shield: bool = False) -> trio.CancelScope: Args: deadline (float): The deadline. - shield (bool): Whether the cancel scope created is shielded. + shield (bool): Initial value for the `~trio.CancelScope.shield` attribute + of the newly created `cancel scope + `__. Raises: ValueError: if deadline is NaN. @@ -30,7 +32,9 @@ def move_on_after(seconds: float, *, shield: bool = False) -> trio.CancelScope: Args: seconds (float): The timeout. - shield (bool): Whether the cancel scope created is shielded. + shield (bool): Initial value for the `~trio.CancelScope.shield` attribute + of the newly created `cancel scope + `__. Raises: ValueError: if timeout is less than zero or NaN. @@ -112,7 +116,9 @@ def fail_at(deadline: float, *, shield: bool = False) -> AbstractContextManager[ Args: deadline (float): The deadline. - shield (bool): Whether the cancel scope created is shielded. + shield (bool): Initial value for the `~trio.CancelScope.shield` attribute + of the newly created `cancel scope + `__. Raises: TooSlowError: if a :exc:`Cancelled` exception is raised in this scope @@ -145,7 +151,9 @@ def fail_after( Args: seconds (float): The timeout. - shield (bool): Whether the cancel scope created is shielded. + shield (bool): Initial value for the `~trio.CancelScope.shield` attribute + of the newly created `cancel scope + `__. Raises: TooSlowError: if a :exc:`Cancelled` exception is raised in this scope From 95f7455c72a2e419c3643dc466047366ade6fd14 Mon Sep 17 00:00:00 2001 From: Agnes Natasya Date: Sat, 3 Aug 2024 11:06:43 +0800 Subject: [PATCH 06/10] undo --- .DS_Store | Bin 6148 -> 0 bytes a.py | 50 -------------------------------------------------- 2 files changed, 50 deletions(-) delete mode 100644 .DS_Store delete mode 100755 a.py diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 6a45c87a23abf24cbf7cc8641820dbd89cfee9c2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%SyvQ6rHirrW7Fyg)Rr&7VJX`#Z8Fy2aM=Kr6#6mFlI`VnnfvOtv}?K_&we` zGZBk*D`M}3nRA~rnFE;zV~l(AsLPnc7_*@va#Yp`y4QxbOfn+JF~TC7hKUTpelxMZ z4*2aBiCSivhOpX+({XK5nSd+=5HRURQRKnxHA#K7h< zV9o@)xw#b3%83DD;0Fe9e-O|RU4x}YwRJ#;*Jq4dh$x`rTLMuSbPbjoAp*j6DWERp z=83^|IrxRia}Aanbvff|W*EoJTs>a6njQQ?r8Dkoq@EZc238rUY16^;{}g_iwU7MO z60(Q^V&I=Kz^#!#@?cTsZ2h)8JZlBCTWBblSE2#}`pP8$4BSUrDyZWEb;xrKmKt#s S^s90}x(Fyjs3Qh`fq@SnMoLxy diff --git a/a.py b/a.py deleted file mode 100755 index 434e16caf5..0000000000 --- a/a.py +++ /dev/null @@ -1,50 +0,0 @@ -from contextlib import AsyncExitStack, asynccontextmanager -# import trio_asyncio -import trio - -@asynccontextmanager -async def yielder(): - try: - await trio.sleep(0) - yield None - finally: - print("exiting from yielder") - await trio.sleep(3) - print("done exiting from yielder") - -class Context: - def __init__(self): - self._stack = AsyncExitStack() - self.nursery = None - async def __aenter__(self): - async with AsyncExitStack() as stack: - self.nursery = await stack.enter_async_context(trio.open_nursery()) - await stack.enter_async_context(yielder()) - self.nursery.start_soon(some_async_fn) - self._stack = stack.pop_all() - return self - - async def __aexit__(self, *exc): - with trio.CancelScope(shield=True): - await self._stack.__aexit__(*exc) - - -async def some_async_fn(): - raise RuntimeError() - -@asynccontextmanager -async def ContextF(): - try: - async with trio.open_nursery() as nursery, yielder(): - nursery.start_soon(some_async_fn) - yield - finally: - print("exiting from contextf") - await trio.sleep(3) - print("done exiting from contextf") - -async def main2(): - async with Context() as context: - pass - -trio.run(main2) \ No newline at end of file From ee315eccb84c7a74c4d1c55902e3f1df0ff58406 Mon Sep 17 00:00:00 2001 From: Agnes Natasya Date: Sat, 3 Aug 2024 11:08:20 +0800 Subject: [PATCH 07/10] black --- src/trio/_tests/test_timeouts.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/trio/_tests/test_timeouts.py b/src/trio/_tests/test_timeouts.py index 224159970d..8b0f908ca7 100644 --- a/src/trio/_tests/test_timeouts.py +++ b/src/trio/_tests/test_timeouts.py @@ -1,5 +1,5 @@ import time -from typing import Awaitable, Callable, TypeVar, Protocol +from typing import Awaitable, Callable, Protocol, TypeVar import outcome import pytest @@ -74,17 +74,12 @@ async def sleep_3() -> None: await check_takes_about(sleep_3, TARGET) + class TimeoutScope(Protocol): - def __call__(self, seconds: float, *, shield: bool) -> trio.CancelScope: - ... - -@pytest.mark.parametrize( - "scope", - [ - move_on_after, - fail_after - ] -) + def __call__(self, seconds: float, *, shield: bool) -> trio.CancelScope: ... + + +@pytest.mark.parametrize("scope", [move_on_after, fail_after]) async def test_context_shields_from_outer(scope: TimeoutScope) -> None: with _core.CancelScope() as outer, scope(TARGET, shield=True) as inner: outer.cancel() @@ -108,6 +103,7 @@ async def task() -> None: await check_takes_about(task, TARGET) + @slow async def test_fail_after_fails_even_if_shielded() -> None: async def task() -> None: From 308cebb8f45a15b92e86702a9ee1f56b09282c22 Mon Sep 17 00:00:00 2001 From: Agnes Natasya Date: Sat, 3 Aug 2024 11:09:47 +0800 Subject: [PATCH 08/10] new line --- newsfragments/3049.feature.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/newsfragments/3049.feature.rst b/newsfragments/3049.feature.rst index d693e52bf1..3d843b4feb 100644 --- a/newsfragments/3049.feature.rst +++ b/newsfragments/3049.feature.rst @@ -1 +1 @@ -`trio.move_on_at`, `trio.move_on_after`, `trio.fail_at` and `trio.fail_after` now accept *shield* as a keyword argument. If specified, it provides an initial value for the `~trio.CancelScope.shield` attribute of the `trio.CancelScope` object created by the context manager. \ No newline at end of file +`trio.move_on_at`, `trio.move_on_after`, `trio.fail_at` and `trio.fail_after` now accept *shield* as a keyword argument. If specified, it provides an initial value for the `~trio.CancelScope.shield` attribute of the `trio.CancelScope` object created by the context manager. From a63e48386f7e82642c2fe4b8220d42e9d6c164ed Mon Sep 17 00:00:00 2001 From: Agnes Natasya Date: Sat, 3 Aug 2024 15:26:20 +0800 Subject: [PATCH 09/10] update news rst to issue number --- newsfragments/{3049.feature.rst => 3052.feature.rst} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename newsfragments/{3049.feature.rst => 3052.feature.rst} (100%) diff --git a/newsfragments/3049.feature.rst b/newsfragments/3052.feature.rst similarity index 100% rename from newsfragments/3049.feature.rst rename to newsfragments/3052.feature.rst From 63880431e2e963a0079992875595a890079b7e0c Mon Sep 17 00:00:00 2001 From: Agnes Natasya Date: Sun, 4 Aug 2024 11:44:59 +0800 Subject: [PATCH 10/10] no need to explicitly link to docs --- src/trio/_timeouts.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/trio/_timeouts.py b/src/trio/_timeouts.py index ddc5f8c7d9..7bc985039b 100644 --- a/src/trio/_timeouts.py +++ b/src/trio/_timeouts.py @@ -14,8 +14,7 @@ def move_on_at(deadline: float, *, shield: bool = False) -> trio.CancelScope: Args: deadline (float): The deadline. shield (bool): Initial value for the `~trio.CancelScope.shield` attribute - of the newly created `cancel scope - `__. + of the newly created cancel scope. Raises: ValueError: if deadline is NaN. @@ -33,8 +32,7 @@ def move_on_after(seconds: float, *, shield: bool = False) -> trio.CancelScope: Args: seconds (float): The timeout. shield (bool): Initial value for the `~trio.CancelScope.shield` attribute - of the newly created `cancel scope - `__. + of the newly created cancel scope. Raises: ValueError: if timeout is less than zero or NaN. @@ -117,8 +115,7 @@ def fail_at(deadline: float, *, shield: bool = False) -> AbstractContextManager[ Args: deadline (float): The deadline. shield (bool): Initial value for the `~trio.CancelScope.shield` attribute - of the newly created `cancel scope - `__. + of the newly created cancel scope. Raises: TooSlowError: if a :exc:`Cancelled` exception is raised in this scope @@ -152,8 +149,7 @@ def fail_after( Args: seconds (float): The timeout. shield (bool): Initial value for the `~trio.CancelScope.shield` attribute - of the newly created `cancel scope - `__. + of the newly created cancel scope. Raises: TooSlowError: if a :exc:`Cancelled` exception is raised in this scope