Skip to content

Commit

Permalink
Merge pull request #40 from pomponchik/develop
Browse files Browse the repository at this point in the history
0.0.29
  • Loading branch information
pomponchik authored Aug 8, 2024
2 parents ccd012e + 0e236f3 commit a410e02
Show file tree
Hide file tree
Showing 7 changed files with 1,797 additions and 37 deletions.
56 changes: 41 additions & 15 deletions cantok/tokens/abstract/abstract_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,21 @@
from threading import RLock
from typing import List, Dict, Awaitable, Optional, Union, Any


from cantok.errors import CancellationError
from cantok.tokens.abstract.cancel_cause import CancelCause
from cantok.tokens.abstract.report import CancellationReport
from cantok.tokens.abstract.coroutine_wrapper import WaitCoroutineWrapper
from cantok.types import IterableWithTokens


class AbstractToken(ABC):
exception = CancellationError
rollback_if_nondirect_polling = False

def __init__(self, *tokens: 'AbstractToken', cancelled: bool = False) -> None:
from cantok import DefaultToken

self.cached_report: Optional[CancellationReport] = None
self._cancelled: bool = cancelled
self.tokens: List[AbstractToken] = []

for token in tokens:
if isinstance(token, DefaultToken):
pass
else:
self.tokens.append(token)
self.tokens: List[AbstractToken] = self.filter_tokens(tokens)

self.lock: RLock = RLock()

Expand Down Expand Up @@ -61,15 +53,36 @@ def __add__(self, item: 'AbstractToken') -> 'AbstractToken':
if not isinstance(item, AbstractToken):
raise TypeError('Cancellation Token can only be combined with another Cancellation Token.')

from cantok import SimpleToken, DefaultToken
from cantok import SimpleToken, DefaultToken, TimeoutToken

if self._cancelled or item._cancelled:
return SimpleToken(cancelled=True)

nested_tokens = []
container_token: Optional[AbstractToken] = None

if isinstance(self, TimeoutToken) and isinstance(item, TimeoutToken) and self.monotonic == item.monotonic:
if self.deadline >= item.deadline and getrefcount(self) < 4:
if getrefcount(item) < 4:
item.tokens.extend(self.tokens)
return item
else:
if self.tokens:
return SimpleToken(*(self.tokens), item)
else:
return item
elif self.deadline < item.deadline and getrefcount(item) < 4:
if getrefcount(self) < 4:
self.tokens.extend(item.tokens)
return self
else:
if item.tokens:
return SimpleToken(*(item.tokens), self)
else:
return self

for token in self, item:
if token._cancelled:
return SimpleToken(cancelled=True)
elif isinstance(token, SimpleToken) and getrefcount(token) < 6:
if isinstance(token, SimpleToken) and getrefcount(token) < 6:
nested_tokens.extend(token.tokens)
elif isinstance(token, DefaultToken):
pass
Expand All @@ -81,12 +94,25 @@ def __add__(self, item: 'AbstractToken') -> 'AbstractToken':
if container_token is None:
return SimpleToken(*nested_tokens)
else:
container_token.tokens.extend(nested_tokens)
container_token.tokens.extend(container_token.filter_tokens(nested_tokens))
return container_token

def __bool__(self) -> bool:
return self.keep_on()

def filter_tokens(self, tokens: IterableWithTokens) -> List['AbstractToken']: # type: ignore[type-arg]
from cantok import DefaultToken

result: List[AbstractToken] = []

for token in tokens:
if isinstance(token, DefaultToken):
pass
else:
result.append(token)

return result

@property
def cancelled(self) -> bool:
return self.is_cancelled()
Expand Down
6 changes: 4 additions & 2 deletions cantok/tokens/timeout_token.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from time import monotonic_ns, perf_counter

from typing import Union, Callable, Dict, Any

