haiway 0.8.2__tar.gz → 0.8.4__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 (56) hide show
  1. {haiway-0.8.2/src/haiway.egg-info → haiway-0.8.4}/PKG-INFO +4 -4
  2. {haiway-0.8.2 → haiway-0.8.4}/pyproject.toml +4 -4
  3. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/__init__.py +6 -0
  4. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/state/structure.py +2 -12
  5. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/utils/__init__.py +5 -0
  6. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/utils/env.py +69 -3
  7. haiway-0.8.4/src/haiway/utils/mappings.py +30 -0
  8. haiway-0.8.4/src/haiway/utils/sequences.py +56 -0
  9. {haiway-0.8.2 → haiway-0.8.4/src/haiway.egg-info}/PKG-INFO +4 -4
  10. {haiway-0.8.2 → haiway-0.8.4}/src/haiway.egg-info/SOURCES.txt +2 -0
  11. {haiway-0.8.2 → haiway-0.8.4}/src/haiway.egg-info/requires.txt +2 -2
  12. {haiway-0.8.2 → haiway-0.8.4}/tests/test_state.py +14 -0
  13. {haiway-0.8.2 → haiway-0.8.4}/LICENSE +0 -0
  14. {haiway-0.8.2 → haiway-0.8.4}/README.md +0 -0
  15. {haiway-0.8.2 → haiway-0.8.4}/setup.cfg +0 -0
  16. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/context/__init__.py +0 -0
  17. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/context/access.py +0 -0
  18. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/context/disposables.py +0 -0
  19. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/context/identifier.py +0 -0
  20. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/context/logging.py +0 -0
  21. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/context/metrics.py +0 -0
  22. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/context/state.py +0 -0
  23. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/context/tasks.py +0 -0
  24. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/context/types.py +0 -0
  25. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/helpers/__init__.py +0 -0
  26. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/helpers/asynchrony.py +0 -0
  27. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/helpers/caching.py +0 -0
  28. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/helpers/metrics.py +0 -0
  29. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/helpers/retries.py +0 -0
  30. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/helpers/throttling.py +0 -0
  31. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/helpers/timeouted.py +0 -0
  32. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/helpers/tracing.py +0 -0
  33. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/py.typed +0 -0
  34. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/state/__init__.py +0 -0
  35. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/state/attributes.py +0 -0
  36. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/state/path.py +0 -0
  37. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/state/requirement.py +0 -0
  38. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/state/validation.py +0 -0
  39. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/types/__init__.py +0 -0
  40. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/types/frozen.py +0 -0
  41. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/types/missing.py +0 -0
  42. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/utils/always.py +0 -0
  43. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/utils/immutable.py +0 -0
  44. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/utils/logs.py +0 -0
  45. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/utils/mimic.py +0 -0
  46. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/utils/noop.py +0 -0
  47. {haiway-0.8.2 → haiway-0.8.4}/src/haiway/utils/queue.py +0 -0
  48. {haiway-0.8.2 → haiway-0.8.4}/src/haiway.egg-info/dependency_links.txt +0 -0
  49. {haiway-0.8.2 → haiway-0.8.4}/src/haiway.egg-info/top_level.txt +0 -0
  50. {haiway-0.8.2 → haiway-0.8.4}/tests/test_async_queue.py +0 -0
  51. {haiway-0.8.2 → haiway-0.8.4}/tests/test_attribute_path.py +0 -0
  52. {haiway-0.8.2 → haiway-0.8.4}/tests/test_auto_retry.py +0 -0
  53. {haiway-0.8.2 → haiway-0.8.4}/tests/test_cache.py +0 -0
  54. {haiway-0.8.2 → haiway-0.8.4}/tests/test_context.py +0 -0
  55. {haiway-0.8.2 → haiway-0.8.4}/tests/test_streaming.py +0 -0
  56. {haiway-0.8.2 → haiway-0.8.4}/tests/test_timeout.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: haiway
3
- Version: 0.8.2
3
+ Version: 0.8.4
4
4
  Summary: Framework for dependency injection and state management within structured concurrency model.
5
5
  Maintainer-email: Kacper Kaliński <kacper.kalinski@miquido.com>
6
6
  License: MIT License
@@ -37,12 +37,12 @@ Description-Content-Type: text/markdown
37
37
  License-File: LICENSE
38
38
  Provides-Extra: dev
39
39
  Requires-Dist: haiway; extra == "dev"
40
- Requires-Dist: ruff~=0.8.0; extra == "dev"
40
+ Requires-Dist: ruff~=0.9; extra == "dev"
41
41
  Requires-Dist: pyright~=1.1; extra == "dev"
