From fee07e309c9935ae67d8a8e8aa4da576a8180d70 Mon Sep 17 00:00:00 2001 From: Daniel Zullo Date: Mon, 22 Jul 2024 16:23:59 +0200 Subject: [PATCH] Update sender type in ConfigManagingActor The ConfigManagingActor now sends a collections.abc.Mapping type as the output sender type to indicate to the user that the broadcasted configuration is intended to be read-only. This change leverages type checkers (e.g., mypy, etc.) to help ensure that users do not attempt to modify the dictionary contents. Note that this change won't prevent users from modifying the contents at runtime, but it will help prevent accidental modifications. Signed-off-by: Daniel Zullo --- RELEASE_NOTES.md | 2 ++ src/frequenz/sdk/actor/_config_managing.py | 6 +++--- tests/actor/test_config_manager.py | 5 +++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index adfe7dabf..1f765c78d 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -21,6 +21,8 @@ - Power distribution results are no longer available through the `power_status` streams in the `*Pool`s. They can now be accessed as a stream from a separate property `power_distribution_results`, which is available from all the `*Pool`s. +- The `ConfigManagingActor` now uses `collections.abc.Mapping` as the output sender type. This change indicates that the broadcasted configuration is intended to be read-only. + ## New Features - Classes `Bounds` and `SystemBounds` now implement the `__contains__` method, allowing the use of the `in` operator to check whether a value falls within the bounds or not. diff --git a/src/frequenz/sdk/actor/_config_managing.py b/src/frequenz/sdk/actor/_config_managing.py index bf7c72a4c..a141f0571 100644 --- a/src/frequenz/sdk/actor/_config_managing.py +++ b/src/frequenz/sdk/actor/_config_managing.py @@ -32,7 +32,7 @@ class ConfigManagingActor(Actor): def __init__( self, config_path: pathlib.Path | str, - output: Sender[dict[str, Any]], + output: Sender[abc.Mapping[str, Any]], event_types: abc.Set[EventType] = frozenset(EventType), *, name: str | None = None, @@ -58,9 +58,9 @@ def __init__( self._file_watcher: FileWatcher = FileWatcher( paths=[self._config_path.parent], event_types=event_types ) - self._output: Sender[dict[str, Any]] = output + self._output: Sender[abc.Mapping[str, Any]] = output - def _read_config(self) -> dict[str, Any]: + def _read_config(self) -> abc.Mapping[str, Any]: """Read the contents of the configuration file. Returns: diff --git a/tests/actor/test_config_manager.py b/tests/actor/test_config_manager.py index 88d15c139..c31417d6a 100644 --- a/tests/actor/test_config_manager.py +++ b/tests/actor/test_config_manager.py @@ -4,6 +4,7 @@ """Test for ConfigManager.""" import os import pathlib +from collections.abc import Mapping from typing import Any import pytest @@ -65,7 +66,7 @@ async def test_update(self, config_file: pathlib.Path) -> None: - the initial content of the content file is correct - the config file modifications are picked up and the new content is correct """ - config_channel: Broadcast[dict[str, Any]] = Broadcast( + config_channel: Broadcast[Mapping[str, Any]] = Broadcast( name="Config Channel", resend_latest=True ) config_receiver = config_channel.new_receiver() @@ -91,7 +92,7 @@ async def test_update(self, config_file: pathlib.Path) -> None: async def test_update_relative_path(self, config_file: pathlib.Path) -> None: """Test ConfigManagingActor with a relative path.""" - config_channel: Broadcast[dict[str, Any]] = Broadcast( + config_channel: Broadcast[Mapping[str, Any]] = Broadcast( name="Config Channel", resend_latest=True ) config_receiver = config_channel.new_receiver()