From 1135544eff4cf72347de0a259af844e78fbe6bfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20H=C3=B6ning?= Date: Fri, 14 Jul 2023 00:25:04 +0200 Subject: [PATCH 1/3] feat: let CLI users pass a JSON list (as a string) to set an asset or sensor attribute MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nicolas Höning --- flexmeasures/cli/data_edit.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/flexmeasures/cli/data_edit.py b/flexmeasures/cli/data_edit.py index 32095459d..1b22b0c2a 100644 --- a/flexmeasures/cli/data_edit.py +++ b/flexmeasures/cli/data_edit.py @@ -10,6 +10,7 @@ import pandas as pd from flask import current_app as app from flask.cli import with_appcontext +import json from flexmeasures import Sensor from flexmeasures.data import db @@ -78,6 +79,13 @@ def fm_edit_data(): type=int, help="Set the attribute to this integer value.", ) +@click.option( + "--list", + "attribute_list_value", + required=False, + type=str, + help="Set the attribute to this list value. Pass a string with a JSON-parse-able list representation, e.g. '[1,\"a\"]'.", +) @click.option( "--null", "attribute_null_value", @@ -95,6 +103,7 @@ def edit_attribute( attribute_bool_value: bool | None = None, attribute_str_value: str | None = None, attribute_int_value: int | None = None, + attribute_list_value: str | None = None, ): """Edit (or add) an asset attribute or sensor attribute.""" @@ -107,6 +116,7 @@ def edit_attribute( attribute_bool_value=attribute_bool_value, attribute_str_value=attribute_str_value, attribute_int_value=attribute_int_value, + attribute_list_value=attribute_list_value, attribute_null_value=attribute_null_value, ) @@ -217,6 +227,7 @@ def parse_attribute_value( attribute_bool_value: bool | None = None, attribute_str_value: str | None = None, attribute_int_value: int | None = None, + attribute_list_value: str | None = None, ) -> float | int | bool | str | None: """Parse attribute value.""" if not single_true( @@ -228,6 +239,7 @@ def parse_attribute_value( attribute_bool_value, attribute_str_value, attribute_int_value, + attribute_list_value, ] ] ): @@ -240,6 +252,14 @@ def parse_attribute_value( return bool(attribute_bool_value) elif attribute_int_value is not None: return int(attribute_int_value) + elif attribute_list_value is not None: + try: + val = json.loads(attribute_list_value) + except json.decoder.JSONDecodeError as jde: + raise ValueError(f"Error parsing list value: {jde}") + if not isinstance(val, list): + raise ValueError(f"{val} is not a list.") + return val return attribute_str_value From 77b4111a0104093b32f7fa8d13fcaf46e2878523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20H=C3=B6ning?= Date: Mon, 17 Jul 2023 21:57:54 +0200 Subject: [PATCH 2/3] add option to set dict values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nicolas Höning --- flexmeasures/cli/data_edit.py | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/flexmeasures/cli/data_edit.py b/flexmeasures/cli/data_edit.py index 1b22b0c2a..63b104fb9 100644 --- a/flexmeasures/cli/data_edit.py +++ b/flexmeasures/cli/data_edit.py @@ -86,6 +86,13 @@ def fm_edit_data(): type=str, help="Set the attribute to this list value. Pass a string with a JSON-parse-able list representation, e.g. '[1,\"a\"]'.", ) +@click.option( + "--dict", + "attribute_dict_value", + required=False, + type=str, + help="Set the attribute to this dict value. Pass a string with a JSON-parse-able dict representation, e.g. '{1:\"a\"}'.", +) @click.option( "--null", "attribute_null_value", @@ -104,6 +111,7 @@ def edit_attribute( attribute_str_value: str | None = None, attribute_int_value: int | None = None, attribute_list_value: str | None = None, + attribute_dict_value: str | None = None, ): """Edit (or add) an asset attribute or sensor attribute.""" @@ -117,6 +125,7 @@ def edit_attribute( attribute_str_value=attribute_str_value, attribute_int_value=attribute_int_value, attribute_list_value=attribute_list_value, + attribute_dict_value=attribute_dict_value, attribute_null_value=attribute_null_value, ) @@ -221,14 +230,15 @@ def resample_sensor_data( app.cli.add_command(fm_edit_data) -def parse_attribute_value( +def parse_attribute_value( # noqa: C901 attribute_null_value: bool, attribute_float_value: float | None = None, attribute_bool_value: bool | None = None, attribute_str_value: str | None = None, attribute_int_value: int | None = None, attribute_list_value: str | None = None, -) -> float | int | bool | str | None: + attribute_dict_value: str | None = None, +) -> float | int | bool | str | list | dict | None: """Parse attribute value.""" if not single_true( [attribute_null_value] @@ -240,6 +250,7 @@ def parse_attribute_value( attribute_str_value, attribute_int_value, attribute_list_value, + attribute_dict_value, ] ] ): @@ -260,6 +271,14 @@ def parse_attribute_value( if not isinstance(val, list): raise ValueError(f"{val} is not a list.") return val + elif attribute_dict_value is not None: + try: + val = json.loads(attribute_dict_value) + except json.decoder.JSONDecodeError as jde: + raise ValueError(f"Error parsing dict value: {jde}") + if not isinstance(val, dict): + raise ValueError(f"{val} is not a dict.") + return val return attribute_str_value From 429dc637f4dc3fad34ebf4f311bf2b5d714d83c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20H=C3=B6ning?= Date: Mon, 17 Jul 2023 22:09:11 +0200 Subject: [PATCH 3/3] docs: add changelog entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nicolas Höning --- documentation/changelog.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/changelog.rst b/documentation/changelog.rst index 167a8fb8c..98f202509 100644 --- a/documentation/changelog.rst +++ b/documentation/changelog.rst @@ -15,6 +15,7 @@ New features * Make it a lot easier to read off the color legend on the asset page, especially when showing many sensors, as they will now be ordered from top to bottom in the same order as they appear in the chart (as defined in the ``sensors_to_show`` attribute), rather than alphabetically [see `PR #742 `_] * Having percentages within the [0, 100] domain is such a common use case that we now always include it in sensor charts with % units, making it easier to read off individual charts and also to compare across charts [see `PR #739 `_] * DataSource table now allows storing arbitrary attributes as a JSON (without content validation), similar to the Sensor and GenericAsset tables [see `PR #750 `_] +* The CLI now allows to set lists and dicts as asset & sensor attributes (formerly only single values) [see `PR #762 `_] Bugfixes -----------