frequenz-dispatch 0.1.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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright © 2024 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,109 @@
1
+ Metadata-Version: 2.1
2
+ Name: frequenz-dispatch
3
+ Version: 0.1.0
4
+ Summary: A highlevel interface for the dispatch API
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-dispatch-python/
8
+ Project-URL: Changelog, https://github.com/frequenz-floss/frequenz-dispatch-python/releases
9
+ Project-URL: Issues, https://github.com/frequenz-floss/frequenz-dispatch-python/issues
10
+ Project-URL: Repository, https://github.com/frequenz-floss/frequenz-dispatch-python
11
+ Project-URL: Support, https://github.com/frequenz-floss/frequenz-dispatch-python/discussions/categories/support
12
+ Keywords: frequenz,python,actor,frequenz-dispatch,dispatch,highlevel,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
+ Provides-Extra: dev-flake8
23
+ Provides-Extra: dev-formatting
24
+ Provides-Extra: dev-mkdocs
25
+ Provides-Extra: dev-mypy
26
+ Provides-Extra: dev-noxfile
27
+ Provides-Extra: dev-pylint
28
+ Provides-Extra: dev-pytest
29
+ Provides-Extra: dev
30
+ License-File: LICENSE
31
+
32
+ # Dispatch Highlevel Interface
33
+
34
+ [![Build Status](https://github.com/frequenz-floss/frequenz-dispatch-python/actions/workflows/ci.yaml/badge.svg)](https://github.com/frequenz-floss/frequenz-dispatch-python/actions/workflows/ci.yaml)
35
+ [![PyPI Package](https://img.shields.io/pypi/v/frequenz-dispatch)](https://pypi.org/project/frequenz-dispatch/)
36
+ [![Docs](https://img.shields.io/badge/docs-latest-informational)](https://frequenz-floss.github.io/frequenz-dispatch-python/)
37
+
38
+ ## Introduction
39
+
40
+ A highlevel interface for the dispatch API.
41
+
42
+ See [the documentation](https://frequenz-floss.github.io/frequenz-dispatch-python/v0.1/reference/frequenz/dispatch) for more information.
43
+
44
+ ## Usage
45
+
46
+ The [`Dispatcher` class](https://frequenz-floss.github.io/frequenz-dispatch-python/v0.1/reference/frequenz/dispatch/#frequenz.dispatch.Dispatcher), the main entry point for the API, provides two channels:
47
+
48
+ * [Lifecycle events](https://frequenz-floss.github.io/frequenz-dispatch-python/v0.1/reference/frequenz/dispatch/#frequenz.dispatch.Dispatcher.lifecycle_events): A channel that sends a message whenever a [Dispatch][frequenz.dispatch.Dispatch] is created, updated or deleted.
49
+ * [Running status change](https://frequenz-floss.github.io/frequenz-dispatch-python/v0.1/reference/frequenz/dispatch/#frequenz.dispatch.Dispatcher.running_status_change): Sends a dispatch message whenever a dispatch is ready to be executed according to the schedule or the running status of the dispatch changed in a way that could potentially require the actor to start, stop or reconfigure itself.
50
+
51
+ ### Example using the running status change channel
52
+
53
+ ```python
54
+ import os
55
+ import grpc.aio
56
+ from unittest.mock import MagicMock
57
+
58
+ async def run():
59
+ host = os.getenv("DISPATCH_API_HOST", "localhost")
60
+ port = os.getenv("DISPATCH_API_PORT", "50051")
61
+
62
+ service_address = f"{host}:{port}"
63
+ grpc_channel = grpc.aio.insecure_channel(service_address)
64
+ microgrid_id = 1
65
+ dispatcher = Dispatcher(microgrid_id, grpc_channel, service_address)
66
+ await dispatcher.start()
67
+
68
+ actor = MagicMock() # replace with your actor
69
+
70
+ changed_running_status_rx = dispatcher.running_status_change.new_receiver()
71
+
72
+ async for dispatch in changed_running_status_rx:
73
+ match dispatch.running("DEMO_TYPE"):
74
+ case RunningState.RUNNING:
75
+ print(f"Executing dispatch {dispatch.id}, due on {dispatch.start_time}")
76
+ if actor.is_running:
77
+ actor.reconfigure(
78
+ components=dispatch.selector,
79
+ run_parameters=dispatch.payload, # custom actor parameters
80
+ dry_run=dispatch.dry_run,
81
+ until=dispatch.until,
82
+ ) # this will reconfigure the actor
83
+ else:
84
+ # this will start a new actor with the given components
85
+ # and run it for the duration of the dispatch
86
+ actor.start(
87
+ components=dispatch.selector,
88
+ run_parameters=dispatch.payload, # custom actor parameters
89
+ dry_run=dispatch.dry_run,
90
+ until=dispatch.until,
91
+ )
92
+ case RunningState.STOPPED:
93
+ actor.stop() # this will stop the actor
94
+ case RunningState.DIFFERENT_TYPE:
95
+ pass # dispatch not for this type
96
+ ```
97
+
98
+ ## Supported Platforms
99
+
100
+ The following platforms are officially supported (tested):
101
+
102
+ - **Python:** 3.11
103
+ - **Operating System:** Ubuntu Linux 20.04
104
+ - **Architectures:** amd64, arm64
105
+
106
+ ## Contributing
107
+
108
+ If you want to know how to build this project and contribute to it, please
109
+ check out the [Contributing Guide](CONTRIBUTING.md).
@@ -0,0 +1,78 @@
1
+ # Dispatch Highlevel Interface
2
+
3
+ [![Build Status](https://github.com/frequenz-floss/frequenz-dispatch-python/actions/workflows/ci.yaml/badge.svg)](https://github.com/frequenz-floss/frequenz-dispatch-python/actions/workflows/ci.yaml)
4
+ [![PyPI Package](https://img.shields.io/pypi/v/frequenz-dispatch)](https://pypi.org/project/frequenz-dispatch/)
5
+ [![Docs](https://img.shields.io/badge/docs-latest-informational)](https://frequenz-floss.github.io/frequenz-dispatch-python/)
6
+
7
+ ## Introduction
8
+
9
+ A highlevel interface for the dispatch API.
10
+
11
+ See [the documentation](https://frequenz-floss.github.io/frequenz-dispatch-python/v0.1/reference/frequenz/dispatch) for more information.
12
+
13
+ ## Usage
14
+
15
+ The [`Dispatcher` class](https://frequenz-floss.github.io/frequenz-dispatch-python/v0.1/reference/frequenz/dispatch/#frequenz.dispatch.Dispatcher), the main entry point for the API, provides two channels:
16
+
17
+ * [Lifecycle events](https://frequenz-floss.github.io/frequenz-dispatch-python/v0.1/reference/frequenz/dispatch/#frequenz.dispatch.Dispatcher.lifecycle_events): A channel that sends a message whenever a [Dispatch][frequenz.dispatch.Dispatch] is created, updated or deleted.
18
+ * [Running status change](https://frequenz-floss.github.io/frequenz-dispatch-python/v0.1/reference/frequenz/dispatch/#frequenz.dispatch.Dispatcher.running_status_change): Sends a dispatch message whenever a dispatch is ready to be executed according to the schedule or the running status of the dispatch changed in a way that could potentially require the actor to start, stop or reconfigure itself.
19
+
20
+ ### Example using the running status change channel
21
+
22
+ ```python
23
+ import os
24
+ import grpc.aio
25
+ from unittest.mock import MagicMock
26
+
27
+ async def run():
28
+ host = os.getenv("DISPATCH_API_HOST", "localhost")
29
+ port = os.getenv("DISPATCH_API_PORT", "50051")
30
+
31
+ service_address = f"{host}:{port}"
32
+ grpc_channel = grpc.aio.insecure_channel(service_address)
33
+ microgrid_id = 1
34
+ dispatcher = Dispatcher(microgrid_id, grpc_channel, service_address)
35
+ await dispatcher.start()
36
+
37
+ actor = MagicMock() # replace with your actor
38
+
39
+ changed_running_status_rx = dispatcher.running_status_change.new_receiver()
40
+
41
+ async for dispatch in changed_running_status_rx:
42
+ match dispatch.running("DEMO_TYPE"):
43
+ case RunningState.RUNNING:
44
+ print(f"Executing dispatch {dispatch.id}, due on {dispatch.start_time}")
45
+ if actor.is_running:
46
+ actor.reconfigure(
47
+ components=dispatch.selector,
48
+ run_parameters=dispatch.payload, # custom actor parameters
49
+ dry_run=dispatch.dry_run,
50
+ until=dispatch.until,
51
+ ) # this will reconfigure the actor
52
+ else:
53
+ # this will start a new actor with the given components
54
+ # and run it for the duration of the dispatch
55
+ actor.start(
56
+ components=dispatch.selector,
57
+ run_parameters=dispatch.payload, # custom actor parameters
58
+ dry_run=dispatch.dry_run,
59
+ until=dispatch.until,
60
+ )
61
+ case RunningState.STOPPED:
62
+ actor.stop() # this will stop the actor
63
+ case RunningState.DIFFERENT_TYPE:
64
+ pass # dispatch not for this type
65
+ ```
66
+
67
+ ## Supported Platforms
68
+
69
+ The following platforms are officially supported (tested):
70
+
71
+ - **Python:** 3.11
72
+ - **Operating System:** Ubuntu Linux 20.04
73
+ - **Architectures:** amd64, arm64
74
+
75
+ ## Contributing
76
+
77
+ If you want to know how to build this project and contribute to it, please
78
+ check out the [Contributing Guide](CONTRIBUTING.md).
@@ -0,0 +1,14 @@
1
+ # Dispatch Highlevel Interface Release Notes
2
+
3
+ ## Summary
4
+
5
+ This is the first release of the highlevel dispatch interface!
6
+
7
+ ## Upgrading
8
+
9
+ * `Dispatcher.ready_to_execute()` was renamed to `Dispatcher.running_status_change()`
10
+
11
+ ## New Features
12
+
13
+ * Introduced new class `Dispatch` (based on the client class) that contains useful functions and extended information about the received dispatch.
14
+ * `Dispatcher.client` was added to provide an easy access to the client for updating, deleting and creating dispatches
@@ -0,0 +1,184 @@
1
+ # License: MIT
2
+ # Copyright © 2024 Frequenz Energy-as-a-Service GmbH
3
+
4
+ [build-system]
5
+ requires = [
6
+ "setuptools == 68.1.0",
7
+ "setuptools_scm[toml] == 7.1.0",
8
+ "frequenz-repo-config[lib] == 0.9.2",
9
+ ]
10
+ build-backend = "setuptools.build_meta"
11
+
12
+ [project]
13
+ name = "frequenz-dispatch"
14
+ description = "A highlevel interface for the dispatch API"
15
+ readme = "README.md"
16
+ license = { text = "MIT" }
17
+ keywords = [
18
+ "frequenz",
19
+ "python",
20
+ "actor",
21
+ "frequenz-dispatch",
22
+ "dispatch",
23
+ "highlevel",
24
+ "api",
25
+ ]
26
+ classifiers = [
27
+ "Development Status :: 3 - Alpha",
28
+ "Intended Audience :: Developers",
29
+ "License :: OSI Approved :: MIT License",
30
+ "Programming Language :: Python :: 3",
31
+ "Programming Language :: Python :: 3 :: Only",
32
+ "Topic :: Software Development :: Libraries",
33
+ "Typing :: Typed",
34
+ ]
35
+ requires-python = ">= 3.11, < 4"
36
+ dependencies = [
37
+ "python-dateutil >= 2.8.2, < 3.0",
38
+ "typing-extensions == 4.11.0",
39
+ # Make sure to update the version for cross-referencing also in the
40
+ # mkdocs.yml file when changing the version here (look for the config key
41
+ # plugins.mkdocstrings.handlers.python.import)
42
+ "frequenz-sdk == v1.0.0-rc6",
43
+ "frequenz-channels == 1.0.0",
44
+ "frequenz-api-dispatch >= 0.13.0, < 0.14",
45
+ "frequenz-client-dispatch == 0.2.0",
46
+ "frequenz-client-base >= 0.3.0, < 0.4.0",
47
+ "frequenz-client-common >= 0.1.0, < 0.2.0",
48
+ ]
49
+ dynamic = ["version"]
50
+
51
+ [[project.authors]]
52
+ name = "Frequenz Energy-as-a-Service GmbH"
53
+ email = "floss@frequenz.com"
54
+
55
+ [project.optional-dependencies]
56
+ dev-flake8 = [
57
+ "flake8 == 7.0.0",
58
+ "flake8-docstrings == 1.7.0",
59
+ "flake8-pyproject == 1.2.3", # For reading the flake8 config from pyproject.toml
60
+ "pydoclint == 0.4.1",
61
+ "pydocstyle == 6.3.0",
62
+ ]
63
+ dev-formatting = ["black == 24.4.2", "isort == 5.13.2"]
64
+ dev-mkdocs = [
65
+ "black == 24.4.2",
66
+ "Markdown==3.6",
67
+ "mike == 2.1.0",
68
+ "mkdocs-gen-files == 0.5.0",
69
+ "mkdocs-literate-nav == 0.6.1",
70
+ "mkdocs-macros-plugin == 1.0.5",
71
+ "mkdocs-material == 9.5.20",
72
+ "mkdocstrings[python] == 0.25.0",
73
+ "frequenz-repo-config[lib] == 0.9.2",
74
+ ]
75
+ dev-mypy = [
76
+ "mypy == 1.10.0",
77
+ "types-Markdown == 3.6.0.20240316",
78
+ "types-python-dateutil==2.9.0.20240316",
79
+ # For checking the noxfile, docs/ script, and tests
80
+ "frequenz-dispatch[dev-mkdocs,dev-noxfile,dev-pytest]",
81
+ ]
82
+ dev-noxfile = [
83
+ "uv == 0.1.39",
84
+ "nox == 2024.4.15",
85
+ "frequenz-repo-config[lib] == 0.9.2",
86
+ ]
87
+ dev-pylint = [
88
+ "pylint == 3.1.0",
89
+ # For checking the noxfile, docs/ script, and tests
90
+ "frequenz-dispatch[dev-mkdocs,dev-noxfile,dev-pytest]",
91
+ ]
92
+ dev-pytest = [
93
+ "pytest == 8.2.0",
94
+ "frequenz-repo-config[extra-lint-examples] == 0.9.2",
95
+ "pytest-mock == 3.14.0",
96
+ "pytest-asyncio == 0.23.6",
97
+ "async-solipsism == 0.6",
98
+ "time-machine == 2.14.1",
99
+ ]
100
+ dev = [
101
+ "frequenz-dispatch[dev-mkdocs,dev-flake8,dev-formatting,dev-mkdocs,dev-mypy,dev-noxfile,dev-pylint,dev-pytest]",
102
+ ]
103
+
104
+ [project.urls]
105
+ Documentation = "https://frequenz-floss.github.io/frequenz-dispatch-python/"
106
+ Changelog = "https://github.com/frequenz-floss/frequenz-dispatch-python/releases"
107
+ Issues = "https://github.com/frequenz-floss/frequenz-dispatch-python/issues"
108
+ Repository = "https://github.com/frequenz-floss/frequenz-dispatch-python"
109
+ Support = "https://github.com/frequenz-floss/frequenz-dispatch-python/discussions/categories/support"
110
+
111
+ [tool.black]
112
+ line-length = 88
113
+ target-version = ['py311']
114
+ include = '\.pyi?$'
115
+
116
+ [tool.isort]
117
+ profile = "black"
118
+ line_length = 88
119
+ src_paths = ["benchmarks", "examples", "src", "tests"]
120
+
121
+ [tool.flake8]
122
+ # We give some flexibility to go over 88, there are cases like long URLs or
123
+ # code in documenation that have extra indentation. Black will still take care
124
+ # of making everything that can be 88 wide, 88 wide.
125
+ max-line-length = 100
126
+ extend-ignore = [
127
+ "E203", # Whitespace before ':' (conflicts with black)
128
+ "W503", # Line break before binary operator (conflicts with black)
129
+ ]
130
+ # pydoclint options
131
+ style = "google"
132
+ check-return-types = false
133
+ check-yield-types = false
134
+ arg-type-hints-in-docstring = false
135
+ arg-type-hints-in-signature = true
136
+ allow-init-docstring = true
137
+
138
+ [tool.pylint.similarities]
139
+ ignore-comments = ['yes']
140
+ ignore-docstrings = ['yes']
141
+ ignore-imports = ['no']
142
+ min-similarity-lines = 40
143
+
144
+ [tool.pylint.messages_control]
145
+ disable = [
146
+ "too-few-public-methods",
147
+ "too-many-return-statements",
148
+ # disabled because it conflicts with isort
149
+ "wrong-import-order",
150
+ "ungrouped-imports",
151
+ # pylint's unsubscriptable check is buggy and is not needed because
152
+ # it is a type-check, for which we already have mypy.
153
+ "unsubscriptable-object",
154
+ # Checked by flake8
155
+ "line-too-long",
156
+ "redefined-outer-name",
157
+ "unnecessary-lambda-assignment",
158
+ "unused-import",
159
+ "unused-variable",
160
+ ]
161
+
162
+ [tool.pytest.ini_options]
163
+ testpaths = ["tests", "src"]
164
+ asyncio_mode = "auto"
165
+ required_plugins = ["pytest-asyncio", "pytest-mock"]
166
+
167
+ [tool.mypy]
168
+ explicit_package_bases = true
169
+ namespace_packages = true
170
+ # This option disables mypy cache, and it is sometimes useful to enable it if
171
+ # you are getting weird intermittent error, or error in the CI but not locally
172
+ # (or vice versa). In particular errors saying that type: ignore is not
173
+ # used but getting the original ignored error when removing the type: ignore.
174
+ # See for example: https://github.com/python/mypy/issues/2960
175
+ #no_incremental = true
176
+ packages = ["frequenz.dispatch"]
177
+ strict = true
178
+
179
+ [[tool.mypy.overrides]]
180
+ module = ["mkdocs_macros.*", "async_solipsism", "async_solipsism.*"]
181
+ ignore_missing_imports = true
182
+
183
+ [tool.setuptools_scm]
184
+ version_scheme = "post-release"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,29 @@
1
+ # License: MIT
2
+ # Copyright © 2024 Frequenz Energy-as-a-Service GmbH
3
+
4
+ """A highlevel interface for the dispatch API.
5
+
6
+ A small overview of the most important classes in this module:
7
+
8
+ * [Dispatcher][frequenz.dispatch.Dispatcher]: The entry point for the API.
9
+ * [Dispatch][frequenz.dispatch.Dispatch]: A dispatch type with lots of useful extra functionality.
10
+ * [Created][frequenz.dispatch.Created],
11
+ [Updated][frequenz.dispatch.Updated],
12
+ [Deleted][frequenz.dispatch.Deleted]: Dispatch event types.
13
+
14
+ """
15
+
16
+ from ._dispatch import Dispatch, RunningState
17
+ from ._dispatcher import Dispatcher, ReceiverFetcher
18
+ from ._event import Created, Deleted, DispatchEvent, Updated
19
+
20
+ __all__ = [
21
+ "Created",
22
+ "Deleted",
23
+ "DispatchEvent",
24
+ "Dispatcher",
25
+ "ReceiverFetcher",
26
+ "Updated",
27
+ "Dispatch",
28
+ "RunningState",
29
+ ]