frequenz-core 1.0.2__tar.gz → 1.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.
- frequenz_core-1.2.0/PKG-INFO +236 -0
- frequenz_core-1.2.0/README.md +172 -0
- frequenz_core-1.2.0/RELEASE_NOTES.md +41 -0
- {frequenz_core-1.0.2 → frequenz_core-1.2.0}/pyproject.toml +19 -19
- {frequenz_core-1.0.2 → frequenz_core-1.2.0}/src/frequenz/core/datetime.py +1 -1
- frequenz_core-1.2.0/src/frequenz/core/enum.py +265 -0
- frequenz_core-1.2.0/src/frequenz_core.egg-info/PKG-INFO +236 -0
- {frequenz_core-1.0.2 → frequenz_core-1.2.0}/src/frequenz_core.egg-info/SOURCES.txt +1 -0
- {frequenz_core-1.0.2 → frequenz_core-1.2.0}/src/frequenz_core.egg-info/requires.txt +17 -17
- frequenz_core-1.0.2/PKG-INFO +0 -91
- frequenz_core-1.0.2/README.md +0 -27
- frequenz_core-1.0.2/RELEASE_NOTES.md +0 -17
- frequenz_core-1.0.2/src/frequenz_core.egg-info/PKG-INFO +0 -91
- {frequenz_core-1.0.2 → frequenz_core-1.2.0}/LICENSE +0 -0
- {frequenz_core-1.0.2 → frequenz_core-1.2.0}/MANIFEST.in +0 -0
- {frequenz_core-1.0.2 → frequenz_core-1.2.0}/setup.cfg +0 -0
- {frequenz_core-1.0.2 → frequenz_core-1.2.0}/src/frequenz/core/__init__.py +0 -0
- {frequenz_core-1.0.2 → frequenz_core-1.2.0}/src/frequenz/core/conftest.py +0 -0
- {frequenz_core-1.0.2 → frequenz_core-1.2.0}/src/frequenz/core/id.py +0 -0
- {frequenz_core-1.0.2 → frequenz_core-1.2.0}/src/frequenz/core/math.py +0 -0
- {frequenz_core-1.0.2 → frequenz_core-1.2.0}/src/frequenz/core/module.py +0 -0
- {frequenz_core-1.0.2 → frequenz_core-1.2.0}/src/frequenz/core/py.typed +0 -0
- {frequenz_core-1.0.2 → frequenz_core-1.2.0}/src/frequenz/core/typing.py +0 -0
- {frequenz_core-1.0.2 → frequenz_core-1.2.0}/src/frequenz_core.egg-info/dependency_links.txt +0 -0
- {frequenz_core-1.0.2 → frequenz_core-1.2.0}/src/frequenz_core.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: frequenz-core
|
|
3
|
+
Version: 1.2.0
|
|
4
|
+
Summary: Core utilities to complement Python's standard library
|
|
5
|
+
Author-email: Frequenz Energy-as-a-Service GmbH <floss@frequenz.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Documentation, https://frequenz-floss.github.io/frequenz-core-python/
|
|
8
|
+
Project-URL: Changelog, https://github.com/frequenz-floss/frequenz-core-python/releases
|
|
9
|
+
Project-URL: Issues, https://github.com/frequenz-floss/frequenz-core-python/issues
|
|
10
|
+
Project-URL: Repository, https://github.com/frequenz-floss/frequenz-core-python
|
|
11
|
+
Project-URL: Support, https://github.com/frequenz-floss/frequenz-core-python/discussions/categories/support
|
|
12
|
+
Keywords: asyncio,collections,core,datetime,frequenz,lib,library,math,python,stdlib,typing
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Python: <4,>=3.11
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: typing-extensions<5,>=4.13.0
|
|
24
|
+
Provides-Extra: dev-flake8
|
|
25
|
+
Requires-Dist: flake8==7.3.0; extra == "dev-flake8"
|
|
26
|
+
Requires-Dist: flake8-docstrings==1.7.0; extra == "dev-flake8"
|
|
27
|
+
Requires-Dist: flake8-pyproject==1.2.3; extra == "dev-flake8"
|
|
28
|
+
Requires-Dist: pydoclint==0.6.11; extra == "dev-flake8"
|
|
29
|
+
Requires-Dist: pydocstyle==6.3.0; extra == "dev-flake8"
|
|
30
|
+
Provides-Extra: dev-formatting
|
|
31
|
+
Requires-Dist: black==25.1.0; extra == "dev-formatting"
|
|
32
|
+
Requires-Dist: isort==6.0.1; extra == "dev-formatting"
|
|
33
|
+
Provides-Extra: dev-mkdocs
|
|
34
|
+
Requires-Dist: Markdown==3.8.2; extra == "dev-mkdocs"
|
|
35
|
+
Requires-Dist: black==25.1.0; extra == "dev-mkdocs"
|
|
36
|
+
Requires-Dist: mike==2.1.3; extra == "dev-mkdocs"
|
|
37
|
+
Requires-Dist: mkdocs-gen-files==0.5.0; extra == "dev-mkdocs"
|
|
38
|
+
Requires-Dist: mkdocs-literate-nav==0.6.2; extra == "dev-mkdocs"
|
|
39
|
+
Requires-Dist: mkdocs-macros-plugin==1.3.9; extra == "dev-mkdocs"
|
|
40
|
+
Requires-Dist: mkdocs-material==9.6.18; extra == "dev-mkdocs"
|
|
41
|
+
Requires-Dist: mkdocstrings[python]==0.30.0; extra == "dev-mkdocs"
|
|
42
|
+
Requires-Dist: mkdocstrings-python==1.18.2; extra == "dev-mkdocs"
|
|
43
|
+
Requires-Dist: frequenz-repo-config[lib]==0.13.5; extra == "dev-mkdocs"
|
|
44
|
+
Provides-Extra: dev-mypy
|
|
45
|
+
Requires-Dist: mypy==1.17.1; extra == "dev-mypy"
|
|
46
|
+
Requires-Dist: types-Markdown==3.8.0.20250809; extra == "dev-mypy"
|
|
47
|
+
Requires-Dist: frequenz-core[dev-mkdocs,dev-noxfile,dev-pytest]; extra == "dev-mypy"
|
|
48
|
+
Provides-Extra: dev-noxfile
|
|
49
|
+
Requires-Dist: nox==2025.5.1; extra == "dev-noxfile"
|
|
50
|
+
Requires-Dist: frequenz-repo-config[lib]==0.13.5; extra == "dev-noxfile"
|
|
51
|
+
Provides-Extra: dev-pylint
|
|
52
|
+
Requires-Dist: frequenz-core[dev-mkdocs,dev-noxfile,dev-pytest]; extra == "dev-pylint"
|
|
53
|
+
Provides-Extra: dev-pytest
|
|
54
|
+
Requires-Dist: pytest==8.4.1; extra == "dev-pytest"
|
|
55
|
+
Requires-Dist: pylint==3.3.8; extra == "dev-pytest"
|
|
56
|
+
Requires-Dist: frequenz-repo-config[extra-lint-examples]==0.13.5; extra == "dev-pytest"
|
|
57
|
+
Requires-Dist: pytest-mock==3.14.1; extra == "dev-pytest"
|
|
58
|
+
Requires-Dist: pytest-asyncio==1.1.0; extra == "dev-pytest"
|
|
59
|
+
Requires-Dist: async-solipsism==0.8; extra == "dev-pytest"
|
|
60
|
+
Requires-Dist: hypothesis==6.138.11; extra == "dev-pytest"
|
|
61
|
+
Provides-Extra: dev
|
|
62
|
+
Requires-Dist: frequenz-core[dev-flake8,dev-formatting,dev-mkdocs,dev-mypy,dev-noxfile,dev-pylint,dev-pytest]; extra == "dev"
|
|
63
|
+
Dynamic: license-file
|
|
64
|
+
|
|
65
|
+
# Frequenz Core Library
|
|
66
|
+
|
|
67
|
+
[](https://github.com/frequenz-floss/frequenz-core-python/actions/workflows/ci.yaml)
|
|
68
|
+
[](https://pypi.org/project/frequenz-core/)
|
|
69
|
+
[](https://frequenz-floss.github.io/frequenz-core-python/)
|
|
70
|
+
|
|
71
|
+
## Introduction
|
|
72
|
+
|
|
73
|
+
Core utilities to complement Python's standard library. This library provides
|
|
74
|
+
essential building blocks for Python applications, including mathematical
|
|
75
|
+
utilities, datetime constants, typing helpers, strongly-typed identifiers, and
|
|
76
|
+
module introspection tools.
|
|
77
|
+
|
|
78
|
+
The `frequenz-core` library is designed to be lightweight, type-safe, and
|
|
79
|
+
follow modern Python best practices. It fills common gaps in the standard
|
|
80
|
+
library with utilities that are frequently needed across different projects.
|
|
81
|
+
|
|
82
|
+
## Supported Platforms
|
|
83
|
+
|
|
84
|
+
The following platforms are officially supported (tested):
|
|
85
|
+
|
|
86
|
+
- **Python:** 3.11
|
|
87
|
+
- **Operating System:** Ubuntu Linux 20.04
|
|
88
|
+
- **Architectures:** amd64, arm64
|
|
89
|
+
|
|
90
|
+
## Installation
|
|
91
|
+
|
|
92
|
+
You can install the library from PyPI using pip:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
python -m pip install frequenz-core
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Or add it to your project's dependencies in `pyproject.toml`:
|
|
99
|
+
|
|
100
|
+
```toml
|
|
101
|
+
[project]
|
|
102
|
+
dependencies = [
|
|
103
|
+
"frequenz-core >= 1.0.2, < 2",
|
|
104
|
+
]
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
> [!NOTE]
|
|
108
|
+
> We recommend pinning the dependency to the latest version for programs,
|
|
109
|
+
> like `"frequenz-core == 1.0.2"`, and specifying a version range spanning
|
|
110
|
+
> one major version for libraries, like `"frequenz-core >= 1.0.2, < 2"`.
|
|
111
|
+
> We follow [semver](https://semver.org/).
|
|
112
|
+
|
|
113
|
+
## Quick Start
|
|
114
|
+
|
|
115
|
+
Here's a quick overview of the main functionality:
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
from frequenz.core.math import is_close_to_zero, Interval
|
|
119
|
+
from frequenz.core.datetime import UNIX_EPOCH
|
|
120
|
+
from frequenz.core.module import get_public_module_name
|
|
121
|
+
|
|
122
|
+
# Math utilities
|
|
123
|
+
print(is_close_to_zero(1e-10)) # True - check if float is close to zero
|
|
124
|
+
interval = Interval(1, 10)
|
|
125
|
+
print(5 in interval) # True - check if value is in range
|
|
126
|
+
|
|
127
|
+
# Datetime utilities
|
|
128
|
+
print(UNIX_EPOCH) # 1970-01-01 00:00:00+00:00
|
|
129
|
+
|
|
130
|
+
# Module utilities
|
|
131
|
+
public_name = get_public_module_name("my.package._private.module")
|
|
132
|
+
print(public_name) # "my.package"
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Code Examples
|
|
136
|
+
|
|
137
|
+
### Math Utilities
|
|
138
|
+
|
|
139
|
+
The math module provides utilities for floating-point comparisons and interval
|
|
140
|
+
checking:
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
from frequenz.core.math import is_close_to_zero, Interval
|
|
144
|
+
|
|
145
|
+
# Robust floating-point zero comparison
|
|
146
|
+
assert is_close_to_zero(1e-10) # True
|
|
147
|
+
assert not is_close_to_zero(0.1) # False
|
|
148
|
+
|
|
149
|
+
# Interval checking with inclusive bounds
|
|
150
|
+
numbers = Interval(0, 100)
|
|
151
|
+
assert 50 in numbers # True
|
|
152
|
+
assert not (150 in numbers) # False - 150 is outside the interval
|
|
153
|
+
|
|
154
|
+
# Unbounded intervals
|
|
155
|
+
positive = Interval(0, None) # [0, ∞]
|
|
156
|
+
assert 1000 in positive # True
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### `Enum` with deprecated members
|
|
160
|
+
|
|
161
|
+
Define enums with deprecated members that raise deprecation warnings when
|
|
162
|
+
accessed:
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
from frequenz.core.enum import Enum, DeprecatedMember
|
|
166
|
+
|
|
167
|
+
class TaskStatus(Enum):
|
|
168
|
+
OPEN = 1
|
|
169
|
+
IN_PROGRESS = 2
|
|
170
|
+
PENDING = DeprecatedMember(1, "PENDING is deprecated, use OPEN instead")
|
|
171
|
+
DONE = DeprecatedMember(3, "DONE is deprecated, use FINISHED instead")
|
|
172
|
+
FINISHED = 4
|
|
173
|
+
|
|
174
|
+
status1 = TaskStatus.PENDING # Warns: "PENDING is deprecated, use OPEN instead"
|
|
175
|
+
assert status1 is TaskStatus.OPEN
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Typing Utilities
|
|
179
|
+
|
|
180
|
+
Disable class constructors to enforce factory pattern usage:
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
from frequenz.core.typing import disable_init
|
|
184
|
+
|
|
185
|
+
@disable_init
|
|
186
|
+
class ApiClient:
|
|
187
|
+
@classmethod
|
|
188
|
+
def create(cls, api_key: str) -> "ApiClient":
|
|
189
|
+
# Factory method with validation
|
|
190
|
+
instance = cls.__new__(cls)
|
|
191
|
+
# Custom initialization logic here
|
|
192
|
+
return instance
|
|
193
|
+
|
|
194
|
+
# This will raise TypeError:
|
|
195
|
+
# client = ApiClient() # ❌ TypeError
|
|
196
|
+
|
|
197
|
+
# Use factory method instead:
|
|
198
|
+
client = ApiClient.create("my-api-key") # ✅ Works
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Strongly-Typed IDs
|
|
202
|
+
|
|
203
|
+
Create type-safe identifiers for different entities:
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
from frequenz.core.id import BaseId
|
|
207
|
+
|
|
208
|
+
class UserId(BaseId, str_prefix="USR"):
|
|
209
|
+
pass
|
|
210
|
+
|
|
211
|
+
class OrderId(BaseId, str_prefix="ORD"):
|
|
212
|
+
pass
|
|
213
|
+
|
|
214
|
+
user_id = UserId(123)
|
|
215
|
+
order_id = OrderId(456)
|
|
216
|
+
|
|
217
|
+
print(f"User: {user_id}") # User: USR123
|
|
218
|
+
print(f"Order: {order_id}") # Order: ORD456
|
|
219
|
+
|
|
220
|
+
# Type safety prevents mixing different ID types
|
|
221
|
+
def process_user(user_id: UserId) -> None:
|
|
222
|
+
print(f"Processing user: {user_id}")
|
|
223
|
+
|
|
224
|
+
process_user(user_id) # ✅ Works
|
|
225
|
+
# process_user(order_id) # ❌ Type error
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Documentation
|
|
229
|
+
|
|
230
|
+
For information on how to use this library, please refer to the
|
|
231
|
+
[documentation](https://frequenz-floss.github.io/frequenz-core-python/).
|
|
232
|
+
|
|
233
|
+
## Contributing
|
|
234
|
+
|
|
235
|
+
If you want to know how to build this project and contribute to it, please
|
|
236
|
+
check out the [Contributing Guide](CONTRIBUTING.md).
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# Frequenz Core Library
|
|
2
|
+
|
|
3
|
+
[](https://github.com/frequenz-floss/frequenz-core-python/actions/workflows/ci.yaml)
|
|
4
|
+
[](https://pypi.org/project/frequenz-core/)
|
|
5
|
+
[](https://frequenz-floss.github.io/frequenz-core-python/)
|
|
6
|
+
|
|
7
|
+
## Introduction
|
|
8
|
+
|
|
9
|
+
Core utilities to complement Python's standard library. This library provides
|
|
10
|
+
essential building blocks for Python applications, including mathematical
|
|
11
|
+
utilities, datetime constants, typing helpers, strongly-typed identifiers, and
|
|
12
|
+
module introspection tools.
|
|
13
|
+
|
|
14
|
+
The `frequenz-core` library is designed to be lightweight, type-safe, and
|
|
15
|
+
follow modern Python best practices. It fills common gaps in the standard
|
|
16
|
+
library with utilities that are frequently needed across different projects.
|
|
17
|
+
|
|
18
|
+
## Supported Platforms
|
|
19
|
+
|
|
20
|
+
The following platforms are officially supported (tested):
|
|
21
|
+
|
|
22
|
+
- **Python:** 3.11
|
|
23
|
+
- **Operating System:** Ubuntu Linux 20.04
|
|
24
|
+
- **Architectures:** amd64, arm64
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
You can install the library from PyPI using pip:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
python -m pip install frequenz-core
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Or add it to your project's dependencies in `pyproject.toml`:
|
|
35
|
+
|
|
36
|
+
```toml
|
|
37
|
+
[project]
|
|
38
|
+
dependencies = [
|
|
39
|
+
"frequenz-core >= 1.0.2, < 2",
|
|
40
|
+
]
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
> [!NOTE]
|
|
44
|
+
> We recommend pinning the dependency to the latest version for programs,
|
|
45
|
+
> like `"frequenz-core == 1.0.2"`, and specifying a version range spanning
|
|
46
|
+
> one major version for libraries, like `"frequenz-core >= 1.0.2, < 2"`.
|
|
47
|
+
> We follow [semver](https://semver.org/).
|
|
48
|
+
|
|
49
|
+
## Quick Start
|
|
50
|
+
|
|
51
|
+
Here's a quick overview of the main functionality:
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from frequenz.core.math import is_close_to_zero, Interval
|
|
55
|
+
from frequenz.core.datetime import UNIX_EPOCH
|
|
56
|
+
from frequenz.core.module import get_public_module_name
|
|
57
|
+
|
|
58
|
+
# Math utilities
|
|
59
|
+
print(is_close_to_zero(1e-10)) # True - check if float is close to zero
|
|
60
|
+
interval = Interval(1, 10)
|
|
61
|
+
print(5 in interval) # True - check if value is in range
|
|
62
|
+
|
|
63
|
+
# Datetime utilities
|
|
64
|
+
print(UNIX_EPOCH) # 1970-01-01 00:00:00+00:00
|
|
65
|
+
|
|
66
|
+
# Module utilities
|
|
67
|
+
public_name = get_public_module_name("my.package._private.module")
|
|
68
|
+
print(public_name) # "my.package"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Code Examples
|
|
72
|
+
|
|
73
|
+
### Math Utilities
|
|
74
|
+
|
|
75
|
+
The math module provides utilities for floating-point comparisons and interval
|
|
76
|
+
checking:
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
from frequenz.core.math import is_close_to_zero, Interval
|
|
80
|
+
|
|
81
|
+
# Robust floating-point zero comparison
|
|
82
|
+
assert is_close_to_zero(1e-10) # True
|
|
83
|
+
assert not is_close_to_zero(0.1) # False
|
|
84
|
+
|
|
85
|
+
# Interval checking with inclusive bounds
|
|
86
|
+
numbers = Interval(0, 100)
|
|
87
|
+
assert 50 in numbers # True
|
|
88
|
+
assert not (150 in numbers) # False - 150 is outside the interval
|
|
89
|
+
|
|
90
|
+
# Unbounded intervals
|
|
91
|
+
positive = Interval(0, None) # [0, ∞]
|
|
92
|
+
assert 1000 in positive # True
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### `Enum` with deprecated members
|
|
96
|
+
|
|
97
|
+
Define enums with deprecated members that raise deprecation warnings when
|
|
98
|
+
accessed:
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from frequenz.core.enum import Enum, DeprecatedMember
|
|
102
|
+
|
|
103
|
+
class TaskStatus(Enum):
|
|
104
|
+
OPEN = 1
|
|
105
|
+
IN_PROGRESS = 2
|
|
106
|
+
PENDING = DeprecatedMember(1, "PENDING is deprecated, use OPEN instead")
|
|
107
|
+
DONE = DeprecatedMember(3, "DONE is deprecated, use FINISHED instead")
|
|
108
|
+
FINISHED = 4
|
|
109
|
+
|
|
110
|
+
status1 = TaskStatus.PENDING # Warns: "PENDING is deprecated, use OPEN instead"
|
|
111
|
+
assert status1 is TaskStatus.OPEN
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Typing Utilities
|
|
115
|
+
|
|
116
|
+
Disable class constructors to enforce factory pattern usage:
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
from frequenz.core.typing import disable_init
|
|
120
|
+
|
|
121
|
+
@disable_init
|
|
122
|
+
class ApiClient:
|
|
123
|
+
@classmethod
|
|
124
|
+
def create(cls, api_key: str) -> "ApiClient":
|
|
125
|
+
# Factory method with validation
|
|
126
|
+
instance = cls.__new__(cls)
|
|
127
|
+
# Custom initialization logic here
|
|
128
|
+
return instance
|
|
129
|
+
|
|
130
|
+
# This will raise TypeError:
|
|
131
|
+
# client = ApiClient() # ❌ TypeError
|
|
132
|
+
|
|
133
|
+
# Use factory method instead:
|
|
134
|
+
client = ApiClient.create("my-api-key") # ✅ Works
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Strongly-Typed IDs
|
|
138
|
+
|
|
139
|
+
Create type-safe identifiers for different entities:
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
from frequenz.core.id import BaseId
|
|
143
|
+
|
|
144
|
+
class UserId(BaseId, str_prefix="USR"):
|
|
145
|
+
pass
|
|
146
|
+
|
|
147
|
+
class OrderId(BaseId, str_prefix="ORD"):
|
|
148
|
+
pass
|
|
149
|
+
|
|
150
|
+
user_id = UserId(123)
|
|
151
|
+
order_id = OrderId(456)
|
|
152
|
+
|
|
153
|
+
print(f"User: {user_id}") # User: USR123
|
|
154
|
+
print(f"Order: {order_id}") # Order: ORD456
|
|
155
|
+
|
|
156
|
+
# Type safety prevents mixing different ID types
|
|
157
|
+
def process_user(user_id: UserId) -> None:
|
|
158
|
+
print(f"Processing user: {user_id}")
|
|
159
|
+
|
|
160
|
+
process_user(user_id) # ✅ Works
|
|
161
|
+
# process_user(order_id) # ❌ Type error
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Documentation
|
|
165
|
+
|
|
166
|
+
For information on how to use this library, please refer to the
|
|
167
|
+
[documentation](https://frequenz-floss.github.io/frequenz-core-python/).
|
|
168
|
+
|
|
169
|
+
## Contributing
|
|
170
|
+
|
|
171
|
+
If you want to know how to build this project and contribute to it, please
|
|
172
|
+
check out the [Contributing Guide](CONTRIBUTING.md).
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Frequenz Core Library Release Notes
|
|
2
|
+
|
|
3
|
+
## Summary
|
|
4
|
+
|
|
5
|
+
## New Features
|
|
6
|
+
|
|
7
|
+
* `frequenz.core.enum` now provides a `@unique` decorator that is aware of deprecations, and will only check for uniqueness among non-deprecated enum members.
|
|
8
|
+
|
|
9
|
+
For example this works:
|
|
10
|
+
|
|
11
|
+
```py
|
|
12
|
+
>>> from frequenz.core.enum import DeprecatedMember, Enum, unique
|
|
13
|
+
>>>
|
|
14
|
+
>>> @unique
|
|
15
|
+
... class Status(Enum):
|
|
16
|
+
... ACTIVE = 1
|
|
17
|
+
... INACTIVE = 2
|
|
18
|
+
... PENDING = DeprecatedMember(1, "PENDING is deprecated, use ACTIVE instead")
|
|
19
|
+
...
|
|
20
|
+
>>>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
While using the standard library's `enum.unique` decorator raises a `ValueError`:
|
|
24
|
+
|
|
25
|
+
```py
|
|
26
|
+
>>> from enum import unique
|
|
27
|
+
>>> from frequenz.core.enum import DeprecatedMember, Enum
|
|
28
|
+
>>>
|
|
29
|
+
>>> @unique
|
|
30
|
+
... class Status(Enum):
|
|
31
|
+
... ACTIVE = 1
|
|
32
|
+
... INACTIVE = 2
|
|
33
|
+
... PENDING = DeprecatedMember(1, "PENDING is deprecated, use ACTIVE instead")
|
|
34
|
+
...
|
|
35
|
+
Traceback (most recent call last):
|
|
36
|
+
File "<stdin>", line 1, in <module>
|
|
37
|
+
File "/usr/lib/python3.12/enum.py", line 1617, in unique
|
|
38
|
+
raise ValueError('duplicate values found in %r: %s' %
|
|
39
|
+
ValueError: duplicate values found in <enum 'Status'>: PENDING -> ACTIVE
|
|
40
|
+
>>>
|
|
41
|
+
```
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
[build-system]
|
|
5
5
|
requires = [
|
|
6
6
|
"setuptools == 80.9.0",
|
|
7
|
-
"setuptools_scm[toml] ==
|
|
8
|
-
"frequenz-repo-config[lib] == 0.13.
|
|
7
|
+
"setuptools_scm[toml] == 9.2.0",
|
|
8
|
+
"frequenz-repo-config[lib] == 0.13.5",
|
|
9
9
|
]
|
|
10
10
|
build-backend = "setuptools.build_meta"
|
|
11
11
|
|
|
@@ -46,45 +46,45 @@ email = "floss@frequenz.com"
|
|
|
46
46
|
|
|
47
47
|
[project.optional-dependencies]
|
|
48
48
|
dev-flake8 = [
|
|
49
|
-
"flake8 == 7.
|
|
49
|
+
"flake8 == 7.3.0",
|
|
50
50
|
"flake8-docstrings == 1.7.0",
|
|
51
51
|
"flake8-pyproject == 1.2.3", # For reading the flake8 config from pyproject.toml
|
|
52
|
-
"pydoclint == 0.6.
|
|
52
|
+
"pydoclint == 0.6.11",
|
|
53
53
|
"pydocstyle == 6.3.0",
|
|
54
54
|
]
|
|
55
55
|
dev-formatting = ["black == 25.1.0", "isort == 6.0.1"]
|
|
56
56
|
dev-mkdocs = [
|
|
57
|
-
"Markdown == 3.8",
|
|
57
|
+
"Markdown == 3.8.2",
|
|
58
58
|
"black == 25.1.0",
|
|
59
59
|
"mike == 2.1.3",
|
|
60
60
|
"mkdocs-gen-files == 0.5.0",
|
|
61
61
|
"mkdocs-literate-nav == 0.6.2",
|
|
62
|
-
"mkdocs-macros-plugin == 1.3.
|
|
63
|
-
"mkdocs-material == 9.6.
|
|
64
|
-
"mkdocstrings[python] == 0.
|
|
65
|
-
"mkdocstrings-python == 1.
|
|
66
|
-
"frequenz-repo-config[lib] == 0.13.
|
|
62
|
+
"mkdocs-macros-plugin == 1.3.9",
|
|
63
|
+
"mkdocs-material == 9.6.18",
|
|
64
|
+
"mkdocstrings[python] == 0.30.0",
|
|
65
|
+
"mkdocstrings-python == 1.18.2",
|
|
66
|
+
"frequenz-repo-config[lib] == 0.13.5",
|
|
67
67
|
]
|
|
68
68
|
dev-mypy = [
|
|
69
|
-
"mypy == 1.
|
|
70
|
-
"types-Markdown == 3.8.0.
|
|
69
|
+
"mypy == 1.17.1",
|
|
70
|
+
"types-Markdown == 3.8.0.20250809",
|
|
71
71
|
# For checking the noxfile, docs/ script, and tests
|
|
72
72
|
"frequenz-core[dev-mkdocs,dev-noxfile,dev-pytest]",
|
|
73
73
|
]
|
|
74
|
-
dev-noxfile = ["nox == 2025.5.1", "frequenz-repo-config[lib] == 0.13.
|
|
74
|
+
dev-noxfile = ["nox == 2025.5.1", "frequenz-repo-config[lib] == 0.13.5"]
|
|
75
75
|
dev-pylint = [
|
|
76
76
|
# dev-pytest already defines a dependency to pylint because of the examples
|
|
77
77
|
# For checking the noxfile, docs/ script, and tests
|
|
78
78
|
"frequenz-core[dev-mkdocs,dev-noxfile,dev-pytest]",
|
|
79
79
|
]
|
|
80
80
|
dev-pytest = [
|
|
81
|
-
"pytest == 8.
|
|
82
|
-
"pylint == 3.3.
|
|
83
|
-
"frequenz-repo-config[extra-lint-examples] == 0.13.
|
|
81
|
+
"pytest == 8.4.1",
|
|
82
|
+
"pylint == 3.3.8", # We need this to check for the examples
|
|
83
|
+
"frequenz-repo-config[extra-lint-examples] == 0.13.5",
|
|
84
84
|
"pytest-mock == 3.14.1",
|
|
85
|
-
"pytest-asyncio ==
|
|
86
|
-
"async-solipsism == 0.
|
|
87
|
-
"hypothesis == 6.
|
|
85
|
+
"pytest-asyncio == 1.1.0",
|
|
86
|
+
"async-solipsism == 0.8",
|
|
87
|
+
"hypothesis == 6.138.11",
|
|
88
88
|
]
|
|
89
89
|
dev = [
|
|
90
90
|
"frequenz-core[dev-mkdocs,dev-flake8,dev-formatting,dev-mkdocs,dev-mypy,dev-noxfile,dev-pylint,dev-pytest]",
|