Skip to content

Commit

Permalink
Merge pull request #19 from pomponchik/develop
Browse files Browse the repository at this point in the history
0.0.14
  • Loading branch information
pomponchik authored Jan 16, 2024
2 parents 86351b4 + 9f3bab8 commit 9603345
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 10 deletions.
19 changes: 15 additions & 4 deletions cantok/tokens/condition_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,32 @@
class ConditionToken(AbstractToken):
exception = ConditionCancellationError

def __init__(self, function: Callable[[], bool], *tokens: AbstractToken, cancelled: bool = False, suppress_exceptions: bool = True, default: bool = False):
def __init__(self, function: Callable[[], bool], *tokens: AbstractToken, cancelled: bool = False, suppress_exceptions: bool = True, default: bool = False, before: Callable[[], Any] = lambda: None, after: Callable[[], Any] = lambda: None):
super().__init__(*tokens, cancelled=cancelled)
self.function = function
self.before = before
self.after = after
self.suppress_exceptions = suppress_exceptions
self.default = default

def superpower(self) -> bool:
if not self.suppress_exceptions:
return self.run_function()
self.before()
result = self.run_function()
self.after()
return result

else:
result = self.default

with suppress(Exception):
self.before()
with suppress(Exception):
result = self.run_function()
with suppress(Exception):
return self.run_function()
self.after()

return self.default
return result

def run_function(self) -> bool:
result = self.function()
Expand Down
28 changes: 23 additions & 5 deletions docs/docs/types_of_tokens/ConditionToken.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
A slightly more complex type of token than [`SimpleToken`](/types_of_tokens/SimpleToken/) is `ConditionToken`. In addition to everything that `SimpleToken` does, it also checks the condition passed to it as a first argument, answering the question whether it has been canceled.

To initialize `ConditionToken`, pass a function to it that does not accept arguments and returns a boolean value. If it returns `True`, it means that the operation has been canceled:
ConditionToken has superpower, it can check arbitrary conditions. In addition to this, it can do all the same things as [`SimpleToken`](/types_of_tokens/SimpleToken/). The condition must be passed to the token constructor as the first argument. The condition is a function that should return an answer (`True`/`False`) to the question "has the token been canceled?", it must be passed to the token constructor with the first argument:

```python
from cantok import ConditionToken
Expand Down Expand Up @@ -34,8 +32,28 @@ print(ConditionToken(function, default=False).cancelled) # False
print(ConditionToken(function, default=True).cancelled) # True
```

`ConditionToken` may include other tokens during initialization:
If the condition is complex enough and requires additional preparation before it can be checked, you can pass a function that runs before the condition is checked. To do this, pass any function without arguments as the `before` argument:

```python
token = ConditionToken(lambda: False, SimpleToken(), TimeoutToken(5), CounterToken(20)) # Includes all additional restrictions of the passed tokens.
from cantok import ConditionToken

token = ConditionToken(lambda: print(2), before=lambda: print(1))

token.check()
# Will be printed:
# 1
# 2
```

By analogy with `before`, you can pass a function that will be executed after checking the condition as the `after` argument:

```python
from cantok import ConditionToken

token = ConditionToken(lambda: print(1), after=lambda: print(2))

token.check()
# Will be printed:
# 1
# 2
```
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "cantok"
version = "0.0.13"
version = "0.0.14"
authors = [
{ name="Evgeniy Blinov", email="zheni-b@yandex.ru" },
]
Expand Down
73 changes: 73 additions & 0 deletions tests/units/tokens/test_condition_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,76 @@ async def runner():
finish_time = perf_counter()

assert finish_time - start_time >= timeout


def test_order_of_callbacks():
lst = []
token = ConditionToken(lambda: lst.append(2) is not None, before=lambda: lst.append(1), after=lambda: lst.append(3))

token.check()

assert lst == [1, 2, 3]


@pytest.mark.parametrize(
'options',
[
{},
{'suppress_exceptions': True}
],
)
def test_raise_suppressed_exception_in_before_callback(options):
lst = []

def before_callback():
lst.append(1)
raise ValueError

token = ConditionToken(lambda: lst.append(2) is not None, before=before_callback, after=lambda: lst.append(3), **options)

token.check()

assert lst == [1, 2, 3]


@pytest.mark.parametrize(
'options',
[
{},
{'suppress_exceptions': True}
],
)
def test_raise_suppressed_exception_in_after_callback(options):
lst = []

def after_callback():
lst.append(3)
raise ValueError

token = ConditionToken(lambda: lst.append(2) is not None, before=lambda: lst.append(1), after=after_callback, **options)

token.check()

assert lst == [1, 2, 3]


def test_raise_not_suppressed_exception_in_before_callback():
lst = []

token = ConditionToken(lambda: lst.append(2) is not None, before=lambda: 1 / 0, suppress_exceptions=False)

with pytest.raises(ZeroDivisionError):
token.check()

assert not lst


def test_raise_not_suppressed_exception_in_after_callback():
lst = []

token = ConditionToken(lambda: lst.append(2) is not None, before=lambda: lst.append(1), after=lambda: 1 / 0, suppress_exceptions=False)

with pytest.raises(ZeroDivisionError):
token.check()

assert lst == [1, 2]

0 comments on commit 9603345

Please sign in to comment.