From 594459f788d1d162c5e4a2a90f7c4d08cb1cd951 Mon Sep 17 00:00:00 2001 From: Laurent LAPORTE Date: Tue, 16 Apr 2024 15:48:48 +0200 Subject: [PATCH] feat(raw-study): add validators to validate geographic trimming filtering --- .../filesystem/config/field_validators.py | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 antarest/study/storage/rawstudy/model/filesystem/config/field_validators.py diff --git a/antarest/study/storage/rawstudy/model/filesystem/config/field_validators.py b/antarest/study/storage/rawstudy/model/filesystem/config/field_validators.py new file mode 100644 index 0000000000..74f93f5c46 --- /dev/null +++ b/antarest/study/storage/rawstudy/model/filesystem/config/field_validators.py @@ -0,0 +1,77 @@ +import typing as t + +_ALL_FILTERING = ["hourly", "daily", "weekly", "monthly", "annual"] + + +def extract_filtering(v: t.Any) -> t.Sequence[str]: + """ + Extract filtering values from a comma-separated list of values. + """ + + if v is None: + values = set() + elif isinstance(v, str): + values = {x.strip() for x in v.lower().split(",")} if v else set() + elif isinstance(v, (list, tuple)): + values = set(x.strip().lower() for x in v) + else: + raise TypeError(f"Invalid type for filtering: {type(v)!r}") + + try: + return sorted(values, key=lambda x: _ALL_FILTERING.index(x)) + except ValueError as e: + raise ValueError(f"Invalid value for filtering: {e!s}") from None + + +def validate_filtering(v: t.Any) -> str: + """ + Validate the filtering field and convert it to a comma separated string. + """ + + return ", ".join(extract_filtering(v)) + + +# noinspection SpellCheckingInspection +def validate_colors(values: t.MutableMapping[str, t.Any]) -> t.Mapping[str, t.Any]: + """ + Validate ``color_rgb``, ``color_r``, ``color_g``, ``color_b`` and convert them to ``color_rgb``. + """ + + def _pop_any(dictionary: t.MutableMapping[str, t.Any], *keys: str) -> t.Any: + """Save as `pop` but for multiple keys. Return the first found value.""" + return next((dictionary.pop(key, None) for key in keys if key in dictionary), None) + + color_r = _pop_any(values, "color_r", "colorr") + color_g = _pop_any(values, "color_g", "colorg") + color_b = _pop_any(values, "color_b", "colorb") + if color_r is not None and color_g is not None and color_b is not None: + values["color_rgb"] = color_r, color_g, color_b + return values + + +def validate_color_rgb(v: t.Any) -> str: + """ + Validate RGB color field and convert it to color code. + + Accepts: + - a string in the format "#RRGGBB" + - a string in the format "rgb(R, G, B)" + - a string in the format "R, G, B" + - a list or tuple of 3 integers + """ + + if isinstance(v, str): + if v.startswith("#"): + r = int(v[1:3], 16) + g = int(v[3:5], 16) + b = int(v[5:7], 16) + elif v.startswith("rgb("): + r, g, b = [int(c) for c in v[4:-1].split(",")] + else: + r, g, b = [int(c) for c in v.split(",")] + elif isinstance(v, (list, tuple)): + r, g, b = map(int, v) + else: + raise TypeError(f"Invalid type for 'color_rgb': {type(v)}") + + return f"#{r:02X}{g:02X}{b:02X}"