From 3c07c6aa6eb2a7a7cfa08e9132237e4c6fb59723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=91=D0=BB?= =?UTF-8?q?=D0=B8=D0=BD=D0=BE=D0=B2?= Date: Tue, 31 Mar 2026 02:54:45 +0300 Subject: [PATCH 1/9] Fix minor typos and improve documentation consistency --- docs/index.md | 2 +- docs/the_pattern.md | 4 ++-- docs/types_of_tokens/ConditionToken.md | 2 +- docs/types_of_tokens/CounterToken.md | 2 +- docs/types_of_tokens/SimpleToken.md | 2 +- docs/what_are_tokens/embedding.md | 2 +- docs/what_are_tokens/exceptions.md | 4 ++-- docs/what_are_tokens/in_general.md | 2 +- docs/what_are_tokens/waiting.md | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/index.md b/docs/index.md index f4f8c2a..fe15331 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,4 +1,4 @@ ![logo](https://raw.githubusercontent.com/pomponchik/cantok/main/docs/assets/logo_5.png) -Cancellation Token is a pattern that allows us to refuse to continue calculations that we no longer need. It is implemented out of the box in many programming languages, for example in [C#](https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtoken) and in [Go](https://pkg.go.dev/context). However, there was still no sane implementation in Python, until the [cantok](https://github.com/pomponchik/cantok) library appeared. +Cancellation Token is a pattern that allows us to cancel calculations that we no longer need. It is implemented out of the box in many programming languages, for example in [C#](https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtoken) and in [Go](https://pkg.go.dev/context). However, there was still no sane implementation in Python, until the [cantok](https://github.com/pomponchik/cantok) library appeared. diff --git a/docs/the_pattern.md b/docs/the_pattern.md index 8b26baa..5f9290e 100644 --- a/docs/the_pattern.md +++ b/docs/the_pattern.md @@ -4,8 +4,8 @@ Cancellation Token is a pattern that allows us to cancel calculations that we no The essence of the pattern is that we pass special objects to functions and constructors, by which the executed code can understand whether it should continue its execution or not. When deciding whether to allow code execution to continue, this object can both take into account the restrictions imposed on it, such as the maximum code execution time, and receive signals about the need to stop from the outside, for example from another thread or a coroutine. Thus, we do not nail down the logic associated with stopping code execution, for example, by directly tracking loop counters, but implement [Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection) of this restriction. -In addition, the pattern assumes that various restrictions can be combined in unlimited combinations with each other: if at least one of the restrictions is not met, code execution will be interrupted. It is assumed that each function in the call stack will call other functions, passing its token directly to them, or wrapping it in another token with stricter restrictions. +In addition, the pattern assumes that various restrictions can be combined with each other without limit: if at least one of the restrictions is not met, code execution will be interrupted. It is assumed that each function in the call stack will call other functions, passing its token directly to them, or wrapping it in another token with stricter restrictions. Unlike other ways of stopping code execution, tokens do not force the execution thread to be interrupted. The interruption occurs "gently", allowing the code to terminate correctly, release all held resources and restore consistency. -It is highly desirable for library developers to use this pattern for any long-running operations. Your function can accept a token as an optional argument, with a default value that imposes minimal restrictions or none at all. If the user wishes, they can pass their token to it, imposing stricter restrictions on the library code. In addition to a more convenient and extensible API, this will give the library an advantage in the form of better testability, because the restrictions are no longer hardcoded into the function, which means they can be made whatever you want for the test. In addition, the library developer no longer needs to think about all the numerous restrictions that can be imposed on their code - the user can take care of it themselves if they need to. +It is highly desirable for library developers to use this pattern for any long-running operations. Your function can accept a token as an optional argument, with a default value that imposes minimal restrictions or none at all. If the user wishes, they can pass their token to it, imposing stricter restrictions on the library code. In addition to a more convenient and extensible API, this will give the library an advantage in the form of better testability, because the restrictions are no longer hardcoded into the function, which means they can be set to any value needed for testing. In addition, the library developer no longer needs to think about all the numerous restrictions that can be imposed on their code - the user can take care of it themselves if they need to. diff --git a/docs/types_of_tokens/ConditionToken.md b/docs/types_of_tokens/ConditionToken.md index 0d0e64f..1323125 100644 --- a/docs/types_of_tokens/ConditionToken.md +++ b/docs/types_of_tokens/ConditionToken.md @@ -22,7 +22,7 @@ token = ConditionToken(function, suppress_exceptions=False) token.cancelled # ValueError has been raised. ``` -When using exception suppression mode, the `cancelled` attribute will contain `False` by default in case of an exception. If you want to change this, pass `default=True`. +When using exception suppression mode, the `cancelled` attribute will be `False` by default in case of an exception. If you want to change this, pass `default=True`. ```python def function(): raise ValueError diff --git a/docs/types_of_tokens/CounterToken.md b/docs/types_of_tokens/CounterToken.md index 4d82893..d03b2b6 100644 --- a/docs/types_of_tokens/CounterToken.md +++ b/docs/types_of_tokens/CounterToken.md @@ -1,4 +1,4 @@ -`CounterToken` is the least intuitive of the tokens provided by this library. Do not use it if you are not sure that you understand how it works correctly. However, it can be very useful in situations where you want to limit the number of attempts to perform an operation. +`CounterToken` is the least intuitive of the tokens provided by this library. Do not use it if you are not sure that you understand how it works. However, it can be very useful in situations where you want to limit the number of attempts to perform an operation. `CounterToken` is initialized with an integer greater than or equal to zero. Each time cancellation is checked, this number is decremented by one. When this number becomes zero, the token is considered cancelled: diff --git a/docs/types_of_tokens/SimpleToken.md b/docs/types_of_tokens/SimpleToken.md index 0d1233b..16c84da 100644 --- a/docs/types_of_tokens/SimpleToken.md +++ b/docs/types_of_tokens/SimpleToken.md @@ -1,4 +1,4 @@ -The base token is `SimpleToken`. It has no built-in automation that can cancel it. The only way to cancel `SimpleToken` is to explicitly call the `cancel()` method from it. +The base token is `SimpleToken`. It has no built-in automation that can cancel it. The only way to cancel `SimpleToken` is to explicitly call the `cancel()` method on it. ```python from cantok import SimpleToken diff --git a/docs/what_are_tokens/embedding.md b/docs/what_are_tokens/embedding.md index 5e14e7a..5833487 100644 --- a/docs/what_are_tokens/embedding.md +++ b/docs/what_are_tokens/embedding.md @@ -1,4 +1,4 @@ -You can embed an unlimited number of other tokens in one token by passing them as arguments during initialization. Each time checking whether it has been cancelled, the token first checks its cancellation rules, and if it has not been canceled itself, then it checks the tokens nested in it. Thus, one cancelled token nested in another non-cancelled token cancels it: +You can embed an unlimited number of other tokens in one token by passing them as arguments during initialization. Each time checking whether it has been cancelled, the token first checks its cancellation rules, and if it has not been cancelled itself, then it checks the tokens nested in it. Thus, one cancelled token nested in another non-cancelled token cancels it: ```python from cantok import SimpleToken diff --git a/docs/what_are_tokens/exceptions.md b/docs/what_are_tokens/exceptions.md index c874a37..5c79023 100644 --- a/docs/what_are_tokens/exceptions.md +++ b/docs/what_are_tokens/exceptions.md @@ -1,4 +1,4 @@ -When a token is cancelled, you can call the `check()` method from it and an exception will be raised: +When a token is cancelled, you can call the `check()` method on it and an exception will be raised: ```python from cantok import TimeoutToken @@ -17,7 +17,7 @@ Each type of token (except [`DefaultToken`](../types_of_tokens/DefaultToken.md)) - [`TimeoutToken`](../types_of_tokens/TimeoutToken.md) -> `TimeoutCancellationError` - [`CounterToken`](../types_of_tokens/CounterToken.md) -> `CounterCancellationError` -When you call the `check()` method on any token, one of two things will happen. If it (or any of the tokens nested in it) has been cancelled by calling the `cancel()` method, `CancellationError` will always be raised. But if the cancellation occurred as a result of the unique ability of the token, such as for `TimeoutToken` - timeout expiration, then an exception specific to this type of token will be raised. +When you call the `check()` method on any token, one of two things will happen. If it (or any of the tokens nested in it) has been cancelled by calling the `cancel()` method, `CancellationError` will always be raised. But if the cancellation occurred as a result of the unique ability of the token, such as for `TimeoutToken` — timeout expiration, then an exception specific to this type of token will be raised. `ConditionCancellationError`, `TimeoutCancellationError` and `CounterCancellationError` are inherited from `CancellationError`, so if you're not sure which exception specifically you're catching, catch `CancellationError`. But also all the listed exceptions can always be imported separately: diff --git a/docs/what_are_tokens/in_general.md b/docs/what_are_tokens/in_general.md index 039c3b3..c04cad8 100644 --- a/docs/what_are_tokens/in_general.md +++ b/docs/what_are_tokens/in_general.md @@ -19,7 +19,7 @@ Each of them has its own characteristics, but they also have something in common - Token cancellation is a one-way operation. A token that has already been cancelled cannot be restored. -- All token classes inherit from `AbstractToken` and have a single interface that defines how they can be cancelled, how to find out their status, how to wait for their cancellation and much more. If you are writing a function that accepts an unknown token type, you can use `AbstractToken` to hint types: +- All token classes inherit from `AbstractToken` and have a single interface that defines how they can be cancelled, how to find out their status, how to wait for their cancellation and much more. If you are writing a function that accepts an unknown token type, you can use `AbstractToken` for type hints: ```python from cantok import AbstractToken diff --git a/docs/what_are_tokens/waiting.md b/docs/what_are_tokens/waiting.md index 0cd310a..01ea87c 100644 --- a/docs/what_are_tokens/waiting.md +++ b/docs/what_are_tokens/waiting.md @@ -28,7 +28,7 @@ async def main(): asyncio.run(main()) ``` -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. +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. In addition to the above, the `wait()` method has two optional arguments: From f109ecee3b515851e80610cf29960f6f37f93a34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=91=D0=BB?= =?UTF-8?q?=D0=B8=D0=BD=D0=BE=D0=B2?= Date: Tue, 31 Mar 2026 12:26:55 +0300 Subject: [PATCH 2/9] Fix typo in CounterToken docs and clarify direct parameter behavior --- cantok/tokens/abstract/abstract_token.py | 2 +- cantok/tokens/abstract/report.py | 6 +++--- cantok/tokens/counter_token.py | 7 ++++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/cantok/tokens/abstract/abstract_token.py b/cantok/tokens/abstract/abstract_token.py index 5a77aee..4c33f69 100644 --- a/cantok/tokens/abstract/abstract_token.py +++ b/cantok/tokens/abstract/abstract_token.py @@ -210,7 +210,7 @@ def wait(self, step: Union[int, float] = 0.0001, timeout: Optional[Union[int, fl >>> >>> token = TimeoutToken(5) >>> token.wait() # blocks for ~5 seconds, then returns - >>> asyncio.run(token.wait()) # non-blocking, inside an asyncio event loop + >>> asyncio.run(TimeoutToken(5).wait()) # non-blocking, inside an asyncio event loop """ if step < 0: raise ValueError('The token polling iteration time cannot be less than zero.') diff --git a/cantok/tokens/abstract/report.py b/cantok/tokens/abstract/report.py index e4a0180..6efe793 100644 --- a/cantok/tokens/abstract/report.py +++ b/cantok/tokens/abstract/report.py @@ -5,11 +5,11 @@ from cantok.tokens.abstract.cancel_cause import CancelCause if version_info >= (3, 10): - addictional_fields: Dict[str, bool] = {'slots': True} # pragma: no cover + additional_fields: Dict[str, bool] = {'slots': True} # pragma: no cover else: - addictional_fields = {} # pragma: no cover + additional_fields = {} # pragma: no cover -@dataclass(frozen=True, **addictional_fields) # type: ignore[call-overload, unused-ignore] +@dataclass(frozen=True, **additional_fields) # type: ignore[call-overload, unused-ignore] class CancellationReport: cause: CancelCause from_token: 'AbstractToken' # type: ignore[name-defined] diff --git a/cantok/tokens/counter_token.py b/cantok/tokens/counter_token.py index 9a814fb..7dfe888 100644 --- a/cantok/tokens/counter_token.py +++ b/cantok/tokens/counter_token.py @@ -13,9 +13,10 @@ class CounterToken(ConditionToken): iterations of a loop without tracking state externally. :param counter: Number of iterations before cancellation. Must be >= 0. - :param direct: If True (default), counter decrements even when polled - indirectly through a parent token. If False, indirect polls - are rolled back, so only direct checks consume the counter. + :param direct: If False, the counter decrements even when polled + indirectly through a parent token. If True (default), + indirect polls are rolled back, so only direct checks + consume the counter. >>> token = CounterToken(3) >>> while token: From 57043e1462b1f120d044de8ae8bdd7bf1ba52482 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=91=D0=BB?= =?UTF-8?q?=D0=B8=D0=BD=D0=BE=D0=B2?= Date: Tue, 31 Mar 2026 12:28:16 +0300 Subject: [PATCH 3/9] Bumped version to 0.0.36 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index b7276f7..d8f9b29 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "cantok" -version = "0.0.35" +version = "0.0.36" authors = [{ name = "Evgeniy Blinov", email = "zheni-b@yandex.ru" }] description = 'Implementation of the "Cancellation Token" pattern' readme = "README.md" From f06a899f9d7b821e7251168b629636543d417e3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=91=D0=BB?= =?UTF-8?q?=D0=B8=D0=BD=D0=BE=D0=B2?= Date: Tue, 31 Mar 2026 12:32:08 +0300 Subject: [PATCH 4/9] Fix grammar and punctuation in documentation files --- docs/the_pattern.md | 2 +- docs/types_of_tokens/ConditionToken.md | 4 ++-- docs/what_are_tokens/cancel_and_read_the_status.md | 2 +- docs/what_are_tokens/exceptions.md | 2 +- docs/what_are_tokens/in_general.md | 2 +- docs/what_are_tokens/summation.md | 2 +- docs/what_are_tokens/waiting.md | 4 ++-- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/the_pattern.md b/docs/the_pattern.md index 5f9290e..eb1854d 100644 --- a/docs/the_pattern.md +++ b/docs/the_pattern.md @@ -8,4 +8,4 @@ In addition, the pattern assumes that various restrictions can be combined with Unlike other ways of stopping code execution, tokens do not force the execution thread to be interrupted. The interruption occurs "gently", allowing the code to terminate correctly, release all held resources and restore consistency. -It is highly desirable for library developers to use this pattern for any long-running operations. Your function can accept a token as an optional argument, with a default value that imposes minimal restrictions or none at all. If the user wishes, they can pass their token to it, imposing stricter restrictions on the library code. In addition to a more convenient and extensible API, this will give the library an advantage in the form of better testability, because the restrictions are no longer hardcoded into the function, which means they can be set to any value needed for testing. In addition, the library developer no longer needs to think about all the numerous restrictions that can be imposed on their code - the user can take care of it themselves if they need to. +It is highly desirable for library developers to use this pattern for any long-running operations. Your function can accept a token as an optional argument, with a default value that imposes minimal restrictions or none at all. If the user wishes, they can pass their token to it, imposing stricter restrictions on the library code. In addition to a more convenient and extensible API, this will give the library an advantage in the form of better testability, because the restrictions are no longer hardcoded into the function, which means they can be set to any value needed for testing. In addition, the library developer no longer needs to think about all the numerous restrictions that can be imposed on their code — the user can take care of it themselves if they need to. diff --git a/docs/types_of_tokens/ConditionToken.md b/docs/types_of_tokens/ConditionToken.md index 1323125..0a100ff 100644 --- a/docs/types_of_tokens/ConditionToken.md +++ b/docs/types_of_tokens/ConditionToken.md @@ -1,4 +1,4 @@ -`ConditionToken` has a superpower: it can check arbitrary conditions. In addition to this, it can do all the same things as [`SimpleToken`](../types_of_tokens/SimpleToken.md). The condition is a function that returns an answer to the question "has the token been cancelled" (`True`/`False`), it is passed to the token as the first required argument during initialization: +`ConditionToken` has a superpower: it can check arbitrary conditions. In addition to this, it can do all the same things as [`SimpleToken`](../types_of_tokens/SimpleToken.md). The condition is a function that returns an answer to the question "has the token been cancelled" (`True`/`False`); it is passed to the token as the first required argument during initialization: ```python from cantok import ConditionToken @@ -19,7 +19,7 @@ def function(): raise ValueError token = ConditionToken(function, suppress_exceptions=False) -token.cancelled # ValueError has been raised. +token.cancelled # ValueError will be raised. ``` When using exception suppression mode, the `cancelled` attribute will be `False` by default in case of an exception. If you want to change this, pass `default=True`. diff --git a/docs/what_are_tokens/cancel_and_read_the_status.md b/docs/what_are_tokens/cancel_and_read_the_status.md index 256a0c9..ac4e79c 100644 --- a/docs/what_are_tokens/cancel_and_read_the_status.md +++ b/docs/what_are_tokens/cancel_and_read_the_status.md @@ -62,7 +62,7 @@ print(bool(token)) #> False print(token.keep_on()) #> False ``` -There is another method that is close in meaning to `is_cancelled()` — `check()`. It does nothing if the token is not cancelled, or raises an exception if cancelled. If the token was cancelled by calling the `cancel()` method, a `CancellationError` exception will be raised: +There is another method that is close in meaning to `is_cancelled()` — `check()`. It does nothing if the token is not cancelled, or raises an exception if it is cancelled. If the token was cancelled by calling the `cancel()` method, a `CancellationError` exception will be raised: ```python from cantok import SimpleToken diff --git a/docs/what_are_tokens/exceptions.md b/docs/what_are_tokens/exceptions.md index 5c79023..1751286 100644 --- a/docs/what_are_tokens/exceptions.md +++ b/docs/what_are_tokens/exceptions.md @@ -19,7 +19,7 @@ Each type of token (except [`DefaultToken`](../types_of_tokens/DefaultToken.md)) When you call the `check()` method on any token, one of two things will happen. If it (or any of the tokens nested in it) has been cancelled by calling the `cancel()` method, `CancellationError` will always be raised. But if the cancellation occurred as a result of the unique ability of the token, such as for `TimeoutToken` — timeout expiration, then an exception specific to this type of token will be raised. -`ConditionCancellationError`, `TimeoutCancellationError` and `CounterCancellationError` are inherited from `CancellationError`, so if you're not sure which exception specifically you're catching, catch `CancellationError`. But also all the listed exceptions can always be imported separately: +`ConditionCancellationError`, `TimeoutCancellationError` and `CounterCancellationError` are inherited from `CancellationError`, so if you're not sure which exception specifically you're catching, catch `CancellationError`. All of the listed exceptions can also be imported separately: ```python from cantok import CancellationError, ConditionCancellationError, TimeoutCancellationError, CounterCancellationError diff --git a/docs/what_are_tokens/in_general.md b/docs/what_are_tokens/in_general.md index c04cad8..7fdebb5 100644 --- a/docs/what_are_tokens/in_general.md +++ b/docs/what_are_tokens/in_general.md @@ -13,7 +13,7 @@ Additionally, there is a 5th type that cannot be cancelled: Each of them has its own characteristics, but they also have something in common: -- Each token (except [`DefaultToken`](../types_of_tokens/DefaultToken.md)) can be cancelled manually, and some types of tokens can cancel themselves when a condition or timeout occurs. It doesn't matter how the token was cancelled, you work with it the same way. +- Each token (except [`DefaultToken`](../types_of_tokens/DefaultToken.md)) can be cancelled manually, and some types of tokens can cancel themselves when a condition or timeout occurs. It doesn't matter how the token was cancelled; you work with it the same way. - All types of tokens are thread-safe and can be used from multiple threads/coroutines. However, they are not intended to be shared across multiple processes. diff --git a/docs/what_are_tokens/summation.md b/docs/what_are_tokens/summation.md index 2504e9c..9d0cbb6 100644 --- a/docs/what_are_tokens/summation.md +++ b/docs/what_are_tokens/summation.md @@ -18,7 +18,7 @@ def function(token: AbstractToken): ... ``` -The token summation operation always generates a new token. If at least one of the operand tokens is cancelled, the sum will also be cancelled. It is also guaranteed that the cancellation of this token does not lead to the cancellation of the operands. That is, the sum of two tokens always behaves as if it were a [`SimpleToken`](../types_of_tokens/SimpleToken.md) in which both operands were [nested](embedding.md). However, it is difficult to say exactly which token will result from summation, since the library strives to minimize the generated graph of tokens for performance reasons. +The token summation operation always generates a new token. If at least one of the operand tokens is cancelled, the sum will also be cancelled. It is also guaranteed that the cancellation of this token does not lead to the cancellation of the operands. That is, the sum of two tokens always behaves as if it were a [`SimpleToken`](../types_of_tokens/SimpleToken.md) in which both operands were [nested](embedding.md). However, it is difficult to say exactly which token will result from the summation, since the library strives to minimize the generated graph of tokens for performance reasons. You may notice that some tokens disappear altogether during summation: diff --git a/docs/what_are_tokens/waiting.md b/docs/what_are_tokens/waiting.md index 01ea87c..d655921 100644 --- a/docs/what_are_tokens/waiting.md +++ b/docs/what_are_tokens/waiting.md @@ -32,5 +32,5 @@ Yes, it looks like magic — it is magic. The method itself finds out how it was In addition to the above, the `wait()` method has two optional arguments: -- **`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. -- **`step`** (`int` or `float`, by default `0.0001`) - the duration of each iteration during which the token state is polled, in seconds. For obvious reasons, you cannot set this value to a number that exceeds the `timeout`. +- **`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. +- **`step`** (`int` or `float`, by default `0.0001`) — the duration of each iteration during which the token state is polled, in seconds. For obvious reasons, you cannot set this value to a number that exceeds the `timeout`. From e0cc77cfbdae475b0d48fba357989de06bc2404a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=91=D0=BB?= =?UTF-8?q?=D0=B8=D0=BD=D0=BE=D0=B2?= Date: Tue, 31 Mar 2026 12:36:32 +0300 Subject: [PATCH 5/9] Update documentation for consistent terminology and clarity --- docs/ecosystem/about_ecosystem.md | 2 +- docs/the_pattern.md | 2 +- docs/types_of_tokens/ConditionToken.md | 2 +- docs/types_of_tokens/DefaultToken.md | 2 +- docs/what_are_tokens/cancel_and_read_the_status.md | 2 +- docs/what_are_tokens/embedding.md | 2 +- docs/what_are_tokens/exceptions.md | 2 +- docs/what_are_tokens/summation.md | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/ecosystem/about_ecosystem.md b/docs/ecosystem/about_ecosystem.md index df9b084..992486b 100644 --- a/docs/ecosystem/about_ecosystem.md +++ b/docs/ecosystem/about_ecosystem.md @@ -1 +1 @@ -We recommend adding token support to all your libraries where possible. If you have written such a project or added token support to an existing project, please let us know by writing an [issue](https://github.com/pomponchik/cantok/issues/new). If possible, information about the project will be added here. +We recommend adding token support to all your libraries where possible. If you have written such a project or added token support to an existing project, please let us know by opening an [issue](https://github.com/pomponchik/cantok/issues/new). If possible, information about the project will be added here. diff --git a/docs/the_pattern.md b/docs/the_pattern.md index eb1854d..ab2a4d1 100644 --- a/docs/the_pattern.md +++ b/docs/the_pattern.md @@ -2,7 +2,7 @@ Cancellation Token is a pattern that allows us to cancel calculations that we no longer need. It is implemented out of the box in many programming languages, for example in [C#](https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtoken) and in [Go](https://pkg.go.dev/context). However, there was still no sane implementation in Python, until the [cantok](https://github.com/pomponchik/cantok) library appeared. -The essence of the pattern is that we pass special objects to functions and constructors, by which the executed code can understand whether it should continue its execution or not. When deciding whether to allow code execution to continue, this object can both take into account the restrictions imposed on it, such as the maximum code execution time, and receive signals about the need to stop from the outside, for example from another thread or a coroutine. Thus, we do not nail down the logic associated with stopping code execution, for example, by directly tracking loop counters, but implement [Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection) of this restriction. +The essence of the pattern is that we pass special objects to functions and constructors, by which the executed code can understand whether it should continue its execution. When deciding whether to allow code execution to continue, this object can both take into account the restrictions imposed on it, such as the maximum code execution time, and receive signals about the need to stop from the outside, for example from another thread or a coroutine. Thus, we do not nail down the logic associated with stopping code execution, for example, by directly tracking loop counters, but implement [Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection) of this restriction. In addition, the pattern assumes that various restrictions can be combined with each other without limit: if at least one of the restrictions is not met, code execution will be interrupted. It is assumed that each function in the call stack will call other functions, passing its token directly to them, or wrapping it in another token with stricter restrictions. diff --git a/docs/types_of_tokens/ConditionToken.md b/docs/types_of_tokens/ConditionToken.md index 0a100ff..32dca36 100644 --- a/docs/types_of_tokens/ConditionToken.md +++ b/docs/types_of_tokens/ConditionToken.md @@ -44,7 +44,7 @@ token.check() #> 2 ``` -By analogy with `before`, you can pass a function that will be executed after checking the condition as the `after` argument: +By analogy with `before`, you can pass a function as the `after` argument that will be executed after checking the condition: ```python token = ConditionToken(lambda: print(1), after=lambda: print(2)) diff --git a/docs/types_of_tokens/DefaultToken.md b/docs/types_of_tokens/DefaultToken.md index 4320077..6438f2f 100644 --- a/docs/types_of_tokens/DefaultToken.md +++ b/docs/types_of_tokens/DefaultToken.md @@ -1,4 +1,4 @@ -`DefaultToken` is a type of token that cannot be cancelled. Otherwise, it behaves like a regular token, but if you try to cancel it, you will get an exception: +`DefaultToken` is a type of token that cannot be cancelled. In all other respects, it behaves like a regular token: ```python from cantok import AbstractToken, DefaultToken diff --git a/docs/what_are_tokens/cancel_and_read_the_status.md b/docs/what_are_tokens/cancel_and_read_the_status.md index ac4e79c..06c3e0f 100644 --- a/docs/what_are_tokens/cancel_and_read_the_status.md +++ b/docs/what_are_tokens/cancel_and_read_the_status.md @@ -9,7 +9,7 @@ token.cancel() print(token.cancelled) #> True ``` -The cancelled attribute is dynamically calculated and takes into account, among other things, specific conditions that are checked by a specific token. Here is an example with a [token that measures time](../types_of_tokens/TimeoutToken.md): +The cancelled attribute is dynamically calculated and takes into account, among other things, conditions specific to that token type. Here is an example with a [token that measures time](../types_of_tokens/TimeoutToken.md): ```python from time import sleep diff --git a/docs/what_are_tokens/embedding.md b/docs/what_are_tokens/embedding.md index 5833487..da2fa16 100644 --- a/docs/what_are_tokens/embedding.md +++ b/docs/what_are_tokens/embedding.md @@ -1,4 +1,4 @@ -You can embed an unlimited number of other tokens in one token by passing them as arguments during initialization. Each time checking whether it has been cancelled, the token first checks its cancellation rules, and if it has not been cancelled itself, then it checks the tokens nested in it. Thus, one cancelled token nested in another non-cancelled token cancels it: +You can embed an unlimited number of other tokens in one token by passing them as arguments during initialization. Each time it checks whether it has been cancelled, the token first checks its cancellation rules, and if it has not been cancelled itself, then it checks the tokens nested in it. Thus, one cancelled token nested in another non-cancelled token cancels it: ```python from cantok import SimpleToken diff --git a/docs/what_are_tokens/exceptions.md b/docs/what_are_tokens/exceptions.md index 1751286..c8fa422 100644 --- a/docs/what_are_tokens/exceptions.md +++ b/docs/what_are_tokens/exceptions.md @@ -19,7 +19,7 @@ Each type of token (except [`DefaultToken`](../types_of_tokens/DefaultToken.md)) When you call the `check()` method on any token, one of two things will happen. If it (or any of the tokens nested in it) has been cancelled by calling the `cancel()` method, `CancellationError` will always be raised. But if the cancellation occurred as a result of the unique ability of the token, such as for `TimeoutToken` — timeout expiration, then an exception specific to this type of token will be raised. -`ConditionCancellationError`, `TimeoutCancellationError` and `CounterCancellationError` are inherited from `CancellationError`, so if you're not sure which exception specifically you're catching, catch `CancellationError`. All of the listed exceptions can also be imported separately: +`ConditionCancellationError`, `TimeoutCancellationError` and `CounterCancellationError` are inherited from `CancellationError`, so if you're not sure which specific exception you're catching, catch `CancellationError`. All of the listed exceptions can also be imported separately: ```python from cantok import CancellationError, ConditionCancellationError, TimeoutCancellationError, CounterCancellationError diff --git a/docs/what_are_tokens/summation.md b/docs/what_are_tokens/summation.md index 9d0cbb6..b361594 100644 --- a/docs/what_are_tokens/summation.md +++ b/docs/what_are_tokens/summation.md @@ -29,7 +29,7 @@ print(repr(SimpleToken(cancelled=True) + TimeoutToken(5))) #> SimpleToken(cancelled=True) ``` -In addition, you can safely sum more than 2 tokens - this does not generate anything superfluous: +In addition, you can safely sum more than 2 tokens — this does not generate anything superfluous: ```python print(repr(TimeoutToken(5) + ConditionToken(lambda: False) + CounterToken(23))) From 7f5804458b86611e454702d4ff4869d7140e8f3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=91=D0=BB?= =?UTF-8?q?=D0=B8=D0=BD=D0=BE=D0=B2?= Date: Tue, 31 Mar 2026 12:44:49 +0300 Subject: [PATCH 6/9] Fix typos and improve clarity in documentation --- docs/quick_start.md | 2 +- docs/types_of_tokens/ConditionToken.md | 4 ++-- docs/types_of_tokens/DefaultToken.md | 4 ++-- docs/types_of_tokens/TimeoutToken.md | 2 +- docs/what_are_tokens/cancel_and_read_the_status.md | 2 +- docs/what_are_tokens/exceptions.md | 2 +- docs/what_are_tokens/in_general.md | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/quick_start.md b/docs/quick_start.md index 8bd1e42..c3cb4af 100644 --- a/docs/quick_start.md +++ b/docs/quick_start.md @@ -14,6 +14,6 @@ while token: print(counter) ``` -In this code, we use a token that describes several restrictions: on the [number of iterations](types_of_tokens/CounterToken.md) of the loop, on [time](types_of_tokens/TimeoutToken.md), as well as on the [occurrence](types_of_tokens/ConditionToken.md) of a random unlikely event. When any of the indicated events occur, the loop stops. +In this code, we use a token that describes several restrictions: on the [number of iterations](types_of_tokens/CounterToken.md) of the loop, on [time](types_of_tokens/TimeoutToken.md), as well as on the [occurrence](types_of_tokens/ConditionToken.md) of a random unlikely event. When any of the listed events occur, the loop stops. In fact, the library's capabilities are much broader. Read the documentation below. diff --git a/docs/types_of_tokens/ConditionToken.md b/docs/types_of_tokens/ConditionToken.md index 32dca36..4360968 100644 --- a/docs/types_of_tokens/ConditionToken.md +++ b/docs/types_of_tokens/ConditionToken.md @@ -19,7 +19,7 @@ def function(): raise ValueError token = ConditionToken(function, suppress_exceptions=False) -token.cancelled # ValueError will be raised. +token.cancelled # ValueError will be raised. ``` When using exception suppression mode, the `cancelled` attribute will be `False` by default in case of an exception. If you want to change this, pass `default=True`. @@ -54,7 +54,7 @@ token.check() #> 2 ``` -`ConditionToken` has another feature. If the condition has evaluated to True at least once and cancelled the token, then the condition is no longer polled and the token is permanently considered cancelled. You can change this by manipulating the `caching` parameter when creating a token. By setting it to `False`, you will make sure that the condition is polled every time. +`ConditionToken` has another feature. If the condition has returned True at least once and cancelled the token, then the condition is no longer polled and the token is permanently considered cancelled. You can change this by manipulating the `caching` parameter when creating a token. By setting it to `False`, you will make sure that the condition is polled every time. ```python counter = 0 diff --git a/docs/types_of_tokens/DefaultToken.md b/docs/types_of_tokens/DefaultToken.md index 6438f2f..0a8b81f 100644 --- a/docs/types_of_tokens/DefaultToken.md +++ b/docs/types_of_tokens/DefaultToken.md @@ -1,4 +1,4 @@ -`DefaultToken` is a type of token that cannot be cancelled. In all other respects, it behaves like a regular token: +`DefaultToken` is a type of token that cannot be cancelled — if you try to cancel it, an exception will be raised: ```python from cantok import AbstractToken, DefaultToken @@ -8,7 +8,7 @@ DefaultToken().cancel() #> cantok.errors.ImpossibleCancelError: You cannot cancel a default token. ``` -In addition, you cannot embed other tokens in `DefaultToken`. +In addition, you cannot embed other tokens in `DefaultToken`. In all other respects, it behaves like a regular token. It is best to use `DefaultToken` as the default argument for functions: diff --git a/docs/types_of_tokens/TimeoutToken.md b/docs/types_of_tokens/TimeoutToken.md index edb1cc1..260184d 100644 --- a/docs/types_of_tokens/TimeoutToken.md +++ b/docs/types_of_tokens/TimeoutToken.md @@ -10,7 +10,7 @@ sleep(10) print(token.cancelled) #> True ``` -Just like `ConditionToken`, `TimeoutToken` can include other tokens: +Just like `ConditionToken`, `TimeoutToken` can embed other tokens: ```python token = TimeoutToken(45, SimpleToken(), TimeoutToken(5), CounterToken(20)) # Includes all additional restrictions of the passed tokens. diff --git a/docs/what_are_tokens/cancel_and_read_the_status.md b/docs/what_are_tokens/cancel_and_read_the_status.md index 06c3e0f..f1261b5 100644 --- a/docs/what_are_tokens/cancel_and_read_the_status.md +++ b/docs/what_are_tokens/cancel_and_read_the_status.md @@ -1,4 +1,4 @@ -Each token object has a `cancelled` attribute and a `cancel()` method. By the attribute, you can find out whether this token has been cancelled: +Each token object has a `cancelled` attribute and a `cancel()` method. Using the attribute, you can find out whether this token has been cancelled: ```python from cantok import SimpleToken diff --git a/docs/what_are_tokens/exceptions.md b/docs/what_are_tokens/exceptions.md index c8fa422..d206156 100644 --- a/docs/what_are_tokens/exceptions.md +++ b/docs/what_are_tokens/exceptions.md @@ -17,7 +17,7 @@ Each type of token (except [`DefaultToken`](../types_of_tokens/DefaultToken.md)) - [`TimeoutToken`](../types_of_tokens/TimeoutToken.md) -> `TimeoutCancellationError` - [`CounterToken`](../types_of_tokens/CounterToken.md) -> `CounterCancellationError` -When you call the `check()` method on any token, one of two things will happen. If it (or any of the tokens nested in it) has been cancelled by calling the `cancel()` method, `CancellationError` will always be raised. But if the cancellation occurred as a result of the unique ability of the token, such as for `TimeoutToken` — timeout expiration, then an exception specific to this type of token will be raised. +When you call the `check()` method on any token, one of two things will happen. If it (or any of the tokens nested in it) has been cancelled by calling the `cancel()` method, `CancellationError` will always be raised. But if the cancellation occurred as a result of the unique ability of the token, such as timeout expiration for `TimeoutToken`, then an exception specific to this type of token will be raised. `ConditionCancellationError`, `TimeoutCancellationError` and `CounterCancellationError` are inherited from `CancellationError`, so if you're not sure which specific exception you're catching, catch `CancellationError`. All of the listed exceptions can also be imported separately: diff --git a/docs/what_are_tokens/in_general.md b/docs/what_are_tokens/in_general.md index 7fdebb5..5dbc759 100644 --- a/docs/what_are_tokens/in_general.md +++ b/docs/what_are_tokens/in_general.md @@ -19,7 +19,7 @@ Each of them has its own characteristics, but they also have something in common - Token cancellation is a one-way operation. A token that has already been cancelled cannot be restored. -- All token classes inherit from `AbstractToken` and have a single interface that defines how they can be cancelled, how to find out their status, how to wait for their cancellation and much more. If you are writing a function that accepts an unknown token type, you can use `AbstractToken` for type hints: +- All token classes inherit from `AbstractToken` and have a single interface that defines how they can be cancelled, how to find out their status, how to wait for their cancellation, and much more. If you are writing a function that accepts an unknown token type, you can use `AbstractToken` for type hints: ```python from cantok import AbstractToken From 3c25ce8b99060b5f29b44e83a429050f34d6e137 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=91=D0=BB?= =?UTF-8?q?=D0=B8=D0=BD=D0=BE=D0=B2?= Date: Tue, 31 Mar 2026 13:00:24 +0300 Subject: [PATCH 7/9] Refine documentation wording for consistency and clarity --- docs/the_pattern.md | 2 +- docs/types_of_tokens/ConditionToken.md | 2 +- docs/what_are_tokens/exceptions.md | 2 +- docs/what_are_tokens/summation.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/the_pattern.md b/docs/the_pattern.md index ab2a4d1..c26b47c 100644 --- a/docs/the_pattern.md +++ b/docs/the_pattern.md @@ -2,7 +2,7 @@ Cancellation Token is a pattern that allows us to cancel calculations that we no longer need. It is implemented out of the box in many programming languages, for example in [C#](https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtoken) and in [Go](https://pkg.go.dev/context). However, there was still no sane implementation in Python, until the [cantok](https://github.com/pomponchik/cantok) library appeared. -The essence of the pattern is that we pass special objects to functions and constructors, by which the executed code can understand whether it should continue its execution. When deciding whether to allow code execution to continue, this object can both take into account the restrictions imposed on it, such as the maximum code execution time, and receive signals about the need to stop from the outside, for example from another thread or a coroutine. Thus, we do not nail down the logic associated with stopping code execution, for example, by directly tracking loop counters, but implement [Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection) of this restriction. +The essence of the pattern is that we pass special objects to functions and constructors, through which the executing code can determine whether it should continue its execution. When deciding whether to allow code execution to continue, this object can both take into account the restrictions imposed on it, such as the maximum code execution time, and receive signals about the need to stop from the outside, for example from another thread or a coroutine. Thus, we do not nail down the logic associated with stopping code execution, for example, by directly tracking loop counters, but implement [Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection) of this restriction. In addition, the pattern assumes that various restrictions can be combined with each other without limit: if at least one of the restrictions is not met, code execution will be interrupted. It is assumed that each function in the call stack will call other functions, passing its token directly to them, or wrapping it in another token with stricter restrictions. diff --git a/docs/types_of_tokens/ConditionToken.md b/docs/types_of_tokens/ConditionToken.md index 4360968..949d45e 100644 --- a/docs/types_of_tokens/ConditionToken.md +++ b/docs/types_of_tokens/ConditionToken.md @@ -1,4 +1,4 @@ -`ConditionToken` has a superpower: it can check arbitrary conditions. In addition to this, it can do all the same things as [`SimpleToken`](../types_of_tokens/SimpleToken.md). The condition is a function that returns an answer to the question "has the token been cancelled" (`True`/`False`); it is passed to the token as the first required argument during initialization: +`ConditionToken` has a superpower: it can check arbitrary conditions. In addition to this, it can do all the same things as [`SimpleToken`](../types_of_tokens/SimpleToken.md). The condition is a function that returns an answer to the question "should the token be cancelled" (`True`/`False`); it is passed to the token as the first required argument during initialization: ```python from cantok import ConditionToken diff --git a/docs/what_are_tokens/exceptions.md b/docs/what_are_tokens/exceptions.md index d206156..34b3b77 100644 --- a/docs/what_are_tokens/exceptions.md +++ b/docs/what_are_tokens/exceptions.md @@ -19,7 +19,7 @@ Each type of token (except [`DefaultToken`](../types_of_tokens/DefaultToken.md)) When you call the `check()` method on any token, one of two things will happen. If it (or any of the tokens nested in it) has been cancelled by calling the `cancel()` method, `CancellationError` will always be raised. But if the cancellation occurred as a result of the unique ability of the token, such as timeout expiration for `TimeoutToken`, then an exception specific to this type of token will be raised. -`ConditionCancellationError`, `TimeoutCancellationError` and `CounterCancellationError` are inherited from `CancellationError`, so if you're not sure which specific exception you're catching, catch `CancellationError`. All of the listed exceptions can also be imported separately: +`ConditionCancellationError`, `TimeoutCancellationError`, and `CounterCancellationError` are inherited from `CancellationError`, so if you're not sure which specific exception you're catching, catch `CancellationError`. All of the listed exceptions can also be imported separately: ```python from cantok import CancellationError, ConditionCancellationError, TimeoutCancellationError, CounterCancellationError diff --git a/docs/what_are_tokens/summation.md b/docs/what_are_tokens/summation.md index b361594..168477e 100644 --- a/docs/what_are_tokens/summation.md +++ b/docs/what_are_tokens/summation.md @@ -7,7 +7,7 @@ print(repr(first_token + second_token)) #> SimpleToken(TimeoutToken(5), ConditionToken(λ)) ``` -This feature is convenient to use if your function has received a token with certain restrictions and wants to pass it to other called functions, imposing additional restrictions: +This feature is convenient to use if your function has received a token with certain restrictions and needs to pass it to other called functions, imposing additional restrictions: ```python from cantok import AbstractToken, TimeoutToken From 06abcf8655997114fa0fd9a60c7f1612bd723165 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=91=D0=BB?= =?UTF-8?q?=D0=B8=D0=BD=D0=BE=D0=B2?= Date: Tue, 31 Mar 2026 14:29:43 +0300 Subject: [PATCH 8/9] Add support for Python 3.14t and Free Threading classifiers --- pyproject.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index d8f9b29..8f0710e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,6 +29,8 @@ classifiers = [ 'Programming Language :: Python :: 3.13', 'Programming Language :: Python :: 3.14', 'Programming Language :: Python :: 3.15', + 'Programming Language :: Python :: Free Threading', + 'Programming Language :: Python :: Free Threading :: 3 - Stable', 'License :: OSI Approved :: MIT License', 'Intended Audience :: Developers', 'Topic :: Software Development :: Libraries', From e111fc3700a4af3f7b81be65581991b4dcb0b4b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=91=D0=BB?= =?UTF-8?q?=D0=B8=D0=BD=D0=BE=D0=B2?= Date: Tue, 31 Mar 2026 14:30:19 +0300 Subject: [PATCH 9/9] Update pyproject.toml to fix duplicate typing_extensions dependency --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 8f0710e..9ca835d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,9 +10,9 @@ description = 'Implementation of the "Cancellation Token" pattern' readme = "README.md" requires-python = ">=3.8" dependencies = [ - 'typing_extensions ; python_version <= "3.9"', 'displayhooks>=0.0.6', 'transfunctions>=0.0.12', + 'typing_extensions ; python_version <= "3.9"', ] classifiers = [ "Operating System :: OS Independent",