from cantok import AbstractToken
Expand All @@ -25,8 +24,11 @@ def __init__(self, timeout: Union[int, float], *tokens: AbstractToken, cancelled
timer = perf_counter

start_time: Union[int, float] = timer()
deadline = start_time + timeout
def function() -> bool:
return timer() >= (start_time + timeout)
return timer() >= deadline

self.deadline = deadline

super().__init__(function, *tokens, cancelled=cancelled)

Expand Down
13 changes: 13 additions & 0 deletions cantok/types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import sys
from collections.abc import Iterable

if sys.version_info >= (3, 10):
from typing import TypeAlias # pragma: no cover
else:
from typing_extensions import TypeAlias # pragma: no cover


if sys.version_info >= (3, 9):
IterableWithTokens: TypeAlias = Iterable['AbstractToken'] # type: ignore[name-defined, unused-ignore] # pragma: no cover
else:
IterableWithTokens = Iterable # pragma: no cover
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ build-backend = "setuptools.build_meta"

[project]
name = "cantok"
version = "0.0.28"
version = "0.0.29"
authors = [
{ name="Evgeniy Blinov", email="zheni-b@yandex.ru" },
]
description = 'Implementation of the "Cancellation Token" pattern'
readme = "README.md"
requires-python = ">=3.7"
dependencies = [
'typing_extensions ; python_version <= "3.9"',
]
classifiers = [
"Operating System :: OS Independent",
'Operating System :: MacOS :: MacOS X',
Expand Down
36 changes: 24 additions & 12 deletions tests/units/tokens/abstract/test_abstract_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,10 +173,14 @@ def test_add_not_temp_tokens(first_token_fabric, second_token_fabric):
def test_add_temp_tokens(first_token_class, second_token_class, first_arguments, second_arguments):
tokens_sum = first_token_class(*first_arguments) + second_token_class(*second_arguments)

assert isinstance(tokens_sum, first_token_class)
assert len(tokens_sum.tokens) == 1
assert isinstance(tokens_sum.tokens[0], second_token_class)
assert len(tokens_sum.tokens[0].tokens) == 0
if not (first_token_class is TimeoutToken and second_token_class is TimeoutToken):
assert isinstance(tokens_sum, first_token_class)
assert len(tokens_sum.tokens) == 1
assert isinstance(tokens_sum.tokens[0], second_token_class)
assert len(tokens_sum.tokens[0].tokens) == 0
else:
assert isinstance(tokens_sum, TimeoutToken)
assert len(tokens_sum.tokens) == 0


@pytest.mark.parametrize(
Expand All @@ -199,10 +203,14 @@ def test_add_not_temp_token_and_temp_token(first_token_class, second_token_class
first_token = first_token_class(*first_arguments)
tokens_sum = first_token + second_token_class(*second_arguments)

assert isinstance(tokens_sum, second_token_class)
assert len(tokens_sum.tokens) == 1
assert isinstance(tokens_sum.tokens[0], first_token_class)
assert len(tokens_sum.tokens[0].tokens) == 0
if first_token_class is TimeoutToken and second_token_class is TimeoutToken:
assert tokens_sum is first_token
assert not tokens_sum.tokens
else:
assert isinstance(tokens_sum, second_token_class)
assert len(tokens_sum.tokens) == 1
assert isinstance(tokens_sum.tokens[0], first_token_class)
assert len(tokens_sum.tokens[0].tokens) == 0


@pytest.mark.parametrize(
Expand All @@ -225,10 +233,14 @@ def test_add_temp_token_and_not_temp_token(first_token_class, second_token_class
second_token = second_token_class(*second_arguments)
tokens_sum = first_token_class(*first_arguments) + second_token

assert isinstance(tokens_sum, first_token_class)
assert len(tokens_sum.tokens) == 1
assert isinstance(tokens_sum.tokens[0], second_token_class)
assert len(tokens_sum.tokens[0].tokens) == 0
if first_token_class is TimeoutToken and second_token_class is TimeoutToken:
assert isinstance(tokens_sum, TimeoutToken)
assert len(tokens_sum.tokens) == 0
else:
assert isinstance(tokens_sum, first_token_class)
assert len(tokens_sum.tokens) == 1
assert isinstance(tokens_sum.tokens[0], second_token_class)
assert len(tokens_sum.tokens[0].tokens) == 0


@pytest.mark.parametrize(
Expand Down
3 changes: 1 addition & 2 deletions tests/units/tokens/test_simple_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,8 @@ def test_sum_of_2_temp_timeout_tokens_throw_right_temp_simple_token():

assert isinstance(token, TimeoutToken)
assert len(token.tokens) == 1
assert len(token.tokens[0].tokens) == 0
assert token.timeout == 1

assert isinstance(token.tokens[0], TimeoutToken)
assert token.tokens[0].timeout == 2


Expand Down
Loading

0 comments on commit a410e02

Please sign in to comment.