iker-python-common 1.0.56__tar.gz → 1.0.58__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 (83) hide show
  1. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/.github/workflows/pr.yml +1 -1
  2. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/.github/workflows/push.yml +1 -1
  3. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/PKG-INFO +5 -7
  4. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/README.md +1 -1
  5. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/pyproject.toml +8 -12
  6. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/src/iker/common/utils/funcutils.py +14 -21
  7. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/src/iker/common/utils/jsonutils.py +11 -19
  8. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/src/iker/common/utils/numutils.py +10 -18
  9. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/src/iker/common/utils/randutils.py +16 -14
  10. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/src/iker/common/utils/sequtils.py +95 -105
  11. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/src/iker/common/utils/span.py +3 -6
  12. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/src/iker_python_common.egg-info/PKG-INFO +5 -7
  13. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/src/iker_python_common.egg-info/requires.txt +2 -6
  14. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/test/iker_tests/common/utils/sequtils_test.py +1 -1
  15. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/.editorconfig +0 -0
  16. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/.gitignore +0 -0
  17. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/MANIFEST.in +0 -0
  18. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/VERSION +0 -0
  19. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/resources/unittest/config/config.cfg +0 -0
  20. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/resources/unittest/csv/data.csv +0 -0
  21. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/resources/unittest/csv/data.tsv +0 -0
  22. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/resources/unittest/s3utils/dir.baz/file.bar.baz +0 -0
  23. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/resources/unittest/s3utils/dir.baz/file.foo.bar +0 -0
  24. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/resources/unittest/s3utils/dir.baz/file.foo.baz +0 -0
  25. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/resources/unittest/s3utils/dir.foo/dir.foo.bar/dir.foo.bar.baz/file.foo.bar.baz +0 -0
  26. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/resources/unittest/s3utils/dir.foo/dir.foo.bar/file.bar.baz +0 -0
  27. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/resources/unittest/s3utils/dir.foo/dir.foo.bar/file.foo.bar +0 -0
  28. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/resources/unittest/s3utils/dir.foo/dir.foo.bar/file.foo.baz +0 -0
  29. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/resources/unittest/s3utils/dir.foo/file.bar +0 -0
  30. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/resources/unittest/s3utils/dir.foo/file.baz +0 -0
  31. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/resources/unittest/s3utils/dir.foo/file.foo +0 -0
  32. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/resources/unittest/shutils/dir.baz/file.bar.baz +0 -0
  33. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/resources/unittest/shutils/dir.baz/file.foo.bar +0 -0
  34. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/resources/unittest/shutils/dir.baz/file.foo.baz +0 -0
  35. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/resources/unittest/shutils/dir.foo/dir.foo.bar/dir.foo.bar.baz/file.foo.bar.baz +0 -0
  36. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/resources/unittest/shutils/dir.foo/dir.foo.bar/file.bar.baz +0 -0
  37. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/resources/unittest/shutils/dir.foo/dir.foo.bar/file.foo.bar +0 -0
  38. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/resources/unittest/shutils/dir.foo/dir.foo.bar/file.foo.baz +0 -0
  39. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/resources/unittest/shutils/dir.foo/file.bar +0 -0
  40. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/resources/unittest/shutils/dir.foo/file.baz +0 -0
  41. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/resources/unittest/shutils/dir.foo/file.foo +0 -0
  42. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/setup.cfg +0 -0
  43. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/setup.py +0 -0
  44. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/src/iker/common/__init__.py +0 -0
  45. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/src/iker/common/utils/__init__.py +0 -0
  46. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/src/iker/common/utils/argutils.py +0 -0
  47. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/src/iker/common/utils/config.py +0 -0
  48. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/src/iker/common/utils/csv.py +0 -0
  49. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/src/iker/common/utils/dbutils.py +0 -0
  50. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/src/iker/common/utils/dockerutils.py +0 -0
  51. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/src/iker/common/utils/dtutils.py +0 -0
  52. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/src/iker/common/utils/logger.py +0 -0
  53. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/src/iker/common/utils/retry.py +0 -0
  54. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/src/iker/common/utils/s3utils.py +0 -0
  55. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/src/iker/common/utils/shutils.py +0 -0
  56. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/src/iker/common/utils/strutils.py +0 -0
  57. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/src/iker/common/utils/testutils.py +0 -0
  58. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/src/iker/common/utils/typeutils.py +0 -0
  59. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/src/iker_python_common.egg-info/SOURCES.txt +0 -0
  60. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/src/iker_python_common.egg-info/dependency_links.txt +0 -0
  61. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/src/iker_python_common.egg-info/not-zip-safe +0 -0
  62. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/src/iker_python_common.egg-info/top_level.txt +0 -0
  63. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/test/iker_test.py +0 -0
  64. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/test/iker_tests/__init__.py +0 -0
  65. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/test/iker_tests/common/utils/argutils_test.py +0 -0
  66. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/test/iker_tests/common/utils/config_test.py +0 -0
  67. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/test/iker_tests/common/utils/csv_test.py +0 -0
  68. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/test/iker_tests/common/utils/dbutils_test.py +0 -0
  69. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/test/iker_tests/common/utils/dockerutils_test.py +0 -0
  70. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/test/iker_tests/common/utils/dtutils_test.py +0 -0
  71. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/test/iker_tests/common/utils/funcutils_test.py +0 -0
  72. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/test/iker_tests/common/utils/jsonutils_test.py +0 -0
  73. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/test/iker_tests/common/utils/logger_test.py +0 -0
  74. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/test/iker_tests/common/utils/numutils_test.py +0 -0
  75. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/test/iker_tests/common/utils/randutils_test.py +0 -0
  76. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/test/iker_tests/common/utils/retry_test.py +0 -0
  77. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/test/iker_tests/common/utils/s3utils_test.py +0 -0
  78. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/test/iker_tests/common/utils/shutils_test.py +0 -0
  79. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/test/iker_tests/common/utils/span_test.py +0 -0
  80. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/test/iker_tests/common/utils/strutils_test.py +0 -0
  81. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/test/iker_tests/common/utils/testutils_test.py +0 -0
  82. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/test/iker_tests/common/utils/typeutils_test.py +0 -0
  83. {iker_python_common-1.0.56 → iker_python_common-1.0.58}/test/iker_tests/docker_fixtures.py +0 -0