42
42
  Requires-Dist: bandit~=1.7; extra == "dev"
43
43
  Requires-Dist: pytest~=7.4; extra == "dev"
44
44
  Requires-Dist: pytest-cov~=4.1; extra == "dev"
45
- Requires-Dist: pytest-asyncio~=0.23.0; extra == "dev"
45
+ Requires-Dist: pytest-asyncio~=0.23; extra == "dev"
46
46
 
47
47
  # 🚗 haiway 🚕 🚚 🚙
48
48
 
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  name = "haiway"
7
7
  description = "Framework for dependency injection and state management within structured concurrency model."
8
- version = "0.8.2"
8
+ version = "0.8.4"
9
9
  readme = "README.md"
10
10
  maintainers = [
11
11
  { name = "Kacper Kaliński", email = "kacper.kalinski@miquido.com" },
@@ -29,12 +29,12 @@ Repository = "https://github.com/miquido/haiway.git"
29
29
  [project.optional-dependencies]
30
30
  dev = [
31
31
  "haiway",
32
- "ruff~=0.8.0",
32
+ "ruff~=0.9",
33
33
  "pyright~=1.1",
34
34
  "bandit~=1.7",
35
35
  "pytest~=7.4",
36
36
  "pytest-cov~=4.1",
37
- "pytest-asyncio~=0.23.0",
37
+ "pytest-asyncio~=0.23",
38
38
  ]
39
39
 
40
40
  [tool.ruff]
@@ -42,7 +42,7 @@ target-version = "py312"
42
42
  line-length = 100
43
43
  extend-exclude = [".venv", ".git", ".cache"]
44
44
  lint.select = ["E", "F", "A", "I", "B", "PL", "W", "C", "RUF", "UP"]
45
- lint.ignore = []
45
+ lint.ignore = ["A005"]
46
46
 
47
47
  [tool.ruff.lint.per-file-ignores]
48
48
  "__init__.py" = ["F401", "E402"]
@@ -35,6 +35,9 @@ from haiway.types import (
35
35
  from haiway.utils import (
36
36
  AsyncQueue,
37
37
  always,
38
+ as_dict,
39
+ as_list,
40
+ as_tuple,
38
41
  async_always,
39
42
  async_noop,
40
43
  freeze,
@@ -69,6 +72,9 @@ __all__ = [
69
72
  "ScopeIdentifier",
70
73
  "State",
71
74
  "always",
75
+ "as_dict",
76
+ "as_list",
77
+ "as_tuple",
72
78
  "async_always",
73
79
  "async_noop",
74
80
  "asynchronous",
@@ -1,6 +1,5 @@
1
1
  import typing
2
2
  from collections.abc import Mapping
3
- from copy import deepcopy
4
3
  from types import EllipsisType, GenericAlias
5
4
  from typing import (
6
5
  Any,
@@ -362,22 +361,13 @@ class State(metaclass=StateMeta):
362
361
  )
363
362
 
364
363
  def __copy__(self) -> Self:
365
- return self.__class__(**vars(self))
364
+ return self # State is immutable, no need to provide an actual copy
366
365
 
367
366
  def __deepcopy__(
368
367
  self,
369
368
  memo: dict[int, Any] | None,
370
369
  ) -> Self:
371
- copy: Self = self.__class__(
372
- **{
373
- key: deepcopy(
374
- value,
375
- memo,
376
- )
377
- for key, value in vars(self).items()
378
- }
379
- )
380
- return copy
370
+ return self # State is immutable, no need to provide an actual copy
381
371
 
382
372
  def __replace__(
383
373
  self,
@@ -2,13 +2,18 @@ from haiway.utils.always import always, async_always
2
2
  from haiway.utils.env import getenv_bool, getenv_float, getenv_int, getenv_str, load_env
3
3
  from haiway.utils.immutable import freeze
4
4
  from haiway.utils.logs import setup_logging
5
+ from haiway.utils.mappings import as_dict
5
6
  from haiway.utils.mimic import mimic_function
6
7
  from haiway.utils.noop import async_noop, noop
7
8
  from haiway.utils.queue import AsyncQueue
9
+ from haiway.utils.sequences import as_list, as_tuple
8
10
 
9
11
  __all__ = [
10
12
  "AsyncQueue",
11
13
  "always",
14
+ "as_dict",
15
+ "as_list",
16
+ "as_tuple",
12
17
  "async_always",
13
18
  "async_noop",
14
19
  "freeze",
@@ -1,5 +1,5 @@
1
1
  from os import environ, getenv
2
- from typing import overload
2
+ from typing import Literal, overload
3
3
 
4
4
  __all__ = [
5
5
  "getenv_bool",
@@ -25,13 +25,28 @@ def getenv_bool(
25
25
  ) -> bool: ...
26
26
 
27
27
 
28
+ @overload
29
+ def getenv_bool(
30
+ key: str,
31
+ /,
32
+ *,
33
+ required: Literal[True],
34
+ ) -> bool: ...
35
+
36
+
28
37
  def getenv_bool(
29
38
  key: str,
30
39
  /,
31
40
  default: bool | None = None,
41
+ *,
42
+ required: bool = False,
32
43
  ) -> bool | None:
33
44
  if value := getenv(key=key):
34
45
  return value.lower() in ("true", "1", "t")
46
+
47
+ elif required and default is None:
48
+ raise ValueError(f"Required environment value `{key}` is missing!")
49
+
35
50
  else:
36
51
  return default
37
52
 
@@ -51,13 +66,31 @@ def getenv_int(
51
66
  ) -> int: ...
52
67
 
53
68
 
69
+ @overload
70
+ def getenv_int(
71
+ key: str,
72
+ /,
73
+ *,
74
+ required: Literal[True],
75
+ ) -> int: ...
76
+
77
+
54
78
  def getenv_int(
55
79
  key: str,
56
80
  /,
57
81
  default: int | None = None,
82
+ *,
83
+ required: bool = False,
58
84
  ) -> int | None:
59
85
  if value := getenv(key=key):
60
- return int(value)
86
+ try:
87
+ return int(value)
88
+
89
+ except Exception as exc:
90
+ raise ValueError(f"Environment value `{key}` is not a valid int!") from exc
91
+
92
+ elif required and default is None:
93
+ raise ValueError(f"Required environment value `{key}` is missing!")
61
94
 
62
95
  else:
63
96
  return default
@@ -78,13 +111,31 @@ def getenv_float(
78
111
  ) -> float: ...
79
112
 
80
113
 
114
+ @overload
115
+ def getenv_float(
116
+ key: str,
117
+ /,
118
+ *,
119
+ required: Literal[True],
120
+ ) -> float: ...
121
+
122
+
81
123
  def getenv_float(
82
124
  key: str,
83
125
  /,
84
126
  default: float | None = None,
127
+ *,
128
+ required: bool = False,
85
129
  ) -> float | None:
86
130
  if value := getenv(key=key):
87
- return float(value)
131
+ try:
132
+ return float(value)
133
+
134
+ except Exception as exc:
135
+ raise ValueError(f"Environment value `{key}` is not a valid float!") from exc
136
+
137
+ elif required and default is None:
138
+ raise ValueError(f"Required environment value `{key}` is missing!")
88
139
 
89
140
  else:
90
141
  return default
@@ -105,13 +156,28 @@ def getenv_str(
105
156
  ) -> str: ...
106
157
 
107
158
 
159
+ @overload
160
+ def getenv_str(
161
+ key: str,
162
+ /,
163
+ *,
164
+ required: Literal[True],
165
+ ) -> str: ...
166
+
167
+
108
168
  def getenv_str(
109
169
  key: str,
110
170
  /,
111
171
  default: str | None = None,
172
+ *,
173
+ required: bool = False,
112
174
  ) -> str | None:
113
175
  if value := getenv(key=key):
114
176
  return value
177
+
178
+ elif required and default is None:
179
+ raise ValueError(f"Required environment value `{key}` is missing!")
180
+
115
181
  else:
116
182
  return default
117
183
 
@@ -0,0 +1,30 @@
1
+ from collections.abc import Mapping
2
+
3
+ __all__ = [
4
+ "as_dict",
5
+ ]
6
+
7
+
8
+ def as_dict[K, V](
9
+ mapping: Mapping[K, V],
10
+ /,
11
+ ) -> dict[K, V]:
12
+ """
13
+ Converts any given mapping into a dict.
14
+
15
+ Parameters
16
+ ----------
17
+ mapping : Mapping[K, V]
18
+ The input mapping to be converted.
19
+
20
+ Returns
21
+ -------
22
+ dict[K, V]
23
+ A new dict containing all elements of the input mapping,
24
+ or the original dict if it was already one.
25
+ """
26
+ if isinstance(mapping, dict):
27
+ return mapping
28
+
29
+ else:
30
+ return dict(mapping)
@@ -0,0 +1,56 @@
1
+ from collections.abc import Sequence
2
+
3
+ __all__ = [
4
+ "as_list",
5
+ "as_tuple",
6
+ ]
7
+
8
+
9
+ def as_list[T](
10
+ sequence: Sequence[T],
11
+ /,
12
+ ) -> list[T]:
13
+ """
14
+ Converts any given sequence into a list.
15
+
16
+ Parameters
17
+ ----------
18
+ sequence : Sequence[T]
19
+ The input sequence to be converted.
20
+
21
+ Returns
22
+ -------
23
+ list[T]
24
+ A new list containing all elements of the input sequence,
25
+ or the original list if it was already one.
26
+ """
27
+ if isinstance(sequence, list):
28
+ return sequence
29
+
30
+ else:
31
+ return list(sequence)
32
+
33
+
34
+ def as_tuple[T](
35
+ sequence: Sequence[T],
36
+ /,
37
+ ) -> tuple[T, ...]:
38
+ """
39
+ Converts any given sequence into a tuple.
40
+
41
+ Parameters
42
+ ----------
43
+ sequence : Sequence[T]
44
+ The input sequence to be converted.
45
+
46
+ Returns
47
+ -------
48
+ tuple[T]
49
+ A new tuple containing all elements of the input sequence,
50
+ or the original tuple if it was already one.
51
+ """
52
+ if isinstance(sequence, tuple):
53
+ return sequence
54
+
55
+ else:
56
+ return tuple(sequence)
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: haiway
3
- Version: 0.8.2
3
+ Version: 0.8.4
4
4
  Summary: Framework for dependency injection and state management within structured concurrency model.
5
5
  Maintainer-email: Kacper Kaliński <kacper.kalinski@miquido.com>
6
6
  License: MIT License
@@ -37,12 +37,12 @@ Description-Content-Type: text/markdown
37
37
  License-File: LICENSE
38
38
  Provides-Extra: dev
39
39
  Requires-Dist: haiway; extra == "dev"
40
- Requires-Dist: ruff~=0.8.0; extra == "dev"
40
+ Requires-Dist: ruff~=0.9; extra == "dev"
41
41
  Requires-Dist: pyright~=1.1; extra == "dev"
42
42
  Requires-Dist: bandit~=1.7; extra == "dev"
43
43
  Requires-Dist: pytest~=7.4; extra == "dev"
44
44
  Requires-Dist: pytest-cov~=4.1; extra == "dev"
45
- Requires-Dist: pytest-asyncio~=0.23.0; extra == "dev"
45
+ Requires-Dist: pytest-asyncio~=0.23; extra == "dev"
46
46
 
47
47
  # 🚗 haiway 🚕 🚚 🚙
48
48
 
@@ -39,9 +39,11 @@ src/haiway/utils/always.py
39
39
  src/haiway/utils/env.py
40
40
  src/haiway/utils/immutable.py
41
41
  src/haiway/utils/logs.py
42
+ src/haiway/utils/mappings.py
42
43
  src/haiway/utils/mimic.py
43
44
  src/haiway/utils/noop.py
44
45
  src/haiway/utils/queue.py
46
+ src/haiway/utils/sequences.py
45
47
  tests/test_async_queue.py
46
48
  tests/test_attribute_path.py
47
49
  tests/test_auto_retry.py
@@ -1,9 +1,9 @@
1
1
 
2
2
  [dev]
3
3
  haiway
4
- ruff~=0.8.0
4
+ ruff~=0.9
5
5
  pyright~=1.1
6
6
  bandit~=1.7
7
7
  pytest~=7.4
8
8
  pytest-cov~=4.1
9
- pytest-asyncio~=0.23.0
9
+ pytest-asyncio~=0.23
@@ -1,4 +1,5 @@
1
1
  from collections.abc import Callable, Sequence, Set
2
+ from copy import copy, deepcopy
2
3
  from datetime import date, datetime
3
4
  from enum import StrEnum
4
5
  from typing import Any, Literal, NotRequired, Protocol, Required, Self, TypedDict, runtime_checkable
@@ -222,3 +223,16 @@ def test_generic_subtypes_validation() -> None:
222
223
 
223
224
  # not raises
224
225
  _ = Container(generic=Generic(nested=NestedGeneric(value="ok")))
226
+
227
+
228
+ def test_copying_leaves_same_object() -> None:
229
+ class Nested(State):
230
+ string: str
231
+
232
+ class Copied(State):
233
+ string: str
234
+ nested: Nested
235
+
236
+ origin = Copied(string="42", nested=Nested(string="answer"))
237
+ assert copy(origin) is origin
238
+ assert deepcopy(origin) is origin
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes