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.
Files changed (172) hide show
  1. {designkit-0.1.2 → designkit-0.2.0}/PKG-INFO +5 -2
  2. designkit-0.2.0/designkit/behavioral/cache/__init__.py +5 -0
  3. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/cache/core.py +4 -4
  4. designkit-0.2.0/designkit/behavioral/cache/fifo_cache.py +80 -0
  5. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/cache/lru_cache.py +5 -4
  6. designkit-0.2.0/designkit/behavioral/control/__init__.py +21 -0
  7. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/control/http.py +6 -6
  8. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/control/promises.py +4 -4
  9. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/control/validation.py +0 -18
  10. designkit-0.2.0/designkit/behavioral/pub_sub/__init__.py +4 -0
  11. designkit-0.2.0/designkit/behavioral/pub_sub/core.py +95 -0
  12. designkit-0.2.0/designkit/behavioral/typing/__init__.py +6 -0
  13. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/typing/core.py +204 -15
  14. designkit-0.2.0/designkit/behavioral/verboser/__init__.py +6 -0
  15. designkit-0.2.0/designkit/behavioral/verboser/core.py +163 -0
  16. designkit-0.2.0/designkit/creational/asymptotic/__init__.py +10 -0
  17. designkit-0.2.0/designkit/creational/asymptotic/core.py +38 -0
  18. designkit-0.2.0/designkit/creational/asymptotic/models.py +407 -0
  19. designkit-0.2.0/designkit/creational/backend/__init__.py +14 -0
  20. designkit-0.2.0/designkit/creational/backend/binjson.py +242 -0
  21. designkit-0.2.0/designkit/creational/backend/core.py +1 -0
  22. designkit-0.2.0/designkit/creational/backend/exceptions.py +21 -0
  23. designkit-0.2.0/designkit/creational/backend/json.py +240 -0
  24. designkit-0.2.0/designkit/creational/backend/utils.py +109 -0
  25. designkit-0.2.0/designkit/creational/toolbox/__init__.py +19 -0
  26. designkit-0.2.0/designkit/creational/toolbox/country/repository.py +16 -0
  27. designkit-0.2.0/designkit/creational/toolbox/currency/__init__.py +5 -0
  28. designkit-0.2.0/designkit/creational/toolbox/currency/repository.py +70 -0
  29. designkit-0.2.0/designkit/creational/toolbox/network/ip/__init__.py +5 -0
  30. designkit-0.2.0/designkit/creational/toolbox/network/ip/repository.py +72 -0
  31. designkit-0.2.0/designkit/creational/toolbox/translation/__init__.py +5 -0
  32. designkit-0.2.0/designkit/creational/toolbox/translation/repository.py +46 -0
  33. designkit-0.2.0/designkit/creational/toolbox/utils.py +144 -0
  34. {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/__init__.py +2 -0
  35. {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/card.py +2 -3
  36. designkit-0.2.0/designkit/creational/types/dtypes/coordinates.py +873 -0
  37. {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/currency.py +84 -21
  38. {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/ident.py +2 -4
  39. {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/ip.py +3 -2
  40. {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/money.py +93 -48
  41. {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/percentage.py +4 -33
  42. {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/port.py +2 -1
  43. {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/temperature.py +6 -6
  44. designkit-0.2.0/designkit/structural/environment/__init__.py +3 -0
  45. designkit-0.2.0/designkit/structural/environment/core.py +221 -0
  46. designkit-0.2.0/designkit/structural/environment/exceptions.py +12 -0
  47. designkit-0.2.0/designkit/structural/interface/__init__.py +2 -0
  48. designkit-0.2.0/designkit/structural/interface/core.py +597 -0
  49. designkit-0.2.0/designkit/structural/performance/__init__.py +25 -0
  50. designkit-0.2.0/designkit/structural/performance/core.py +398 -0
  51. {designkit-0.1.2 → designkit-0.2.0}/pyproject.toml +5 -2
  52. {designkit-0.1.2 → designkit-0.2.0}/requirements.txt +3 -0
  53. designkit-0.1.2/designkit/behavioral/cache/__init__.py +0 -3
  54. designkit-0.1.2/designkit/behavioral/control/core.py +0 -22
  55. designkit-0.1.2/designkit/behavioral/typing/__init__.py +0 -5
  56. designkit-0.1.2/designkit/creational/types/dtypes/latitude.py +0 -8
  57. designkit-0.1.2/designkit/structural/modal_driven/__init__.py +0 -19
  58. designkit-0.1.2/designkit/structural/modal_driven/core.py +0 -17
  59. designkit-0.1.2/designkit/structural/modal_driven/modals/can.py +0 -11
  60. designkit-0.1.2/designkit/structural/modal_driven/modals/could.py +0 -19
  61. designkit-0.1.2/designkit/structural/modal_driven/modals/dare.py +0 -0
  62. designkit-0.1.2/designkit/structural/modal_driven/modals/have_to.py +0 -11
  63. designkit-0.1.2/designkit/structural/modal_driven/modals/may.py +0 -11
  64. designkit-0.1.2/designkit/structural/modal_driven/modals/might.py +0 -15
  65. designkit-0.1.2/designkit/structural/modal_driven/modals/must.py +0 -11
  66. designkit-0.1.2/designkit/structural/modal_driven/modals/need_to.py +0 -11
  67. designkit-0.1.2/designkit/structural/modal_driven/modals/ought_to.py +0 -11
  68. designkit-0.1.2/designkit/structural/modal_driven/modals/shall.py +0 -11
  69. designkit-0.1.2/designkit/structural/modal_driven/modals/should.py +0 -11
  70. designkit-0.1.2/designkit/structural/modal_driven/modals/used_to.py +0 -11
  71. designkit-0.1.2/designkit/structural/modal_driven/modals/will.py +0 -11
  72. designkit-0.1.2/designkit/structural/modal_driven/modals/would.py +0 -15
  73. designkit-0.1.2/designkit/structural/modal_driven/models.py +0 -129
  74. {designkit-0.1.2 → designkit-0.2.0}/.gitattributes +0 -0
  75. {designkit-0.1.2 → designkit-0.2.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  76. {designkit-0.1.2 → designkit-0.2.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  77. {designkit-0.1.2 → designkit-0.2.0}/.github/PULL_REQUEST_TEMPLATE/new_pattern.md +0 -0
  78. {designkit-0.1.2 → designkit-0.2.0}/.github/PULL_REQUEST_TEMPLATE/pattern_maintenance.md +0 -0
  79. {designkit-0.1.2 → designkit-0.2.0}/.github/PULL_REQUEST_TEMPLATE/repo_maintenance.md +0 -0
  80. {designkit-0.1.2 → designkit-0.2.0}/.github/workflows/CI.yml +0 -0
  81. {designkit-0.1.2 → designkit-0.2.0}/.gitignore +0 -0
  82. {designkit-0.1.2 → designkit-0.2.0}/CONTRIBUTING.md +0 -0
  83. {designkit-0.1.2 → designkit-0.2.0}/Cargo.lock +0 -0
  84. {designkit-0.1.2 → designkit-0.2.0}/Cargo.toml +0 -0
  85. {designkit-0.1.2 → designkit-0.2.0}/LICENSE +0 -0
  86. {designkit-0.1.2 → designkit-0.2.0}/README.md +0 -0
  87. {designkit-0.1.2 → designkit-0.2.0}/TODO.md +0 -0
  88. {designkit-0.1.2 → designkit-0.2.0}/designkit/__init__.py +0 -0
  89. {designkit-0.1.2 → designkit-0.2.0}/designkit/_designkit.pdb +0 -0
  90. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/cache/exceptions.py +0 -0
  91. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/cache/models.py +0 -0
  92. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/chain_of_responsibility/__init__.py +0 -0
  93. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/chain_of_responsibility/core.py +0 -0
  94. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/command/__init__.py +0 -0
  95. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/command/commands.py +0 -0
  96. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/command/exceptions.py +0 -0
  97. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/command/invokers.py +0 -0
  98. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/command/models.py +0 -0
  99. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/command/receivers.py +0 -0
  100. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/command/utils.py +0 -0
  101. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/control/mathematical.py +0 -0
  102. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/control/result.py +0 -0
  103. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/imperactive/__init__.py +0 -0
  104. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/imperactive/core.py +0 -0
  105. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/imperactive/exceptions.py +0 -0
  106. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/interpreter/__init__.py +0 -0
  107. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/interpreter/builtin_exprs.py +0 -0
  108. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/interpreter/builtin_stmts.py +0 -0
  109. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/interpreter/builtin_units.py +0 -0
  110. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/interpreter/core.py +0 -0
  111. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/iterator/__init__.py +0 -0
  112. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/iterator/core.py +0 -0
  113. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/iterator/exceptions.py +0 -0
  114. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/iterator/iter_types.py +0 -0
  115. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/iterator/specialized/hashful.py +0 -0
  116. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/iterator/specialized/safeful.py +0 -0
  117. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/matcher/__init__.py +0 -0
  118. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/matcher/core.py +0 -0
  119. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/matcher/exceptions.py +0 -0
  120. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/mediator/__init__.py +0 -0
  121. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/mediator/core.py +0 -0
  122. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/memorable/__init__.py +0 -0
  123. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/memorable/core.py +0 -0
  124. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/memorable/exceptions.py +0 -0
  125. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/policy/__init__.py +0 -0
  126. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/policy/core.py +0 -0
  127. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/policy/exceptions.py +0 -0
  128. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/policy/models.py +0 -0
  129. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/state/__init__.py +0 -0
  130. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/state/core.py +0 -0
  131. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/state/exceptions.py +0 -0
  132. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/state/flowchartlib.py +0 -0
  133. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/state/fsm_types.py +0 -0
  134. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/state/renderers.py +0 -0
  135. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/state/tools.py +0 -0
  136. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/state/utils.py +0 -0
  137. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/strategy/__int__.py +0 -0
  138. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/strategy/core.py +0 -0
  139. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/strategy/exceptions.py +0 -0
  140. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/strategy/models.py +0 -0
  141. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/template/__init__.py +0 -0
  142. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/template/core.py +0 -0
  143. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/trie/__init__.py +0 -0
  144. {designkit-0.1.2 → designkit-0.2.0}/designkit/behavioral/trie/core.py +0 -0
  145. {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/prototype/__init__.py +0 -0
  146. {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/prototype/core.py +0 -0
  147. {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/singleton/__init__.py +0 -0
  148. {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/singleton/core.py +0 -0
  149. {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/singleton/exceptions.py +0 -0
  150. {designkit-0.1.2/designkit/behavioral/control → designkit-0.2.0/designkit/creational/toolbox/country}/__init__.py +0 -0
  151. {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/blob.py +0 -0
  152. {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/card_networks.py +0 -0
  153. {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/email.py +0 -0
  154. {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/hostname.py +0 -0
  155. {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/phone.py +0 -0
  156. {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/quantity.py +0 -0
  157. {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/dtypes/url.py +0 -0
  158. {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/thrird_party_dtypes.py +0 -0
  159. {designkit-0.1.2 → designkit-0.2.0}/designkit/creational/types/utils.py +0 -0
  160. {designkit-0.1.2 → designkit-0.2.0}/designkit/structural/decorador/__init__.py +0 -0
  161. {designkit-0.1.2 → designkit-0.2.0}/designkit/structural/decorador/core.py +0 -0
  162. {designkit-0.1.2 → designkit-0.2.0}/designkit/structural/decorador/utils.py +0 -0
  163. {designkit-0.1.2 → designkit-0.2.0}/designkit/structural/menu/__init__.py +0 -0
  164. {designkit-0.1.2 → designkit-0.2.0}/designkit/structural/menu/core.py +0 -0
  165. {designkit-0.1.2 → designkit-0.2.0}/rust/designkit/behavioral/interpreter/core.rs +0 -0
  166. {designkit-0.1.2 → designkit-0.2.0}/rust/designkit/behavioral/mod.rs +0 -0
  167. {designkit-0.1.2 → designkit-0.2.0}/rust/designkit/behavioral/typing/core.rs +0 -0
  168. {designkit-0.1.2 → designkit-0.2.0}/rust/designkit/behavioral/typing/mod.rs +0 -0
  169. {designkit-0.1.2 → designkit-0.2.0}/rust/designkit/creational/singleton/null +0 -0
  170. {designkit-0.1.2 → designkit-0.2.0}/rust/designkit/mod.rs +0 -0
  171. {designkit-0.1.2 → designkit-0.2.0}/rust/lib.rs +0 -0
  172. {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.1.2
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 23 GoF + 6 original design patterns, original architectural patterns, and powerful developer utilities.
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
@@ -0,0 +1,5 @@
1
+
2
+ from designkit.behavioral.cache.core import cached
3
+
4
+ from .lru_cache import LRUCache
5
+ from .fifo_cache import FIFOCache
@@ -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"Invalid HTTP status code: {s}")
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("Status code for Info must be in the range [100, 199]")
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("Status code for Success must be in the range [200, 299]")
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("Status code for Redirect must be in the range [300, 399]")
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("Status code for ClientFailure must be in the range [400, 499]")
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("Status code for ServerFailure must be in the range [500, 599]")
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("Cannot resolve a Promise that is already settled.")
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("Cannot reject a Promise that is already settled.")
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("Cannot run a Task that is already settled.")
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("Each process must be either a dict or a tuple of (func, args, kwargs).")
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,4 @@
1
+
2
+ from designkit.behavioral.pub_sub.core import Publisher, Suscription
3
+
4
+ __all__ = ['Publisher', 'Suscription']
@@ -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
+ ...
@@ -0,0 +1,6 @@
1
+
2
+ from .core import (
3
+ Assertion,
4
+ classname,
5
+ structure, attributes, methods, fields
6
+ )