@@ -15,7 +15,7 @@ jobs:
15
15
  options: --user github
16
16
  strategy:
17
17
  matrix:
18
- python-version: [ "3.11", "3.12", "3.13" ]
18
+ python-version: [ "3.12", "3.13", "3.14" ]
19
19
  steps:
20
20
  - name: Checkout
21
21
  uses: actions/checkout@v4
@@ -20,7 +20,7 @@ jobs:
20
20
  - name: Setup Python
21
21
  uses: actions/setup-python@v5
22
22
  with:
23
- python-version: "3.13"
23
+ python-version: "3.14"
24
24
 
25
25
  - name: Build and Upload
26
26
  run: |
@@ -1,18 +1,17 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iker-python-common
3
- Version: 1.0.56
3
+ Version: 1.0.58
4
4
  Classifier: Programming Language :: Python :: 3
5
- Classifier: Programming Language :: Python :: 3.11
6
5
  Classifier: Programming Language :: Python :: 3.12
7
6
  Classifier: Programming Language :: Python :: 3.13
8
- Requires-Python: <3.14,>=3.11
7
+ Classifier: Programming Language :: Python :: 3.14
8
+ Requires-Python: <3.15,>=3.12
9
9
  Requires-Dist: boto3>=1.35
10
10
  Requires-Dist: docker>=7.1
11
- Requires-Dist: numpy>=1.26
11
+ Requires-Dist: numpy>=2.3
12
12
  Requires-Dist: psycopg>=3.2
