frequenz-client-assets 0.0.2__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_client_assets-0.0.2/LICENSE +21 -0
- frequenz_client_assets-0.0.2/MANIFEST.in +13 -0
- frequenz_client_assets-0.0.2/PKG-INFO +94 -0
- frequenz_client_assets-0.0.2/README.md +22 -0
- frequenz_client_assets-0.0.2/RELEASE_NOTES.md +32 -0
- frequenz_client_assets-0.0.2/pyproject.toml +199 -0
- frequenz_client_assets-0.0.2/setup.cfg +4 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/__init__.py +18 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/_client.py +140 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/_delivery_area.py +89 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/_delivery_area_proto.py +44 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/_lifetime.py +54 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/_lifetime_proto.py +26 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/_location.py +31 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/_location_proto.py +47 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/_microgrid.py +87 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/_microgrid_json.py +15 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/_microgrid_proto.py +79 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/_utils.py +63 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/cli/__init__.py +1 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/cli/__main__.py +219 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/cli/_utils.py +44 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/conftest.py +13 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/electrical_component/__init__.py +90 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/electrical_component/_battery.py +133 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/electrical_component/_breaker.py +20 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/electrical_component/_capacitor_bank.py +20 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/electrical_component/_category.py +88 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/electrical_component/_chp.py +18 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/electrical_component/_converter.py +20 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/electrical_component/_crypto_miner.py +20 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/electrical_component/_electrical_component.py +78 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/electrical_component/_electrical_component_json.py +21 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/electrical_component/_electrical_component_proto.py +507 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/electrical_component/_electrolyzer.py +20 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/electrical_component/_ev_charger.py +157 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/electrical_component/_grid_connection_point.py +61 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/electrical_component/_hvac.py +20 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/electrical_component/_inverter.py +157 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/electrical_component/_meter.py +20 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/electrical_component/_plc.py +18 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/electrical_component/_power_transformer.py +32 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/electrical_component/_precharger.py +20 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/electrical_component/_problematic.py +52 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/electrical_component/_static_transfer_switch.py +20 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/electrical_component/_types.py +73 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/electrical_component/_uninterruptible_power_supply.py +20 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/electrical_component/_wind_turbine.py +20 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/exceptions.py +51 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/metrics/__init__.py +12 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/metrics/_bounds.py +44 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/metrics/_bounds_proto.py +17 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/metrics/_metric.py +261 -0
- frequenz_client_assets-0.0.2/src/frequenz/client/assets/py.typed +0 -0
- frequenz_client_assets-0.0.2/src/frequenz_client_assets.egg-info/PKG-INFO +94 -0
- frequenz_client_assets-0.0.2/src/frequenz_client_assets.egg-info/SOURCES.txt +58 -0
- frequenz_client_assets-0.0.2/src/frequenz_client_assets.egg-info/dependency_links.txt +1 -0
- frequenz_client_assets-0.0.2/src/frequenz_client_assets.egg-info/entry_points.txt +2 -0
- frequenz_client_assets-0.0.2/src/frequenz_client_assets.egg-info/requires.txt +57 -0
- frequenz_client_assets-0.0.2/src/frequenz_client_assets.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright © 2025 Frequenz Energy-as-a-Service GmbH
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
exclude .cookiecutter-replay.json
|
|
2
|
+
exclude .editorconfig
|
|
3
|
+
exclude .gitignore
|
|
4
|
+
exclude CODEOWNERS
|
|
5
|
+
exclude CONTRIBUTING.md
|
|
6
|
+
exclude mkdocs.yml
|
|
7
|
+
exclude noxfile.py
|
|
8
|
+
exclude src/conftest.py
|
|
9
|
+
recursive-exclude .github *
|
|
10
|
+
recursive-exclude benchmarks *
|
|
11
|
+
recursive-exclude docs *
|
|
12
|
+
recursive-exclude tests *
|
|
13
|
+
recursive-include py *.pyi
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: frequenz-client-assets
|
|
3
|
+
Version: 0.0.2
|
|
4
|
+
Summary: Assets API client for Python
|
|
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-client-assets-python/
|
|
8
|
+
Project-URL: Changelog, https://github.com/frequenz-floss/frequenz-client-assets-python/releases
|
|
9
|
+
Project-URL: Issues, https://github.com/frequenz-floss/frequenz-client-assets-python/issues
|
|
10
|
+
Project-URL: Repository, https://github.com/frequenz-floss/frequenz-client-assets-python
|
|
11
|
+
Project-URL: Support, https://github.com/frequenz-floss/frequenz-client-assets-python/discussions/categories/support
|
|
12
|
+
Keywords: frequenz,python,lib,library,frequenz-client-assets,client-assets,client,assets,api
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
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
|
+
Requires-Dist: frequenz-api-assets<0.2.0,>=0.1.0
|
|
25
|
+
Requires-Dist: frequenz-api-common<1,>=0.8.0
|
|
26
|
+
Requires-Dist: frequenz-client-base<0.12.0,>=0.11.0
|
|
27
|
+
Requires-Dist: frequenz-client-common<0.4.0,>=0.3.6
|
|
28
|
+
Requires-Dist: grpcio<2,>=1.73.1
|
|
29
|
+
Provides-Extra: cli
|
|
30
|
+
Requires-Dist: asyncclick==8.3.0.4; extra == "cli"
|
|
31
|
+
Provides-Extra: dev-flake8
|
|
32
|
+
Requires-Dist: flake8==7.3.0; extra == "dev-flake8"
|
|
33
|
+
Requires-Dist: flake8-docstrings==1.7.0; extra == "dev-flake8"
|
|
34
|
+
Requires-Dist: flake8-pyproject==1.2.3; extra == "dev-flake8"
|
|
35
|
+
Requires-Dist: pydoclint==0.6.10; extra == "dev-flake8"
|
|
36
|
+
Requires-Dist: pydocstyle==6.3.0; extra == "dev-flake8"
|
|
37
|
+
Provides-Extra: dev-formatting
|
|
38
|
+
Requires-Dist: black==25.9.0; extra == "dev-formatting"
|
|
39
|
+
Requires-Dist: isort==6.1.0; extra == "dev-formatting"
|
|
40
|
+
Provides-Extra: dev-mkdocs
|
|
41
|
+
Requires-Dist: Markdown==3.9; extra == "dev-mkdocs"
|
|
42
|
+
Requires-Dist: black==25.9.0; extra == "dev-mkdocs"
|
|
43
|
+
Requires-Dist: mike==2.1.3; extra == "dev-mkdocs"
|
|
44
|
+
Requires-Dist: mkdocs-gen-files==0.5.0; extra == "dev-mkdocs"
|
|
45
|
+
Requires-Dist: mkdocs-literate-nav==0.6.2; extra == "dev-mkdocs"
|
|
46
|
+
Requires-Dist: mkdocs-macros-plugin==1.4.0; extra == "dev-mkdocs"
|
|
47
|
+
Requires-Dist: mkdocs-material==9.6.17; extra == "dev-mkdocs"
|
|
48
|
+
Requires-Dist: mkdocstrings[python]==0.30.0; extra == "dev-mkdocs"
|
|
49
|
+
Requires-Dist: mkdocstrings-python==1.18.2; extra == "dev-mkdocs"
|
|
50
|
+
Requires-Dist: frequenz-repo-config[lib]==0.13.5; extra == "dev-mkdocs"
|
|
51
|
+
Provides-Extra: dev-mypy
|
|
52
|
+
Requires-Dist: mypy==1.18.2; extra == "dev-mypy"
|
|
53
|
+
Requires-Dist: grpc-stubs==1.53.0.6; extra == "dev-mypy"
|
|
54
|
+
Requires-Dist: types-Markdown==3.9.0.20250906; extra == "dev-mypy"
|
|
55
|
+
Requires-Dist: types-protobuf==6.32.1.20250918; extra == "dev-mypy"
|
|
56
|
+
Requires-Dist: frequenz-client-assets[cli,dev-mkdocs,dev-noxfile,dev-pytest]; extra == "dev-mypy"
|
|
57
|
+
Provides-Extra: dev-noxfile
|
|
58
|
+
Requires-Dist: nox==2025.5.1; extra == "dev-noxfile"
|
|
59
|
+
Requires-Dist: frequenz-repo-config[lib]==0.13.5; extra == "dev-noxfile"
|
|
60
|
+
Provides-Extra: dev-pylint
|
|
61
|
+
Requires-Dist: frequenz-client-assets[cli,dev-mkdocs,dev-noxfile,dev-pytest]; extra == "dev-pylint"
|
|
62
|
+
Provides-Extra: dev-pytest
|
|
63
|
+
Requires-Dist: pytest==8.4.1; extra == "dev-pytest"
|
|
64
|
+
Requires-Dist: pylint==3.3.8; extra == "dev-pytest"
|
|
65
|
+
Requires-Dist: frequenz-repo-config[extra-lint-examples]==0.13.5; extra == "dev-pytest"
|
|
66
|
+
Requires-Dist: pytest-mock==3.15.1; extra == "dev-pytest"
|
|
67
|
+
Requires-Dist: pytest-asyncio==1.1.0; extra == "dev-pytest"
|
|
68
|
+
Requires-Dist: async-solipsism==0.8; extra == "dev-pytest"
|
|
69
|
+
Provides-Extra: dev
|
|
70
|
+
Requires-Dist: frequenz-client-assets[dev-flake8,dev-formatting,dev-mkdocs,dev-mypy,dev-noxfile,dev-pylint,dev-pytest]; extra == "dev"
|
|
71
|
+
Dynamic: license-file
|
|
72
|
+
|
|
73
|
+
# Frequenz Assets API Client
|
|
74
|
+
|
|
75
|
+
[](https://github.com/frequenz-floss/frequenz-client-assets-python/actions/workflows/ci.yaml)
|
|
76
|
+
[](https://pypi.org/project/frequenz-client-assets/)
|
|
77
|
+
[](https://frequenz-floss.github.io/frequenz-client-assets-python/)
|
|
78
|
+
|
|
79
|
+
## Introduction
|
|
80
|
+
|
|
81
|
+
Assets API client for Python
|
|
82
|
+
|
|
83
|
+
## Supported Platforms
|
|
84
|
+
|
|
85
|
+
The following platforms are officially supported (tested):
|
|
86
|
+
|
|
87
|
+
- **Python:** 3.11
|
|
88
|
+
- **Operating System:** Ubuntu Linux 20.04
|
|
89
|
+
- **Architectures:** amd64, arm64
|
|
90
|
+
|
|
91
|
+
## Contributing
|
|
92
|
+
|
|
93
|
+
If you want to know how to build this project and contribute to it, please
|
|
94
|
+
check out the [Contributing Guide](CONTRIBUTING.md).
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Frequenz Assets API Client
|
|
2
|
+
|
|
3
|
+
[](https://github.com/frequenz-floss/frequenz-client-assets-python/actions/workflows/ci.yaml)
|
|
4
|
+
[](https://pypi.org/project/frequenz-client-assets/)
|
|
5
|
+
[](https://frequenz-floss.github.io/frequenz-client-assets-python/)
|
|
6
|
+
|
|
7
|
+
## Introduction
|
|
8
|
+
|
|
9
|
+
Assets API client for Python
|
|
10
|
+
|
|
11
|
+
## Supported Platforms
|
|
12
|
+
|
|
13
|
+
The following platforms are officially supported (tested):
|
|
14
|
+
|
|
15
|
+
- **Python:** 3.11
|
|
16
|
+
- **Operating System:** Ubuntu Linux 20.04
|
|
17
|
+
- **Architectures:** amd64, arm64
|
|
18
|
+
|
|
19
|
+
## Contributing
|
|
20
|
+
|
|
21
|
+
If you want to know how to build this project and contribute to it, please
|
|
22
|
+
check out the [Contributing Guide](CONTRIBUTING.md).
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Frequenz Assets API Client Release Notes
|
|
2
|
+
|
|
3
|
+
## Summary
|
|
4
|
+
|
|
5
|
+
This release updates the `frequenz-api-assets` dependency to use a version range instead of a specific Git reference, providing more flexibility for dependency updates while maintaining compatibility.
|
|
6
|
+
|
|
7
|
+
## Changes
|
|
8
|
+
|
|
9
|
+
### Dependency Updates
|
|
10
|
+
|
|
11
|
+
* **Updated `frequenz-api-assets` dependency**:
|
|
12
|
+
* Changed from Git reference (`@ git+https://github.com/frequenz-floss/frequenz-api-assets.git@v0.x.x`) to version range (`>= 0.1.0, < 0.2.0`)
|
|
13
|
+
* Enables automatic updates within the specified version range
|
|
14
|
+
* Maintains backward compatibility while reducing maintenance overhead
|
|
15
|
+
|
|
16
|
+
## Benefits
|
|
17
|
+
|
|
18
|
+
* **Improved dependency management**: Version ranges allow for automatic updates within the specified range
|
|
19
|
+
* **Better compatibility**: Ensures compatibility with the project while allowing for patch and minor version updates
|
|
20
|
+
* **Reduced maintenance overhead**: Eliminates the need to manually update Git references for compatible versions
|
|
21
|
+
|
|
22
|
+
## Migration Notes
|
|
23
|
+
|
|
24
|
+
No migration required. This is a transparent dependency update that maintains full backward compatibility.
|
|
25
|
+
|
|
26
|
+
## Files Changed
|
|
27
|
+
|
|
28
|
+
* `pyproject.toml`: Updated the `frequenz-api-assets` dependency specification
|
|
29
|
+
|
|
30
|
+
## Type of Change
|
|
31
|
+
|
|
32
|
+
* [x] Dependency update
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# License: MIT
|
|
2
|
+
# Copyright © 2025 Frequenz Energy-as-a-Service GmbH
|
|
3
|
+
|
|
4
|
+
[build-system]
|
|
5
|
+
requires = [
|
|
6
|
+
"setuptools == 80.9.0",
|
|
7
|
+
"setuptools_scm[toml] == 9.2.0",
|
|
8
|
+
"frequenz-repo-config[lib] == 0.13.5",
|
|
9
|
+
]
|
|
10
|
+
build-backend = "setuptools.build_meta"
|
|
11
|
+
|
|
12
|
+
[project]
|
|
13
|
+
name = "frequenz-client-assets"
|
|
14
|
+
description = "Assets API client for Python"
|
|
15
|
+
readme = "README.md"
|
|
16
|
+
license = { text = "MIT" }
|
|
17
|
+
keywords = [
|
|
18
|
+
"frequenz",
|
|
19
|
+
"python",
|
|
20
|
+
"lib",
|
|
21
|
+
"library",
|
|
22
|
+
"frequenz-client-assets",
|
|
23
|
+
"client-assets",
|
|
24
|
+
"client",
|
|
25
|
+
"assets",
|
|
26
|
+
"api",
|
|
27
|
+
]
|
|
28
|
+
classifiers = [
|
|
29
|
+
"Development Status :: 3 - Alpha",
|
|
30
|
+
"Intended Audience :: Developers",
|
|
31
|
+
"License :: OSI Approved :: MIT License",
|
|
32
|
+
"Programming Language :: Python :: 3",
|
|
33
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
34
|
+
"Topic :: Software Development :: Libraries",
|
|
35
|
+
"Typing :: Typed",
|
|
36
|
+
]
|
|
37
|
+
requires-python = ">= 3.11, < 4"
|
|
38
|
+
dependencies = [
|
|
39
|
+
"typing-extensions >= 4.13.0, < 5",
|
|
40
|
+
"frequenz-api-assets >= 0.1.0, < 0.2.0",
|
|
41
|
+
"frequenz-api-common >= 0.8.0, < 1",
|
|
42
|
+
"frequenz-client-base >= 0.11.0, < 0.12.0",
|
|
43
|
+
"frequenz-client-common >= 0.3.6, < 0.4.0",
|
|
44
|
+
"grpcio >= 1.73.1, < 2",
|
|
45
|
+
]
|
|
46
|
+
dynamic = ["version"]
|
|
47
|
+
|
|
48
|
+
[project.scripts]
|
|
49
|
+
assets-cli = "frequenz.client.assets.cli.__main__:main"
|
|
50
|
+
|
|
51
|
+
[[project.authors]]
|
|
52
|
+
name = "Frequenz Energy-as-a-Service GmbH"
|
|
53
|
+
email = "floss@frequenz.com"
|
|
54
|
+
|
|
55
|
+
[project.optional-dependencies]
|
|
56
|
+
cli = ["asyncclick == 8.3.0.4"]
|
|
57
|
+
dev-flake8 = [
|
|
58
|
+
"flake8 == 7.3.0",
|
|
59
|
+
"flake8-docstrings == 1.7.0",
|
|
60
|
+
"flake8-pyproject == 1.2.3", # For reading the flake8 config from pyproject.toml
|
|
61
|
+
"pydoclint == 0.6.10",
|
|
62
|
+
"pydocstyle == 6.3.0",
|
|
63
|
+
]
|
|
64
|
+
dev-formatting = ["black == 25.9.0", "isort == 6.1.0"]
|
|
65
|
+
dev-mkdocs = [
|
|
66
|
+
"Markdown == 3.9",
|
|
67
|
+
"black == 25.9.0",
|
|
68
|
+
"mike == 2.1.3",
|
|
69
|
+
"mkdocs-gen-files == 0.5.0",
|
|
70
|
+
"mkdocs-literate-nav == 0.6.2",
|
|
71
|
+
"mkdocs-macros-plugin == 1.4.0",
|
|
72
|
+
"mkdocs-material == 9.6.17",
|
|
73
|
+
"mkdocstrings[python] == 0.30.0",
|
|
74
|
+
"mkdocstrings-python == 1.18.2",
|
|
75
|
+
"frequenz-repo-config[lib] == 0.13.5",
|
|
76
|
+
]
|
|
77
|
+
dev-mypy = [
|
|
78
|
+
"mypy == 1.18.2",
|
|
79
|
+
"grpc-stubs == 1.53.0.6",
|
|
80
|
+
"types-Markdown == 3.9.0.20250906",
|
|
81
|
+
"types-protobuf == 6.32.1.20250918",
|
|
82
|
+
# For checking the noxfile, docs/ script, and tests
|
|
83
|
+
"frequenz-client-assets[dev-mkdocs,dev-noxfile,dev-pytest,cli]",
|
|
84
|
+
]
|
|
85
|
+
dev-noxfile = ["nox == 2025.5.1", "frequenz-repo-config[lib] == 0.13.5"]
|
|
86
|
+
dev-pylint = [
|
|
87
|
+
# dev-pytest already defines a dependency to pylint because of the examples
|
|
88
|
+
# For checking the noxfile, docs/ script, and tests
|
|
89
|
+
"frequenz-client-assets[dev-mkdocs,dev-noxfile,dev-pytest,cli]",
|
|
90
|
+
]
|
|
91
|
+
dev-pytest = [
|
|
92
|
+
"pytest == 8.4.1",
|
|
93
|
+
"pylint == 3.3.8", # We need this to check for the examples
|
|
94
|
+
"frequenz-repo-config[extra-lint-examples] == 0.13.5",
|
|
95
|
+
"pytest-mock == 3.15.1",
|
|
96
|
+
"pytest-asyncio == 1.1.0",
|
|
97
|
+
"async-solipsism == 0.8",
|
|
98
|
+
]
|
|
99
|
+
dev = [
|
|
100
|
+
"frequenz-client-assets[dev-mkdocs,dev-flake8,dev-formatting,dev-mkdocs,dev-mypy,dev-noxfile,dev-pylint,dev-pytest]",
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
[project.urls]
|
|
104
|
+
Documentation = "https://frequenz-floss.github.io/frequenz-client-assets-python/"
|
|
105
|
+
Changelog = "https://github.com/frequenz-floss/frequenz-client-assets-python/releases"
|
|
106
|
+
Issues = "https://github.com/frequenz-floss/frequenz-client-assets-python/issues"
|
|
107
|
+
Repository = "https://github.com/frequenz-floss/frequenz-client-assets-python"
|
|
108
|
+
Support = "https://github.com/frequenz-floss/frequenz-client-assets-python/discussions/categories/support"
|
|
109
|
+
|
|
110
|
+
[tool.black]
|
|
111
|
+
line-length = 88
|
|
112
|
+
target-version = ['py311']
|
|
113
|
+
include = '\.pyi?$'
|
|
114
|
+
|
|
115
|
+
[tool.isort]
|
|
116
|
+
profile = "black"
|
|
117
|
+
line_length = 88
|
|
118
|
+
src_paths = ["benchmarks", "examples", "src", "tests"]
|
|
119
|
+
|
|
120
|
+
[tool.flake8]
|
|
121
|
+
# We give some flexibility to go over 88, there are cases like long URLs or
|
|
122
|
+
# code in documentation that have extra indentation. Black will still take care
|
|
123
|
+
# of making everything that can be 88 wide, 88 wide.
|
|
124
|
+
max-line-length = 100
|
|
125
|
+
extend-ignore = [
|
|
126
|
+
"E203", # Whitespace before ':' (conflicts with black)
|
|
127
|
+
"W503", # Line break before binary operator (conflicts with black)
|
|
128
|
+
]
|
|
129
|
+
# pydoclint options
|
|
130
|
+
style = "google"
|
|
131
|
+
check-return-types = false
|
|
132
|
+
check-yield-types = false
|
|
133
|
+
arg-type-hints-in-docstring = false
|
|
134
|
+
arg-type-hints-in-signature = true
|
|
135
|
+
allow-init-docstring = true
|
|
136
|
+
|
|
137
|
+
[tool.pylint.similarities]
|
|
138
|
+
ignore-comments = ['yes']
|
|
139
|
+
ignore-docstrings = ['yes']
|
|
140
|
+
ignore-imports = ['no']
|
|
141
|
+
min-similarity-lines = 40
|
|
142
|
+
|
|
143
|
+
[tool.pylint.messages_control]
|
|
144
|
+
disable = [
|
|
145
|
+
"too-few-public-methods",
|
|
146
|
+
"too-many-return-statements",
|
|
147
|
+
# disabled because it conflicts with isort
|
|
148
|
+
"wrong-import-order",
|
|
149
|
+
"ungrouped-imports",
|
|
150
|
+
# pylint's unsubscriptable check is buggy and is not needed because
|
|
151
|
+
# it is a type-check, for which we already have mypy.
|
|
152
|
+
"unsubscriptable-object",
|
|
153
|
+
# Checked by mypy
|
|
154
|
+
"no-member",
|
|
155
|
+
"possibly-used-before-assignment",
|
|
156
|
+
"no-name-in-module",
|
|
157
|
+
# Checked by flake8
|
|
158
|
+
"f-string-without-interpolation",
|
|
159
|
+
"line-too-long",
|
|
160
|
+
"missing-function-docstring",
|
|
161
|
+
"redefined-outer-name",
|
|
162
|
+
"unnecessary-lambda-assignment",
|
|
163
|
+
"unused-import",
|
|
164
|
+
"unused-variable",
|
|
165
|
+
]
|
|
166
|
+
|
|
167
|
+
[tool.pytest.ini_options]
|
|
168
|
+
addopts = "-vv"
|
|
169
|
+
filterwarnings = [
|
|
170
|
+
"error",
|
|
171
|
+
"once::DeprecationWarning",
|
|
172
|
+
"once::PendingDeprecationWarning",
|
|
173
|
+
# We use a raw string (single quote) to avoid the need to escape special
|
|
174
|
+
# chars as this is a regex
|
|
175
|
+
'ignore:Protobuf gencode version .*exactly one major version older.*:UserWarning',
|
|
176
|
+
]
|
|
177
|
+
testpaths = ["tests", "src"]
|
|
178
|
+
asyncio_mode = "auto"
|
|
179
|
+
asyncio_default_fixture_loop_scope = "function"
|
|
180
|
+
required_plugins = ["pytest-asyncio", "pytest-mock"]
|
|
181
|
+
|
|
182
|
+
[tool.mypy]
|
|
183
|
+
explicit_package_bases = true
|
|
184
|
+
namespace_packages = true
|
|
185
|
+
# This option disables mypy cache, and it is sometimes useful to enable it if
|
|
186
|
+
# you are getting weird intermittent error, or error in the CI but not locally
|
|
187
|
+
# (or vice versa). In particular errors saying that type: ignore is not
|
|
188
|
+
# used but getting the original ignored error when removing the type: ignore.
|
|
189
|
+
# See for example: https://github.com/python/mypy/issues/2960
|
|
190
|
+
#no_incremental = true
|
|
191
|
+
packages = ["frequenz.client.assets"]
|
|
192
|
+
strict = true
|
|
193
|
+
|
|
194
|
+
[[tool.mypy.overrides]]
|
|
195
|
+
module = ["mkdocs_macros.*", "sybil", "sybil.*"]
|
|
196
|
+
ignore_missing_imports = true
|
|
197
|
+
|
|
198
|
+
[tool.setuptools_scm]
|
|
199
|
+
version_scheme = "post-release"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# License: MIT
|
|
2
|
+
# Copyright © 2025 Frequenz Energy-as-a-Service GmbH
|
|
3
|
+
|
|
4
|
+
"""Assets API client."""
|
|
5
|
+
|
|
6
|
+
from ._client import AssetsApiClient
|
|
7
|
+
from ._delivery_area import DeliveryArea, EnergyMarketCodeType
|
|
8
|
+
from ._location import Location
|
|
9
|
+
from ._microgrid import Microgrid, MicrogridStatus
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"AssetsApiClient",
|
|
13
|
+
"DeliveryArea",
|
|
14
|
+
"EnergyMarketCodeType",
|
|
15
|
+
"Microgrid",
|
|
16
|
+
"MicrogridStatus",
|
|
17
|
+
"Location",
|
|
18
|
+
]
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# License: MIT
|
|
2
|
+
# Copyright © 2025 Frequenz Energy-as-a-Service GmbH
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
Assets API client.
|
|
6
|
+
|
|
7
|
+
This module provides a client for the Assets API.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from frequenz.api.assets.v1 import assets_pb2, assets_pb2_grpc
|
|
13
|
+
from frequenz.client.base import channel
|
|
14
|
+
from frequenz.client.base.client import BaseApiClient, call_stub_method
|
|
15
|
+
|
|
16
|
+
from frequenz.client.assets.electrical_component._electrical_component import (
|
|
17
|
+
ElectricalComponent,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
from ._microgrid import Microgrid
|
|
21
|
+
from ._microgrid_proto import microgrid_from_proto
|
|
22
|
+
from .electrical_component._electrical_component_proto import electrical_component_proto
|
|
23
|
+
from .exceptions import ClientNotConnected
|
|
24
|
+
|
|
25
|
+
DEFAULT_GRPC_CALL_TIMEOUT = 60.0
|
|
26
|
+
"""The default timeout for gRPC calls made by this client (in seconds)."""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class AssetsApiClient(
|
|
30
|
+
BaseApiClient[assets_pb2_grpc.PlatformAssetsStub]
|
|
31
|
+
): # pylint: disable=too-many-arguments
|
|
32
|
+
"""A client for the Assets API."""
|
|
33
|
+
|
|
34
|
+
def __init__(
|
|
35
|
+
self,
|
|
36
|
+
server_url: str,
|
|
37
|
+
*,
|
|
38
|
+
auth_key: str | None = None,
|
|
39
|
+
sign_secret: str | None = None,
|
|
40
|
+
channel_defaults: channel.ChannelOptions = channel.ChannelOptions(),
|
|
41
|
+
connect: bool = True,
|
|
42
|
+
) -> None:
|
|
43
|
+
"""
|
|
44
|
+
Initialize the AssetsApiClient.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
server_url: The location of the microgrid API server in the form of a URL.
|
|
48
|
+
The following format is expected:
|
|
49
|
+
"grpc://hostname{:`port`}{?ssl=`ssl`}",
|
|
50
|
+
where the `port` should be an int between 0 and 65535 (defaulting to
|
|
51
|
+
9090) and `ssl` should be a boolean (defaulting to `true`).
|
|
52
|
+
For example: `grpc://localhost:1090?ssl=true`.
|
|
53
|
+
auth_key: The authentication key to use for the connection.
|
|
54
|
+
sign_secret: The secret to use for signing requests.
|
|
55
|
+
channel_defaults: The default options use to create the channel when not
|
|
56
|
+
specified in the URL.
|
|
57
|
+
connect: Whether to connect to the server as soon as a client instance is
|
|
58
|
+
created. If `False`, the client will not connect to the server until
|
|
59
|
+
[connect()][frequenz.client.base.client.BaseApiClient.connect] is
|
|
60
|
+
called.
|
|
61
|
+
"""
|
|
62
|
+
super().__init__(
|
|
63
|
+
server_url,
|
|
64
|
+
assets_pb2_grpc.PlatformAssetsStub,
|
|
65
|
+
connect=connect,
|
|
66
|
+
channel_defaults=channel_defaults,
|
|
67
|
+
auth_key=auth_key,
|
|
68
|
+
sign_secret=sign_secret,
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def stub(self) -> assets_pb2_grpc.PlatformAssetsAsyncStub:
|
|
73
|
+
"""
|
|
74
|
+
The gRPC stub for the Assets API.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
The gRPC stub for the Assets API.
|
|
78
|
+
|
|
79
|
+
Raises:
|
|
80
|
+
ClientNotConnected: If the client is not connected to the server.
|
|
81
|
+
"""
|
|
82
|
+
if self._channel is None or self._stub is None:
|
|
83
|
+
raise ClientNotConnected(server_url=self.server_url, operation="stub")
|
|
84
|
+
# This type: ignore is needed because the stub is a sync stub, but we need to
|
|
85
|
+
# use the async stub, so we cast the sync stub to the async stub.
|
|
86
|
+
return self._stub # type: ignore
|
|
87
|
+
|
|
88
|
+
async def get_microgrid( # noqa: DOC502 (raises ApiClientError indirectly)
|
|
89
|
+
self, microgrid_id: int
|
|
90
|
+
) -> Microgrid:
|
|
91
|
+
"""
|
|
92
|
+
Get the details of a microgrid.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
microgrid_id: The ID of the microgrid to get the details of.
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
The details of the microgrid.
|
|
99
|
+
|
|
100
|
+
Raises:
|
|
101
|
+
ApiClientError: If there are any errors communicating with the Assets API,
|
|
102
|
+
most likely a subclass of [GrpcError][frequenz.client.base.exception.GrpcError].
|
|
103
|
+
"""
|
|
104
|
+
response = await call_stub_method(
|
|
105
|
+
self,
|
|
106
|
+
lambda: self.stub.GetMicrogrid(
|
|
107
|
+
assets_pb2.GetMicrogridRequest(microgrid_id=microgrid_id),
|
|
108
|
+
timeout=DEFAULT_GRPC_CALL_TIMEOUT,
|
|
109
|
+
),
|
|
110
|
+
method_name="GetMicrogrid",
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
return microgrid_from_proto(response.microgrid)
|
|
114
|
+
|
|
115
|
+
async def list_microgrid_electrical_components(
|
|
116
|
+
self, microgrid_id: int
|
|
117
|
+
) -> list[ElectricalComponent]:
|
|
118
|
+
"""
|
|
119
|
+
Get the electrical components of a microgrid.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
microgrid_id: The ID of the microgrid to get the electrical components of.
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
The electrical components of the microgrid.
|
|
126
|
+
"""
|
|
127
|
+
response = await call_stub_method(
|
|
128
|
+
self,
|
|
129
|
+
lambda: self.stub.ListMicrogridElectricalComponents(
|
|
130
|
+
assets_pb2.ListMicrogridElectricalComponentsRequest(
|
|
131
|
+
microgrid_id=microgrid_id,
|
|
132
|
+
),
|
|
133
|
+
timeout=DEFAULT_GRPC_CALL_TIMEOUT,
|
|
134
|
+
),
|
|
135
|
+
method_name="ListMicrogridElectricalComponents",
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
return [
|
|
139
|
+
electrical_component_proto(component) for component in response.components
|
|
140
|
+
]
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# License: MIT
|
|
2
|
+
# Copyright © 2025 Frequenz Energy-as-a-Service GmbH
|
|
3
|
+
|
|
4
|
+
"""Delivery area information for the energy market."""
|
|
5
|
+
|
|
6
|
+
import enum
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
|
|
9
|
+
from frequenz.api.common.v1alpha8.grid import delivery_area_pb2
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@enum.unique
|
|
13
|
+
class EnergyMarketCodeType(enum.Enum):
|
|
14
|
+
"""The identification code types used in the energy market.
|
|
15
|
+
|
|
16
|
+
CodeType specifies the type of identification code used for uniquely
|
|
17
|
+
identifying various entities such as delivery areas, market participants,
|
|
18
|
+
and grid components within the energy market.
|
|
19
|
+
|
|
20
|
+
This enumeration aims to
|
|
21
|
+
offer compatibility across different jurisdictional standards.
|
|
22
|
+
|
|
23
|
+
Note: Understanding Code Types
|
|
24
|
+
Different regions or countries may have their own standards for uniquely
|
|
25
|
+
identifying various entities within the energy market. For example, in
|
|
26
|
+
Europe, the Energy Identification Code (EIC) is commonly used for this
|
|
27
|
+
purpose.
|
|
28
|
+
|
|
29
|
+
Note: Extensibility
|
|
30
|
+
New code types can be added to this enum to accommodate additional regional
|
|
31
|
+
standards, enhancing the API's adaptability.
|
|
32
|
+
|
|
33
|
+
Danger: Validation Required
|
|
34
|
+
The chosen code type should correspond correctly with the `code` field in
|
|
35
|
+
the relevant message objects, such as `DeliveryArea` or `Counterparty`.
|
|
36
|
+
Failure to match the code type with the correct code could lead to
|
|
37
|
+
processing errors.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
UNSPECIFIED = delivery_area_pb2.ENERGY_MARKET_CODE_TYPE_UNSPECIFIED
|
|
41
|
+
"""Unspecified type. This value is a placeholder and should not be used."""
|
|
42
|
+
|
|
43
|
+
EUROPE_EIC = delivery_area_pb2.ENERGY_MARKET_CODE_TYPE_EUROPE_EIC
|
|
44
|
+
"""European Energy Identification Code Standard."""
|
|
45
|
+
|
|
46
|
+
US_NERC = delivery_area_pb2.ENERGY_MARKET_CODE_TYPE_US_NERC
|
|
47
|
+
"""North American Electric Reliability Corporation identifiers."""
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@dataclass(frozen=True, kw_only=True)
|
|
51
|
+
class DeliveryArea:
|
|
52
|
+
"""A geographical or administrative region where electricity deliveries occur.
|
|
53
|
+
|
|
54
|
+
DeliveryArea represents the geographical or administrative region, usually defined
|
|
55
|
+
and maintained by a Transmission System Operator (TSO), where electricity deliveries
|
|
56
|
+
for a contract occur.
|
|
57
|
+
|
|
58
|
+
The concept is important to energy trading as it delineates the agreed-upon delivery
|
|
59
|
+
location. Delivery areas can have different codes based on the jurisdiction in
|
|
60
|
+
which they operate.
|
|
61
|
+
|
|
62
|
+
Note: Jurisdictional Differences
|
|
63
|
+
This is typically represented by specific codes according to local jurisdiction.
|
|
64
|
+
|
|
65
|
+
In Europe, this is represented by an
|
|
66
|
+
[EIC](https://en.wikipedia.org/wiki/Energy_Identification_Code) (Energy
|
|
67
|
+
Identification Code). [List of
|
|
68
|
+
EICs](https://www.entsoe.eu/data/energy-identification-codes-eic/eic-approved-codes/).
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
code: str | None
|
|
72
|
+
"""The code representing the unique identifier for the delivery area."""
|
|
73
|
+
|
|
74
|
+
code_type: EnergyMarketCodeType | int
|
|
75
|
+
"""Type of code used for identifying the delivery area itself.
|
|
76
|
+
|
|
77
|
+
This code could be extended in the future, in case an unknown code type is
|
|
78
|
+
encountered, a plain integer value is used to represent it.
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
def __str__(self) -> str:
|
|
82
|
+
"""Return a human-readable string representation of this instance."""
|
|
83
|
+
code = self.code or "<NO CODE>"
|
|
84
|
+
code_type = (
|
|
85
|
+
f"type={self.code_type}"
|
|
86
|
+
if isinstance(self.code_type, int)
|
|
87
|
+
else self.code_type.name
|
|
88
|
+
)
|
|
89
|
+
return f"{code}[{code_type}]"
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# License: MIT
|
|
2
|
+
# Copyright © 2025 Frequenz Energy-as-a-Service GmbH
|
|
3
|
+
|
|
4
|
+
"""Loading of DeliveryArea objects from protobuf messages."""
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
|
|
8
|
+
from frequenz.api.common.v1alpha8.grid import delivery_area_pb2
|
|
9
|
+
from frequenz.client.common import enum_proto
|
|
10
|
+
|
|
11
|
+
from ._delivery_area import DeliveryArea, EnergyMarketCodeType
|
|
12
|
+
|
|
13
|
+
_logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def delivery_area_from_proto(message: delivery_area_pb2.DeliveryArea) -> DeliveryArea:
|
|
17
|
+
"""Convert a protobuf delivery area message to a delivery area object.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
message: The protobuf message to convert.
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
The resulting delivery area object.
|
|
24
|
+
"""
|
|
25
|
+
issues: list[str] = []
|
|
26
|
+
|
|
27
|
+
code = message.code or None
|
|
28
|
+
if code is None:
|
|
29
|
+
issues.append("code is empty")
|
|
30
|
+
|
|
31
|
+
code_type = enum_proto.enum_from_proto(message.code_type, EnergyMarketCodeType)
|
|
32
|
+
if code_type is EnergyMarketCodeType.UNSPECIFIED:
|
|
33
|
+
issues.append("code_type is unspecified")
|
|
34
|
+
elif isinstance(code_type, int):
|
|
35
|
+
issues.append("code_type is unrecognized")
|
|
36
|
+
|
|
37
|
+
if issues:
|
|
38
|
+
_logger.warning(
|
|
39
|
+
"Found issues in delivery area: %s | Protobuf message:\n%s",
|
|
40
|
+
", ".join(issues),
|
|
41
|
+
message,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
return DeliveryArea(code=code, code_type=code_type)
|