Skip to content

Commit 92db105

Browse files
authored
Merge pull request #53 from mutating/develop
0.0.38
2 parents 47b35f4 + 6ce8319 commit 92db105

28 files changed

Lines changed: 299 additions & 226 deletions

cantok/tokens/abstract/abstract_token.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
from abc import ABC, abstractmethod
22
from threading import RLock
3-
from typing import Any, Awaitable, Dict, List, Optional, Union
3+
from time import sleep
4+
from typing import Any, Dict, List, Optional, Union
45

56
from cantok.errors import CancellationError
67
from cantok.tokens.abstract.cancel_cause import CancelCause
7-
from cantok.tokens.abstract.coroutine_wrapper import WaitCoroutineWrapper
88
from cantok.tokens.abstract.report import CancellationReport
99

1010

@@ -156,22 +156,18 @@ def wait(
156156
self,
157157
step: Union[int, float] = 0.0001,
158158
timeout: Optional[Union[int, float]] = None,
159-
) -> Awaitable: # type: ignore[type-arg]
159+
) -> None:
160160
"""
161161
Waits until the token is cancelled.
162162
163-
When used with ``await``, runs non-blocking inside an asyncio event loop.
164-
When called without ``await``, blocks the current thread.
163+
Blocks the current thread until the token is cancelled.
165164
166165
:param step: Interval between status checks, in seconds. Defaults to 0.0001.
167166
:param timeout: Maximum time to wait, in seconds. If exceeded,
168167
raises TimeoutCancellationError. Defaults to None (no limit).
169168
170-
>>> import asyncio
171-
>>>
172169
>>> token = TimeoutToken(5)
173170
>>> token.wait() # blocks for ~5 seconds, then returns
174-
>>> asyncio.run(TimeoutToken(5).wait()) # non-blocking, inside an asyncio event loop
175171
"""
176172
if step < 0:
177173
raise ValueError(
@@ -193,7 +189,12 @@ def wait(
193189

194190
token = TimeoutToken(timeout)
195191

196-
return WaitCoroutineWrapper(step, self + token, token)
192+
token_for_wait = self + token
193+
194+
while token_for_wait:
195+
sleep(step)
196+
197+
token.check()
197198

198199
def cancel(self) -> 'AbstractToken':
199200
"""

cantok/tokens/abstract/coroutine_wrapper.py

Lines changed: 0 additions & 67 deletions
This file was deleted.

docs/what_are_tokens/exceptions.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,19 @@ token.check()
1010
#> cantok.errors.TimeoutCancellationError: The timeout of 1 second has expired.
1111
```
1212

13+
The `wait()` method can also raise an exception directly when its own waiting timeout expires:
14+
15+
```python
16+
from cantok import SimpleToken, TimeoutCancellationError
17+
18+
token = SimpleToken()
19+
20+
try:
21+
token.wait(timeout=1)
22+
except TimeoutCancellationError:
23+
print('Waiting took too long.')
24+
```
25+
1326
Each type of token (except [`DefaultToken`](../types_of_tokens/DefaultToken.md)) has a corresponding type of exception that can be raised in this case:
1427

1528
- [`SimpleToken`](../types_of_tokens/SimpleToken.md) -> `CancellationError`

docs/what_are_tokens/waiting.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Each token has a `wait()` method, which allows you to wait for its cancellation.
1+
Each token has a `wait()` method, which allows you to block the current thread until the token is cancelled.
22

33
```python
44
from cantok import TimeoutToken
@@ -10,26 +10,26 @@ token.check() # Since the timeout has expired, an exception will be raised.
1010
#> cantok.errors.TimeoutCancellationError: The timeout of 5 seconds has expired.
1111
```
1212

13-
If you add the `await` keyword before calling `wait()`, the method will be automatically used in non-blocking mode:
13+
This is useful when one thread needs to wait for cancellation requested from another thread:
1414

1515
```python
16-
import asyncio
16+
from threading import Thread
17+
from time import sleep
1718
from cantok import SimpleToken
1819

19-
async def do_something(token):
20-
await asyncio.sleep(3) # Imitation of some real async activity.
20+
def do_something(token):
21+
sleep(3) # Imitation of some real activity.
2122
token.cancel()
2223

23-
async def main():
24-
token = SimpleToken()
25-
await asyncio.gather(do_something(token), token.wait())
26-
print('Something has been done!')
24+
token = SimpleToken()
25+
thread = Thread(target=do_something, args=(token,))
26+
thread.start()
2727

28-
asyncio.run(main())
28+
token.wait()
29+
thread.join()
30+
print('Something has been done!')
2931
```
3032

31-
Yes, it looks like magic — it is magic. The method itself finds out how it was used: inside an expression with or without the `await` keyword. In the first case, it runs in CPU-saving mode, in the second — in non-blocking event-loop mode.
32-
3333
In addition to the above, the `wait()` method has two optional arguments:
3434

3535
- **`timeout`** (`int` or `float`) — the maximum waiting time in seconds. If this time is exceeded, a [`TimeoutCancellationError` exception](../what_are_tokens/exceptions.md) will be raised. By default, the `timeout` is not set.

pyproject.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,12 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "cantok"
7-
version = "0.0.37"
7+
version = "0.0.38"
88
authors = [{ name = "Evgeniy Blinov", email = "zheni-b@yandex.ru" }]
99
description = 'Implementation of the "Cancellation Token" pattern'
1010
readme = "README.md"
1111
requires-python = ">=3.8"
1212
dependencies = [
13-
'displayhooks>=0.0.6',
1413
'transfunctions>=0.0.12',
1514
'typing_extensions ; python_version <= "3.9"',
1615
]

tests/examples/test_examples.py

Lines changed: 1 addition & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
import asyncio
2-
from contextlib import redirect_stdout
3-
from io import StringIO
41
from random import randint
52
from threading import Thread
63

7-
from cantok import ConditionToken, CounterToken, SimpleToken, TimeoutToken
4+
from cantok import ConditionToken, CounterToken, TimeoutToken
85

96
counter = 0
107

@@ -30,38 +27,3 @@ def test_cancel_simple_token_with_function_and_thread_2():
3027
counter += 1
3128

3229
assert counter
33-
34-
35-
def test_waiting_of_cancelled_token():
36-
async def do_something(token):
37-
await asyncio.sleep(0.1) # Imitation of some real async activity.
38-
token.cancel()
39-
40-
async def main():
41-
token = SimpleToken()
42-
await do_something(token)
43-
await token.wait()
44-
print('Something has been done!') # noqa: T201
45-
46-
buffer = StringIO()
47-
with redirect_stdout(buffer):
48-
asyncio.run(main())
49-
50-
assert buffer.getvalue() == 'Something has been done!\n'
51-
52-
53-
def test_waiting_of_cancelled_token_with_gather():
54-
async def do_something(token):
55-
await asyncio.sleep(0.1) # Imitation of some real async activity.
56-
token.cancel()
57-
58-
async def main():
59-
token = SimpleToken()
60-
await asyncio.gather(do_something(token), token.wait())
61-
print('Something has been done!') # noqa: T201
62-
63-
buffer = StringIO()
64-
with redirect_stdout(buffer):
65-
asyncio.run(main())
66-
67-
assert buffer.getvalue() == 'Something has been done!\n'
File renamed without changes.
File renamed without changes.

tests/skipped/sum_optimization/tokens/abstract/__init__.py

Whitespace-only changes.

tests/skipped/tokens/abstract/test_abstract_token.py renamed to tests/skipped/sum_optimization/tokens/abstract/test_abstract_token.py

File renamed without changes.

0 commit comments

Comments
 (0)