13
13
  Requires-Dist: pymysql>=1.1
14
- Requires-Dist: sqlalchemy>=1.4
15
- Requires-Dist: typing-extensions; python_version < "3.12"
14
+ Requires-Dist: sqlalchemy>=2.0
16
15
  Provides-Extra: all
17
16
  Requires-Dist: iker-python-common; extra == "all"
18
17
  Provides-Extra: test
@@ -23,4 +22,3 @@ Requires-Dist: pytest-mysql>=3.0; extra == "test"
23
22
  Requires-Dist: pytest-order>=1.3; extra == "test"
24
23
  Requires-Dist: pytest-postgresql>=6.1; extra == "test"
25
24
  Requires-Dist: pytest>=8.3; extra == "test"
26
- Requires-Dist: sqlalchemy>=2.0; extra == "test"
@@ -13,7 +13,7 @@ the [official site](https://www.anaconda.com/products/distribution)
13
13
  Create a Conda environment and install the modules and their dependencies in it
14
14
 
15
15
  ```shell
16
- conda create -n iker python=3.13
16
+ conda create -n iker python=3.14
17
17
  conda activate iker
18
18
 
19
19
  pip install .
@@ -1,7 +1,7 @@
1
1
  [build-system]
2
2
  requires = [
3
- "setuptools>=75.0",
4
- "setuptools-scm>=8.0",
3
+ "setuptools>=80.0",
4
+ "setuptools-scm>=9.0",
5
5
  "iker-python-setup>=1.0",
6
6
  ]
7
7
  build-backend = "setuptools.build_meta"
@@ -10,11 +10,10 @@ build-backend = "setuptools.build_meta"
10
10
  dev = [
11
11
  "boto3>=1.35",
12
12
  "docker>=7.1",
13
- "numpy>=1.26",
13
+ "numpy>=2.3",
14
14
  "psycopg>=3.2",
15
15
  "pymysql>=1.1",
16
- "sqlalchemy>=1.4",
17
- "typing-extensions; python_version<'3.12'"
16
+ "sqlalchemy>=2.0",
18
17
  ]
19
18
  test = [
20
19
  "ddt>=1.7",
@@ -24,27 +23,25 @@ test = [
24
23
  "pytest-order>=1.3",
25
24
  "pytest-postgresql>=6.1",
26
25
  "pytest>=8.3",
27
- "sqlalchemy>=2.0",
28
26
  ]
29
27
 
30
28
  [project]
31
29
  name = "iker-python-common"
32
30
  dynamic = ["version"]
33
- requires-python = ">=3.11,<3.14"
31
+ requires-python = ">=3.12,<3.15"
34
32
  classifiers = [
35
33
  "Programming Language :: Python :: 3",
36
- "Programming Language :: Python :: 3.11",
37
34
  "Programming Language :: Python :: 3.12",
38
35
  "Programming Language :: Python :: 3.13",
36
+ "Programming Language :: Python :: 3.14",
39
37
  ]
40
38
  dependencies = [
41
39
  "boto3>=1.35",
42
40
  "docker>=7.1",
43
- "numpy>=1.26",
41
+ "numpy>=2.3",
44
42
  "psycopg>=3.2",
45
43
  "pymysql>=1.1",
46
- "sqlalchemy>=1.4",
47
- "typing-extensions; python_version<'3.12'"
44
+ "sqlalchemy>=2.0",
48
45
  ]
49
46
 
50
47
  [project.optional-dependencies]
@@ -59,7 +56,6 @@ test = [
59
56
  "pytest-order>=1.3",
60
57
  "pytest-postgresql>=6.1",
61
58
  "pytest>=8.3",
62
- "sqlalchemy>=2.0",
63
59
  ]
64
60
 
65
61
  [tool.setuptools]
@@ -1,6 +1,6 @@
1
1
  import functools
2
2
  from collections.abc import Callable
3
- from typing import Protocol, TypeVar
3
+ from typing import Protocol
4
4
 
5
5
  __all__ = [
6
6
  "identity",
@@ -11,12 +11,8 @@ __all__ = [
11
11
  "unique_returns",
12
12
  ]
13
13
 
14
- T = TypeVar("T")
15
- U = TypeVar("U")
16
- RT = TypeVar("RT")
17
14
 
18
-
19
- def identity(instance: T) -> T:
15
+ def identity[T](instance: T) -> T:
20
16
  """
21
17
  Returns the input ``instance`` unchanged. This is a utility function often used as a default or placeholder.
22
18
 
@@ -26,22 +22,19 @@ def identity(instance: T) -> T:
26
22
  return instance
27
23
 
28
24
 
29
- class Composable(Protocol[T, RT]):
25
+ class Composable[T, R](Protocol):
30
26
  """
31
27
  Protocol for composable callables, supporting composition and chaining with other callables.
32
-
33
- :param x: The input value for the callable.
34
- :return: The result of the callable.
35
28
  """
36
29
 
37
- def __call__(self, x: T) -> RT: ...
30
+ def __call__(self, x: T) -> R: ...
38
31
 
39
- def compose(self, func: "Callable[[U], T] | Composable[U, T]") -> "Composable[U, RT]": ...
32
+ def compose[U](self, func: "Callable[[U], T] | Composable[U, T]") -> "Composable[U, R]": ...
40
33
 
41
- def and_then(self, func: "Callable[[RT], U] | Composable[RT, U]") -> "Composable[T, U]": ...
34
+ def and_then[U](self, func: "Callable[[R], U] | Composable[R, U]") -> "Composable[T, U]": ...
42
35
 
43
36
 
44
- def composable(func: Callable[[T], RT]) -> Composable[T, RT]:
37
+ def composable[T, R](func: Callable[[T], R]) -> Composable[T, R]:
45
38
  """
46
39
  Wraps a function to make it composable, allowing chaining with compose and and_then methods.
47
40
 
@@ -49,13 +42,13 @@ def composable(func: Callable[[T], RT]) -> Composable[T, RT]:
49
42
  :return: A composable version of the function.
50
43
  """
51
44
 
52
- def compose(another_func: Callable[[U], T] | Composable[U, T]) -> Composable[U, RT]:
53
- def chained(x: U) -> RT:
45
+ def compose[U](another_func: Callable[[U], T] | Composable[U, T]) -> Composable[U, R]:
46
+ def chained(x: U) -> R:
54
47
  return func(another_func(x))
55
48
 
56
49
  return composable(chained)
57
50
 
58
- def and_then(another_func: Callable[[RT], U] | Composable[RT, U]) -> Composable[T, U]:
51
+ def and_then[U](another_func: Callable[[R], U] | Composable[R, U]) -> Composable[T, U]:
59
52
  def chained(x: T) -> U:
60
53
  return another_func(func(x))
61
54
 
@@ -66,7 +59,7 @@ def composable(func: Callable[[T], RT]) -> Composable[T, RT]:
66
59
  return func
67
60
 
68
61
 
69
- def singleton(tar: Callable[..., RT] = None):
62
+ def singleton[R](tar: Callable[..., R] = None):
70
63
  """
71
64
  Decorator to ensure a function or class is only instantiated once. Subsequent calls return the same instance.
72
65
 
@@ -91,7 +84,7 @@ def singleton(tar: Callable[..., RT] = None):
91
84
  return decorator if tar is None else decorator(tar)
92
85
 
93
86
 
94
- def memorized(tar: Callable[..., RT] = None, *, ordered: bool = False, typed: bool = False):
87
+ def memorized[R](tar: Callable[..., R] = None, *, ordered: bool = False, typed: bool = False):
95
88
  """
96
89
  Decorator to cache the results of a function based on its arguments. Supports options for argument order and type.
97
90
 
@@ -134,7 +127,7 @@ def memorized(tar: Callable[..., RT] = None, *, ordered: bool = False, typed: bo
134
127
  return decorator if tar is None else decorator(tar)
135
128
 
136
129
 
137
- def lazy(tar: Callable[..., RT] = None):
130
+ def lazy[R](tar: Callable[..., R] = None):
138
131
  """
139
132
  Decorator to defer the execution of a function until its result is explicitly requested.
140
133
 
@@ -155,7 +148,7 @@ def lazy(tar: Callable[..., RT] = None):
155
148
  return decorator if tar is None else decorator(tar)
156
149
 
157
150
 
158
- def unique_returns(tar: Callable[..., RT] = None, *, max_trials: int | None = None):
151
+ def unique_returns[R](tar: Callable[..., R] = None, *, max_trials: int | None = None):
159
152
  """
160
153
  Decorator to ensure a function produces unique return values. If no unique value is found within max_trials,
161
154
  raises an error.
@@ -1,12 +1,6 @@
1
1
  import math
2
- import sys
3
2
  from collections.abc import Callable, Mapping, MutableMapping, MutableSequence, Sequence, Set
4
- from typing import Any, SupportsFloat, SupportsInt, TypeAlias
5
-
6
- if sys.version_info < (3, 12):
7
- from typing_extensions import TypeAliasType
8
- else:
9
- from typing import TypeAliasType
3
+ from typing import Any, SupportsFloat, SupportsInt
10
4
 
11
5
  from iker.common.utils.numutils import is_normal_real
12
6
 
@@ -35,28 +29,26 @@ __all__ = [
35
29
 
36
30
  JsonKey = str
37
31
  JsonValue = str | bool | float | int | None
38
- JsonObject: TypeAlias = TypeAliasType("JsonObject", "dict[JsonKey, JsonType]")
39
- JsonArray: TypeAlias = TypeAliasType("JsonArray", "list[JsonType]")
40
- JsonType: TypeAlias = TypeAliasType("JsonType", "JsonValue | JsonObject | JsonArray")
32
+ type JsonObject = dict[JsonKey, JsonType]
33
+ type JsonArray = list[JsonType]
34
+ type JsonType = JsonValue | JsonObject | JsonArray
35
+
41
36
  JsonKeyCompatible = str
42
37
  JsonValueCompatible = str | bool | SupportsFloat | SupportsInt | None
43
- JsonObjectCompatible: TypeAlias = TypeAliasType("JsonObjectCompatible",
44
- "Mapping[JsonKeyCompatible, JsonTypeCompatible]")
45
- JsonArrayCompatible: TypeAlias = TypeAliasType("JsonArrayCompatible",
46
- "Sequence[JsonTypeCompatible]")
47
- JsonTypeCompatible: TypeAlias = TypeAliasType("JsonTypeCompatible",
48
- "JsonValueCompatible | JsonObjectCompatible | JsonArrayCompatible")
38
+ type JsonObjectCompatible = Mapping[JsonKeyCompatible, JsonTypeCompatible]
39
+ type JsonArrayCompatible = Sequence[JsonTypeCompatible]
40
+ type JsonTypeCompatible = JsonValueCompatible | JsonObjectCompatible | JsonArrayCompatible
49
41
 
50
42
 
51
43
  class NodeAsterisk(object):
52
44
  pass
53
45
 
54
46
 
55
- Node = str | int | NodeAsterisk
56
- NodePath: TypeAlias = TypeAliasType("NodePath", "list[Node]")
57
-
58
47
  asterisk = NodeAsterisk()
59
48
 
49
+ Node = str | int | NodeAsterisk
50
+ type NodePath = list[Node]
51
+
60
52
 
61
53
  def json_get(
62
54
  obj: JsonTypeCompatible,
@@ -2,7 +2,7 @@ import math
2
2
  from collections.abc import Callable, Sequence
3
3
  from decimal import Decimal
4
4
  from numbers import Real
5
- from typing import Any, TypeVar
5
+ from typing import Any
6
6
 
7
7
  import numpy as np
8
8
 
@@ -26,8 +26,6 @@ __all__ = [
26
26
  "real_nan_std",
27
27
  ]
28
28
 
29
- RealT = TypeVar("RealT", bound=Real)
30
-
31
29
 
32
30
  def to_decimal(x: float | str | None) -> Decimal | None:
33
31
  """
@@ -72,10 +70,7 @@ def is_normal_real(v: Any) -> bool:
72
70
  return is_real(v) and not math.isnan(v) and not math.isinf(v)
73
71
 
74
72
 
75
- def make_real_unary(
76
- op: Callable[[RealT], RealT],
77
- fb: RealT | None = None,
78
- ) -> Callable[[RealT], RealT | None]:
73
+ def make_real_unary[T: Real](op: Callable[[T], T], fb: T | None = None) -> Callable[[T], T | None]:
79
74
  """
80
75
  Creates a unary function that applies the given operation to a real number, returning a fallback if not real.
81
76
 
@@ -84,7 +79,7 @@ def make_real_unary(
84
79
  :return: A function that applies ``op`` to a real number or returns ``fb``.
85
80
  """
86
81
 
87
- def func(x: RealT) -> RealT | None:
82
+ def func(x: T) -> T | None:
88
83
  if not is_real(x):
89
84
  return fb
90
85
  return op(x)
@@ -92,10 +87,7 @@ def make_real_unary(
92
87
  return func
93
88
 
94
89
 
95
- def make_real_binary(
96
- op: Callable[[RealT, RealT], RealT],
97
- fb: RealT | None = None,
98
- ) -> Callable[[RealT, RealT], RealT | None]:
90
+ def make_real_binary[T: Real](op: Callable[[T, T], T], fb: T | None = None) -> Callable[[T, T], T | None]:
99
91
  """
100
92
  Creates a binary function that applies the given operation to two real numbers, with fallback logic.
101
93
 
@@ -104,7 +96,7 @@ def make_real_binary(
104
96
  :return: A function that applies ``op`` to two real numbers or returns ``fb``.
105
97
  """
106
98
 
107
- def func(a: RealT, b: RealT) -> RealT | None:
99
+ def func(a: T, b: T) -> T | None:
108
100
  if not is_real(a) and not is_real(b):
109
101
  return fb
110
102
  if not is_real(a):
@@ -116,10 +108,10 @@ def make_real_binary(
116
108
  return func
117
109
 
118
110
 
119
- def make_real_reducer(
120
- op: Callable[[Sequence[RealT], ...], RealT],
121
- fb: RealT | None = None,
122
- ) -> Callable[[Sequence[RealT], ...], RealT | None]:
111
+ def make_real_reducer[T: Real](
112
+ op: Callable[[Sequence[T], ...], T],
113
+ fb: T | None = None,
114
+ ) -> Callable[[Sequence[T], ...], T | None]:
123
115
  """
124
116
  Creates a reducer function that applies the given operation to a sequence of real numbers, filtering out non-reals.
125
117
 
@@ -128,7 +120,7 @@ def make_real_reducer(
128
120
  :return: A function that reduces a sequence of real numbers or returns ``fb``.
129
121
  """
130
122
 
131
- def func(xs: Sequence[RealT], *args, **kwargs) -> RealT | None:
123
+ def func(xs: Sequence[T], *args, **kwargs) -> T | None:
132
124
  xs_new = list(filter(is_real, xs))
133
125
  return op(xs_new, *args, **kwargs) if len(xs_new) > 0 else fb
134
126
 
@@ -4,7 +4,6 @@ import random
4
4
  import string
5
5
  import sys
6
6
  from collections.abc import Callable, Sequence
7
- from typing import TypeVar
8
7
  from typing import overload
9
8
 
10
9
  from iker.common.utils.dtutils import dt_utc_max, dt_utc_min
@@ -19,8 +18,6 @@ __all__ = [
19
18
  "randomizer",
20
19
  ]
21
20
 
22
- T = TypeVar("T")
23
-
24
21
 
25
22
  @singleton
26
23
  def max_int() -> int:
@@ -268,22 +265,22 @@ class Randomizer(object):
268
265
  return generate_json_object(0)
269
266
 
270
267
  @overload
271
- def sample(self, population: Sequence[T], count_func: Callable[[T], int], k: int) -> list[T]:
268
+ def sample[T](self, population: Sequence[T], count_func: Callable[[T], int], k: int) -> list[T]:
272
269
  ...
273
270
 
274
271
  @overload
275
- def sample(self, population: Sequence[T], k: int) -> list[T]:
272
+ def sample[T](self, population: Sequence[T], k: int) -> list[T]:
276
273
  ...
277
274
 
278
275
  @overload
279
- def sample(self, population: Sequence[T], count_func: Callable[[T], int], k: None = None) -> T:
276
+ def sample[T](self, population: Sequence[T], count_func: Callable[[T], int], k: None = None) -> T:
280
277
  ...
281
278
 
282
279
  @overload
283
- def sample(self, population: Sequence[T], k: None = None) -> T:
280
+ def sample[T](self, population: Sequence[T], k: None = None) -> T:
284
281
  ...
285
282
 
286
- def sample(self, population: Sequence[T], count_func: Callable[[T], int] = None, k: int = None) -> list[T] | T:
283
+ def sample[T](self, population: Sequence[T], count_func: Callable[[T], int] = None, k: int = None) -> list[T] | T:
287
284
  """
288
285
  Returns a random sample from the population, optionally weighted by a count function.
289
286
 
@@ -297,22 +294,27 @@ class Randomizer(object):
297
294
  return result if k is not None else head_or_none(result)
298
295
 
299
296
  @overload
300
- def choose(self, population: Sequence[T], weight_func: Callable[[T], float], k: int) -> list[T]:
297
+ def choose[T](self, population: Sequence[T], weight_func: Callable[[T], float], k: int) -> list[T]:
301
298
  ...
302
299
 
303
300
  @overload
304
- def choose(self, population: Sequence[T], k: int) -> list[T]:
301
+ def choose[T](self, population: Sequence[T], k: int) -> list[T]:
305
302
  ...
306
303
 
307
304
  @overload
308
- def choose(self, population: Sequence[T], weight_func: Callable[[T], float], k: None = None) -> T:
305
+ def choose[T](self, population: Sequence[T], weight_func: Callable[[T], float], k: None = None) -> T:
309
306
  ...
310
307
 
311
308
  @overload
312
- def choose(self, population: Sequence[T], k: None = None) -> T:
309
+ def choose[T](self, population: Sequence[T], k: None = None) -> T:
313
310
  ...
314
311
 
315
- def choose(self, population: Sequence[T], weight_func: Callable[[T], float] = None, k: int = None) -> list[T] | T:
312
+ def choose[T](
313
+ self,
314
+ population: Sequence[T],
315
+ weight_func: Callable[[T], float] = None,
316
+ k: int = None,
317
+ ) -> list[T] | T:
316
318
  """
317
319
  Returns a random selection from the population, optionally weighted by a weight function.
318
320
 
@@ -325,7 +327,7 @@ class Randomizer(object):
325
327
  result = self.random.choices(population, weights=weights, k=k or 1)
326
328
  return result if k is not None else head_or_none(result)
327
329
 
328
- def shuffle(self, data: Sequence[T]) -> list[T]:
330
+ def shuffle[T](self, data: Sequence[T]) -> list[T]:
329
331
  """
330
332
  Returns a shuffled copy of the input ``data`` sequence.
331
333