Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: let CLI users pass a JSON list (as a string) to set an asset or sensor attribute #762

Merged
merged 3 commits into from Jul 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions documentation/changelog.rst
Expand Up @@ -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 <https://www.github.com/FlexMeasures/flexmeasures/pull/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 <https://www.github.com/FlexMeasures/flexmeasures/pull/739>`_]
* DataSource table now allows storing arbitrary attributes as a JSON (without content validation), similar to the Sensor and GenericAsset tables [see `PR #750 <https://www.github.com/FlexMeasures/flexmeasures/pull/750>`_]
* The CLI now allows to set lists and dicts as asset & sensor attributes (formerly only single values) [see `PR #762 <https://www.github.com/FlexMeasures/flexmeasures/pull/762>`_]

Bugfixes
-----------
Expand Down
43 changes: 41 additions & 2 deletions flexmeasures/cli/data_edit.py
Expand Up @@ -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
Expand Down Expand Up @@ -78,6 +79,20 @@ 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(
"--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\"}'.",
)
nhoening marked this conversation as resolved.
Show resolved Hide resolved
@click.option(
"--null",
"attribute_null_value",
Expand All @@ -95,6 +110,8 @@ 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,
attribute_dict_value: str | None = None,
):
"""Edit (or add) an asset attribute or sensor attribute."""

Expand All @@ -107,6 +124,8 @@ 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_dict_value=attribute_dict_value,
attribute_null_value=attribute_null_value,
)

Expand Down Expand Up @@ -211,13 +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,
) -> float | int | bool | str | None:
attribute_list_value: str | None = None,
attribute_dict_value: str | None = None,
) -> float | int | bool | str | list | dict | None:
"""Parse attribute value."""
if not single_true(
[attribute_null_value]
Expand All @@ -228,6 +249,8 @@ def parse_attribute_value(
attribute_bool_value,
attribute_str_value,
attribute_int_value,
attribute_list_value,
attribute_dict_value,
]
]
):
Expand All @@ -240,6 +263,22 @@ 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
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


Expand Down