designkit 0.1.2__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {designkit-0.1.2 → designkit-0.2.0}/PKG-INFO +5 -2
- designkit-0.2.0/designkit/behavioral/cache/__init__.py +5 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/cache/core.py +4 -4
- designkit-0.2.0/designkit/behavioral/cache/fifo_cache.py +80 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/cache/lru_cache.py +5 -4
- designkit-0.2.0/designkit/behavioral/control/__init__.py +21 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/control/http.py +6 -6
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/control/promises.py +4 -4
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/control/validation.py +0 -18
- designkit-0.2.0/designkit/behavioral/pub_sub/__init__.py +4 -0
- designkit-0.2.0/designkit/behavioral/pub_sub/core.py +95 -0
- designkit-0.2.0/designkit/behavioral/typing/__init__.py +6 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/typing/core.py +204 -15
- designkit-0.2.0/designkit/behavioral/verboser/__init__.py +6 -0
- designkit-0.2.0/designkit/behavioral/verboser/core.py +163 -0
- designkit-0.2.0/designkit/creational/asymptotic/__init__.py +10 -0
- designkit-0.2.0/designkit/creational/asymptotic/core.py +38 -0
- designkit-0.2.0/designkit/creational/asymptotic/models.py +407 -0
- designkit-0.2.0/designkit/creational/backend/__init__.py +14 -0
- designkit-0.2.0/designkit/creational/backend/binjson.py +242 -0
- designkit-0.2.0/designkit/creational/backend/core.py +1 -0
- designkit-0.2.0/designkit/creational/backend/exceptions.py +21 -0
- designkit-0.2.0/designkit/creational/backend/json.py +240 -0
- designkit-0.2.0/designkit/creational/backend/utils.py +109 -0
- designkit-0.2.0/designkit/creational/toolbox/__init__.py +19 -0
- designkit-0.2.0/designkit/creational/toolbox/country/repository.py +16 -0
- designkit-0.2.0/designkit/creational/toolbox/currency/__init__.py +5 -0
- designkit-0.2.0/designkit/creational/toolbox/currency/repository.py +70 -0
- designkit-0.2.0/designkit/creational/toolbox/network/ip/__init__.py +5 -0
- designkit-0.2.0/designkit/creational/toolbox/network/ip/repository.py +72 -0
- designkit-0.2.0/designkit/creational/toolbox/translation/__init__.py +5 -0
- designkit-0.2.0/designkit/creational/toolbox/translation/repository.py +46 -0
- designkit-0.2.0/designkit/creational/toolbox/utils.py +144 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/__init__.py +2 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/card.py +2 -3
- designkit-0.2.0/designkit/creational/types/dtypes/coordinates.py +873 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/currency.py +84 -21
- {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/ident.py +2 -4
- {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/ip.py +3 -2
- {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/money.py +93 -48
- {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/percentage.py +4 -33
- {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/port.py +2 -1
- {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/temperature.py +6 -6
- designkit-0.2.0/designkit/structural/environment/__init__.py +3 -0
- designkit-0.2.0/designkit/structural/environment/core.py +221 -0
- designkit-0.2.0/designkit/structural/environment/exceptions.py +12 -0
- designkit-0.2.0/designkit/structural/interface/__init__.py +2 -0
- designkit-0.2.0/designkit/structural/interface/core.py +597 -0
- designkit-0.2.0/designkit/structural/performance/__init__.py +25 -0
- designkit-0.2.0/designkit/structural/performance/core.py +398 -0
- {designkit-0.1.2 → designkit-0.2.0}/pyproject.toml +5 -2
- {designkit-0.1.2 → designkit-0.2.0}/requirements.txt +3 -0
- designkit-0.1.2/designkit/behavioral/cache/__init__.py +0 -3
- designkit-0.1.2/designkit/behavioral/control/core.py +0 -22
- designkit-0.1.2/designkit/behavioral/typing/__init__.py +0 -5
- designkit-0.1.2/designkit/creational/types/dtypes/latitude.py +0 -8
- designkit-0.1.2/designkit/structural/modal_driven/__init__.py +0 -19
- designkit-0.1.2/designkit/structural/modal_driven/core.py +0 -17
- designkit-0.1.2/designkit/structural/modal_driven/modals/can.py +0 -11
- designkit-0.1.2/designkit/structural/modal_driven/modals/could.py +0 -19
- designkit-0.1.2/designkit/structural/modal_driven/modals/dare.py +0 -0
- designkit-0.1.2/designkit/structural/modal_driven/modals/have_to.py +0 -11
- designkit-0.1.2/designkit/structural/modal_driven/modals/may.py +0 -11
- designkit-0.1.2/designkit/structural/modal_driven/modals/might.py +0 -15
- designkit-0.1.2/designkit/structural/modal_driven/modals/must.py +0 -11
- designkit-0.1.2/designkit/structural/modal_driven/modals/need_to.py +0 -11
- designkit-0.1.2/designkit/structural/modal_driven/modals/ought_to.py +0 -11
- designkit-0.1.2/designkit/structural/modal_driven/modals/shall.py +0 -11
- designkit-0.1.2/designkit/structural/modal_driven/modals/should.py +0 -11
- designkit-0.1.2/designkit/structural/modal_driven/modals/used_to.py +0 -11
- designkit-0.1.2/designkit/structural/modal_driven/modals/will.py +0 -11
- designkit-0.1.2/designkit/structural/modal_driven/modals/would.py +0 -15
- designkit-0.1.2/designkit/structural/modal_driven/models.py +0 -129
- {designkit-0.1.2 → designkit-0.2.0}/.gitattributes +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/.github/PULL_REQUEST_TEMPLATE/new_pattern.md +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/.github/PULL_REQUEST_TEMPLATE/pattern_maintenance.md +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/.github/PULL_REQUEST_TEMPLATE/repo_maintenance.md +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/.github/workflows/CI.yml +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/.gitignore +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/CONTRIBUTING.md +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/Cargo.lock +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/Cargo.toml +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/LICENSE +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/README.md +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/TODO.md +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/__init__.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/_designkit.pdb +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/cache/exceptions.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/cache/models.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/chain_of_responsibility/__init__.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/chain_of_responsibility/core.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/command/__init__.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/command/commands.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/command/exceptions.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/command/invokers.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/command/models.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/command/receivers.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/command/utils.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/control/mathematical.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/control/result.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/imperactive/__init__.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/imperactive/core.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/imperactive/exceptions.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/interpreter/__init__.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/interpreter/builtin_exprs.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/interpreter/builtin_stmts.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/interpreter/builtin_units.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/interpreter/core.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/iterator/__init__.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/iterator/core.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/iterator/exceptions.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/iterator/iter_types.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/iterator/specialized/hashful.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/iterator/specialized/safeful.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/matcher/__init__.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/matcher/core.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/matcher/exceptions.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/mediator/__init__.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/mediator/core.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/memorable/__init__.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/memorable/core.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/memorable/exceptions.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/policy/__init__.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/policy/core.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/policy/exceptions.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/policy/models.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/state/__init__.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/state/core.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/state/exceptions.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/state/flowchartlib.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/state/fsm_types.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/state/renderers.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/state/tools.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/state/utils.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/strategy/__int__.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/strategy/core.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/strategy/exceptions.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/strategy/models.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/template/__init__.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/template/core.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/trie/__init__.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/trie/core.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/prototype/__init__.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/prototype/core.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/singleton/__init__.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/singleton/core.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/singleton/exceptions.py +0 -0
- {designkit-0.1.2/designkit/behavioral/control → designkit-0.2.0/designkit/creational/toolbox/country}/__init__.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/blob.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/card_networks.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/email.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/hostname.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/phone.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/quantity.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/url.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/thrird_party_dtypes.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/utils.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/structural/decorador/__init__.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/structural/decorador/core.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/structural/decorador/utils.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/structural/menu/__init__.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/designkit/structural/menu/core.py +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/rust/designkit/behavioral/interpreter/core.rs +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/rust/designkit/behavioral/mod.rs +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/rust/designkit/behavioral/typing/core.rs +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/rust/designkit/behavioral/typing/mod.rs +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/rust/designkit/creational/singleton/null +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/rust/designkit/mod.rs +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/rust/lib.rs +0 -0
- {designkit-0.1.2 → designkit-0.2.0}/samples/structural/modal_driven/soft_case.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: designkit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Classifier: Intended Audience :: Developers
|
|
5
5
|
Classifier: License :: OSI Approved :: MIT License
|
|
6
6
|
Classifier: Programming Language :: Rust
|
|
@@ -16,12 +16,15 @@ Requires-Dist: designkit-utils>=0.6.1,<0.7
|
|
|
16
16
|
Requires-Dist: validators>=0.35.0,<0.36
|
|
17
17
|
Requires-Dist: pathlib>=1.0.1,<2.0
|
|
18
18
|
Requires-Dist: rich>=15.0.0,<16.0
|
|
19
|
+
Requires-Dist: python-dotenv>=1.2.3,<2.0
|
|
20
|
+
Requires-Dist: httpx>=0.28.1,<0.29
|
|
21
|
+
Requires-Dist: msgspec>=0.21.1,<0.22
|
|
19
22
|
Requires-Dist: pytest>=9.1.1,<10.0 ; extra == 'dev'
|
|
20
23
|
Requires-Dist: pytest-cov>=5.3.1,<6.0 ; extra == 'dev'
|
|
21
24
|
Requires-Dist: mypy ; extra == 'dev'
|
|
22
25
|
Provides-Extra: dev
|
|
23
26
|
License-File: LICENSE
|
|
24
|
-
Summary: A modern Python toolkit for software architecture, featuring all
|
|
27
|
+
Summary: A modern Python toolkit for software architecture, featuring all 12 GoF + 18 original design patterns, original architectural patterns, and powerful developer utilities.
|
|
25
28
|
Keywords: patterns,design,kit,utils,framework,rust,pyo3
|
|
26
29
|
Author-email: Sheñey <sheneyby2010@gmail.com>
|
|
27
30
|
Requires-Python: >=3.14
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
from functools import wraps
|
|
3
3
|
from typing import Callable, overload, Any
|
|
4
4
|
|
|
5
|
-
from .models import _MISSING, AbstractCache
|
|
6
|
-
from .lru_cache import LRUCache
|
|
5
|
+
from designkit.behavioral.cache.models import _MISSING, AbstractCache
|
|
6
|
+
from designkit.behavioral.cache.lru_cache import LRUCache
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
@overload
|
|
@@ -17,7 +17,7 @@ def cached[F: Callable[..., R], R](
|
|
|
17
17
|
*,
|
|
18
18
|
capacity: int = 32,
|
|
19
19
|
cache: type[AbstractCache[R]] = LRUCache,
|
|
20
|
-
skip_when: Callable[[tuple[Any], dict[str, Any]], bool] = lambda args, kwargs: False,
|
|
20
|
+
skip_when: Callable[[tuple[Any], dict[str, Any]], bool] = lambda *args, **kwargs: False,
|
|
21
21
|
) -> Callable[[F], F]: ...
|
|
22
22
|
|
|
23
23
|
def cached[F: Callable[..., R], R](
|
|
@@ -26,7 +26,7 @@ def cached[F: Callable[..., R], R](
|
|
|
26
26
|
*,
|
|
27
27
|
capacity: int = 32,
|
|
28
28
|
cache: type[AbstractCache[R]] = LRUCache,
|
|
29
|
-
skip_when: Callable[[tuple[Any], dict[str, Any]], bool] = lambda args, kwargs: False,
|
|
29
|
+
skip_when: Callable[[tuple[Any], dict[str, Any]], bool] = lambda *args, **kwargs: False,
|
|
30
30
|
) -> Callable[[F], F]:
|
|
31
31
|
def decorator(func: F) -> F:
|
|
32
32
|
@wraps(func)
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
|
|
2
|
+
from typing import Hashable
|
|
3
|
+
from collections import deque
|
|
4
|
+
|
|
5
|
+
from designkit.behavioral.cache.exceptions import ItemNotHashableError
|
|
6
|
+
from designkit.behavioral.cache.models import _MISSING, AbstractCache
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class FIFOCache[T](AbstractCache[T]):
|
|
10
|
+
def __init__(self, capacity: int) -> None:
|
|
11
|
+
self.__capacity: int = capacity
|
|
12
|
+
self.__map: deque[tuple[Hashable, T]] = deque(maxlen=capacity)
|
|
13
|
+
|
|
14
|
+
def __str__(self) -> str:
|
|
15
|
+
return f'{self.__class__.__name__}( capacity={self.__capacity} )'
|
|
16
|
+
|
|
17
|
+
def __repr__(self) -> str:
|
|
18
|
+
fmt = lambda k, v: f'[{k}:{v}]'
|
|
19
|
+
return ''.join(fmt(k, v) for k, v in self.__map)
|
|
20
|
+
|
|
21
|
+
def __getitem__(self, key: Hashable) -> T:
|
|
22
|
+
return self.get(key, _MISSING)
|
|
23
|
+
|
|
24
|
+
def __setitem__(self, key: Hashable, value: T) -> None:
|
|
25
|
+
self.put(key, value)
|
|
26
|
+
|
|
27
|
+
def __contains__(self, key: Hashable) -> bool:
|
|
28
|
+
return any(k == key for k, _ in self.__map)
|
|
29
|
+
|
|
30
|
+
def __len__(self) -> int:
|
|
31
|
+
return len(self.__map)
|
|
32
|
+
|
|
33
|
+
def get(self, key: Hashable, default: T | object = _MISSING) -> T | object:
|
|
34
|
+
for k, v in self.__map:
|
|
35
|
+
if k == key:
|
|
36
|
+
return v
|
|
37
|
+
return default
|
|
38
|
+
|
|
39
|
+
def put(self, key: Hashable, value: T) -> None:
|
|
40
|
+
try:
|
|
41
|
+
for i, (k, _) in enumerate(self.__map):
|
|
42
|
+
if k == key:
|
|
43
|
+
del self.__map[i]
|
|
44
|
+
break
|
|
45
|
+
self.__map.append((key, value))
|
|
46
|
+
except TypeError:
|
|
47
|
+
raise ItemNotHashableError(self.__class__.__name__, key)
|
|
48
|
+
|
|
49
|
+
def dump(self, from_page: int = 0, to_page: int | None = None) -> list[tuple[Hashable, T]]:
|
|
50
|
+
PAGE_SIZE: int = 32
|
|
51
|
+
|
|
52
|
+
if to_page is None:
|
|
53
|
+
to_page = len(self.__map)
|
|
54
|
+
|
|
55
|
+
if from_page < 0 or to_page < 0 or from_page >= to_page:
|
|
56
|
+
raise ValueError(f'Invalid page range: from_page={from_page}, to_page={to_page}')
|
|
57
|
+
|
|
58
|
+
start_index: int = from_page * PAGE_SIZE
|
|
59
|
+
end_index: int = min(to_page * PAGE_SIZE, len(self.__map))
|
|
60
|
+
return list(self.__map)[start_index:end_index]
|
|
61
|
+
|
|
62
|
+
def clear(self) -> None:
|
|
63
|
+
self.__map.clear()
|
|
64
|
+
|
|
65
|
+
def copy(self) -> FIFOCache[T]:
|
|
66
|
+
new_cache: FIFOCache[T] = FIFOCache(self.__capacity)
|
|
67
|
+
new_cache.__map = self.__map.copy()
|
|
68
|
+
return new_cache
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def capacity(self) -> int:
|
|
72
|
+
return self.__capacity
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def free_space(self) -> int:
|
|
76
|
+
return self.__capacity - len(self.__map)
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def is_full(self) -> bool:
|
|
80
|
+
return len(self.__map) >= self.__capacity
|
|
@@ -4,6 +4,7 @@ from typing import Hashable
|
|
|
4
4
|
from designkit.behavioral.cache.exceptions import ItemNotHashableError
|
|
5
5
|
from designkit.behavioral.cache.models import _MISSING, AbstractCache
|
|
6
6
|
|
|
7
|
+
|
|
7
8
|
class Node[T]:
|
|
8
9
|
def __init__(self, key: Hashable, value: T) -> None:
|
|
9
10
|
self.key: Hashable = key
|
|
@@ -20,6 +21,9 @@ class LRUCache[T](AbstractCache[T]):
|
|
|
20
21
|
self.__head.next = self.__tail
|
|
21
22
|
self.__tail.prev = self.__head
|
|
22
23
|
|
|
24
|
+
def __str__(self) -> str:
|
|
25
|
+
return f'{self.__class__.__name__}( capacity={self.__capacity}, map={self.__map} )'
|
|
26
|
+
|
|
23
27
|
def __repr__(self) -> str:
|
|
24
28
|
nodes: list[str] = []
|
|
25
29
|
current: Node[T] | None = self.__head.next
|
|
@@ -30,11 +34,8 @@ class LRUCache[T](AbstractCache[T]):
|
|
|
30
34
|
|
|
31
35
|
return ' <-> '.join(nodes)
|
|
32
36
|
|
|
33
|
-
def __str__(self) -> str:
|
|
34
|
-
return f'{self.__class__.__name__}( capacity={self.__capacity}, map={self.__map} )'
|
|
35
|
-
|
|
36
37
|
def __getitem__(self, key: Hashable) -> T:
|
|
37
|
-
return self.get(key)
|
|
38
|
+
return self.get(key, _MISSING)
|
|
38
39
|
|
|
39
40
|
def __setitem__(self, key: Hashable, value: T) -> None:
|
|
40
41
|
self.put(key, value)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
|
|
2
|
+
from designkit.behavioral.control.promises import (
|
|
3
|
+
Pending, Resolved, Rejected,
|
|
4
|
+
Promise, Task,
|
|
5
|
+
)
|
|
6
|
+
from designkit.behavioral.control.result import (
|
|
7
|
+
Ok, Err,
|
|
8
|
+
Some, Nothing,
|
|
9
|
+
Result
|
|
10
|
+
)
|
|
11
|
+
from designkit.behavioral.control.http import (
|
|
12
|
+
Info, Success, Redirect, ClientFailure, ServerFailure,
|
|
13
|
+
HTTPResult, HTTPStatus
|
|
14
|
+
)
|
|
15
|
+
from designkit.behavioral.control.validation import (
|
|
16
|
+
Valid, Invalid,
|
|
17
|
+
Validation
|
|
18
|
+
)
|
|
19
|
+
from designkit.behavioral.control.mathematical import (
|
|
20
|
+
Left, Right, Either
|
|
21
|
+
)
|
|
@@ -36,7 +36,7 @@ class HTTPResponse[T]:
|
|
|
36
36
|
case s if 500 <= s < 600:
|
|
37
37
|
return ServerFailure(value=value, status=s)
|
|
38
38
|
case _:
|
|
39
|
-
raise ValueError(f
|
|
39
|
+
raise ValueError(f'Invalid HTTP status code: {s}')
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
|
|
@@ -51,7 +51,7 @@ class Info[T](HTTPResponse[T]):
|
|
|
51
51
|
|
|
52
52
|
def __post_init__(self) -> None:
|
|
53
53
|
if not (100 <= self.status < 200):
|
|
54
|
-
raise ValueError(
|
|
54
|
+
raise ValueError('Status code for Info must be in the range [100, 199]')
|
|
55
55
|
|
|
56
56
|
@dataclass(frozen=True)
|
|
57
57
|
class Success[T](HTTPResponse[T]):
|
|
@@ -60,7 +60,7 @@ class Success[T](HTTPResponse[T]):
|
|
|
60
60
|
|
|
61
61
|
def __post_init__(self) -> None:
|
|
62
62
|
if not (200 <= self.status < 300):
|
|
63
|
-
raise ValueError(
|
|
63
|
+
raise ValueError('Status code for Success must be in the range [200, 299]')
|
|
64
64
|
|
|
65
65
|
@dataclass(frozen=True)
|
|
66
66
|
class Redirect[T](HTTPResponse[T]):
|
|
@@ -69,7 +69,7 @@ class Redirect[T](HTTPResponse[T]):
|
|
|
69
69
|
|
|
70
70
|
def __post_init__(self) -> None:
|
|
71
71
|
if not (300 <= self.status < 400):
|
|
72
|
-
raise ValueError(
|
|
72
|
+
raise ValueError('Status code for Redirect must be in the range [300, 399]')
|
|
73
73
|
|
|
74
74
|
@dataclass(frozen=True)
|
|
75
75
|
class ClientFailure[T](HTTPResponse[T]):
|
|
@@ -78,7 +78,7 @@ class ClientFailure[T](HTTPResponse[T]):
|
|
|
78
78
|
|
|
79
79
|
def __post_init__(self) -> None:
|
|
80
80
|
if not (400 <= self.status < 500):
|
|
81
|
-
raise ValueError(
|
|
81
|
+
raise ValueError('Status code for ClientFailure must be in the range [400, 499]')
|
|
82
82
|
|
|
83
83
|
@dataclass(frozen=True)
|
|
84
84
|
class ServerFailure[T](HTTPResponse[T]):
|
|
@@ -87,7 +87,7 @@ class ServerFailure[T](HTTPResponse[T]):
|
|
|
87
87
|
|
|
88
88
|
def __post_init__(self) -> None:
|
|
89
89
|
if not (500 <= self.status < 600):
|
|
90
|
-
raise ValueError(
|
|
90
|
+
raise ValueError('Status code for ServerFailure must be in the range [500, 599]')
|
|
91
91
|
|
|
92
92
|
|
|
93
93
|
|
|
@@ -68,13 +68,13 @@ class Future[T, E]:
|
|
|
68
68
|
class Promise[T, E](Future[T, E]):
|
|
69
69
|
def resolve(self, value: T) -> None:
|
|
70
70
|
if self.settled:
|
|
71
|
-
raise RuntimeError(
|
|
71
|
+
raise RuntimeError('Cannot resolve a Promise that is already settled.')
|
|
72
72
|
|
|
73
73
|
self.state = Resolved(value)
|
|
74
74
|
|
|
75
75
|
def reject(self, error: E) -> None:
|
|
76
76
|
if self.settled:
|
|
77
|
-
raise RuntimeError(
|
|
77
|
+
raise RuntimeError('Cannot reject a Promise that is already settled.')
|
|
78
78
|
|
|
79
79
|
self.state = Rejected(error)
|
|
80
80
|
|
|
@@ -88,7 +88,7 @@ class Task[T, E](Future[T, E]):
|
|
|
88
88
|
) -> None:
|
|
89
89
|
|
|
90
90
|
if self.settled:
|
|
91
|
-
raise RuntimeError(
|
|
91
|
+
raise RuntimeError('Cannot run a Task that is already settled.')
|
|
92
92
|
|
|
93
93
|
_normalized_processes: list[ProcessAsTuple[T, Any, Any]] = []
|
|
94
94
|
for process in processes:
|
|
@@ -100,7 +100,7 @@ class Task[T, E](Future[T, E]):
|
|
|
100
100
|
elif isinstance(process, tuple) and len(process) == 3:
|
|
101
101
|
_normalized_processes.append(process)
|
|
102
102
|
else:
|
|
103
|
-
raise ValueError(
|
|
103
|
+
raise ValueError('Each process must be either a dict or a tuple of (func, args, kwargs).')
|
|
104
104
|
|
|
105
105
|
workers: int = min(workers, mp.cpu_count())
|
|
106
106
|
try:
|
|
@@ -64,21 +64,3 @@ class Invalid[T](ValidatedResponse[Never, T]):
|
|
|
64
64
|
|
|
65
65
|
type Validated[T] = Valid[T] | Invalid[T]
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
# Example Usage:
|
|
69
|
-
|
|
70
|
-
db: list[int] = [-3, 0, 5, 10, -62, 13, 2]
|
|
71
|
-
|
|
72
|
-
def are_all_positive(n: list[int]) -> bool:
|
|
73
|
-
return all(x > 0 for x in n)
|
|
74
|
-
|
|
75
|
-
def validate_db() -> Validated[list[int]]:
|
|
76
|
-
return Validation.validate(db, are_all_positive)
|
|
77
|
-
|
|
78
|
-
results: Validated[list[int]] = validate_db()
|
|
79
|
-
|
|
80
|
-
match results:
|
|
81
|
-
case Valid(value=numbers):
|
|
82
|
-
print(f"All numbers are valid: {numbers}")
|
|
83
|
-
case Invalid(value=numbers):
|
|
84
|
-
print(f"Few numbers are invalid: {numbers}")
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
|
|
2
|
+
from typing import Callable, Self
|
|
3
|
+
from enum import Enum
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class ReasonCallback[R: Enum, T]:
|
|
9
|
+
reason: R
|
|
10
|
+
callback: Callable[[T], None]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Publisher[R: Enum]:
|
|
14
|
+
def __init__(self, max_subscribers: int | None = None) -> None:
|
|
15
|
+
self.__subscribers: dict[tuple[Suscription, R], Callable] = {}
|
|
16
|
+
self.__max_subscribers = max_subscribers
|
|
17
|
+
self.__subs_count: int = 0
|
|
18
|
+
|
|
19
|
+
def __str__(self) -> str:
|
|
20
|
+
return f'{self.__class__.__name__}( subs={len(self.__subscribers)}, max_subs={self.__max_subscribers} )'
|
|
21
|
+
|
|
22
|
+
def __len__(self) -> int:
|
|
23
|
+
return self.__subs_count
|
|
24
|
+
|
|
25
|
+
def __contains__(self, subscriber: Suscription) -> bool:
|
|
26
|
+
return self.has_subscriber(subscriber)
|
|
27
|
+
|
|
28
|
+
def __getitem__(self, subscriber: Suscription) -> list[ReasonCallback[R]]:
|
|
29
|
+
return self.subscribers.get(subscriber, [])
|
|
30
|
+
|
|
31
|
+
def __setitem__(self, subscriber: Suscription, reason: R) -> None:
|
|
32
|
+
self.subscribe(subscriber, [reason])
|
|
33
|
+
|
|
34
|
+
def subscribe(self, subscriber: Suscription, reasons: list[R]) -> Self:
|
|
35
|
+
if self.__max_subscribers is not None and self.__subs_count >= self.__max_subscribers:
|
|
36
|
+
raise ValueError('Maximum number of subscribers reached')
|
|
37
|
+
|
|
38
|
+
for reason in reasons:
|
|
39
|
+
expected_callback: str = f'on_{reason.name.lower()}'
|
|
40
|
+
callback: Callable | None = getattr(subscriber, expected_callback)
|
|
41
|
+
|
|
42
|
+
if not callable(callback):
|
|
43
|
+
raise ValueError(f'Subscriber must implement a callable method named "{expected_callback}" for reason "{reason.name}"')
|
|
44
|
+
self.__subscribers[(subscriber, reason)] = callback
|
|
45
|
+
self.__subs_count += 1
|
|
46
|
+
return self
|
|
47
|
+
|
|
48
|
+
def unsubscribe(self, subscriber: Suscription) -> Self:
|
|
49
|
+
keys_to_remove = [key for key in self.__subscribers if key[0] == subscriber]
|
|
50
|
+
for key in keys_to_remove:
|
|
51
|
+
del self.__subscribers[key]
|
|
52
|
+
self.__subs_count -= 1
|
|
53
|
+
return self
|
|
54
|
+
|
|
55
|
+
def unsubscribe_for_reason(self, subscriber: Suscription, reason: R) -> Self:
|
|
56
|
+
key: tuple[Suscription, R] = (subscriber, reason)
|
|
57
|
+
if key in self.__subscribers:
|
|
58
|
+
del self.__subscribers[key]
|
|
59
|
+
self.__subs_count -= 1
|
|
60
|
+
return self
|
|
61
|
+
|
|
62
|
+
def notify[T](self, reason: R, content: T) -> Self:
|
|
63
|
+
for (subs, r), callback in self.__subscribers.items():
|
|
64
|
+
if r == reason:
|
|
65
|
+
callback(content)
|
|
66
|
+
return self
|
|
67
|
+
|
|
68
|
+
def is_subscribed(self, subscriber: Suscription, reason: R) -> bool:
|
|
69
|
+
return (subscriber, reason) in self.__subscribers
|
|
70
|
+
|
|
71
|
+
def has_subscriber(self, subscriber: Suscription) -> bool:
|
|
72
|
+
return any(subs == subscriber for (subs, _) in self.__subscribers.keys())
|
|
73
|
+
|
|
74
|
+
def has_subs_for_reason(self, reason: R) -> bool:
|
|
75
|
+
return any(r == reason for (_, r) in self.__subscribers.keys())
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def subscribers(self) -> dict[Suscription, list[ReasonCallback[R]]]:
|
|
79
|
+
result: dict[Suscription, list[ReasonCallback[R]]] = {}
|
|
80
|
+
for (subs, r), callback in self.__subscribers.items():
|
|
81
|
+
if subs not in result:
|
|
82
|
+
result[subs] = []
|
|
83
|
+
result[subs].append(ReasonCallback(reason=r, callback=callback))
|
|
84
|
+
return result
|
|
85
|
+
|
|
86
|
+
@subscribers.delete
|
|
87
|
+
def subscribers(self) -> None:
|
|
88
|
+
self.__subscribers.clear()
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def max_subscribers(self) -> int | None:
|
|
92
|
+
return self.__max_subscribers
|
|
93
|
+
|
|
94
|
+
class Suscription:
|
|
95
|
+
...
|