Skip to content

Commit

Permalink
wip: fix cdd and other unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Abel Aoun committed Feb 27, 2024
1 parent 10f2a1b commit e44e455
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 23 deletions.
45 changes: 31 additions & 14 deletions src/icclim/generic_indices/thresholds/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from collections.abc import Sequence
from typing import TYPE_CHECKING

from pint.errors import UndefinedUnitError
from xarray import DataArray, Dataset
from xclim.core.units import units as xc_units

Expand Down Expand Up @@ -34,6 +35,9 @@
if TYPE_CHECKING:
import pint

VALUE_REGEX = re.compile(r"-?\d+\.?\d*")
OPERAND_REGEX = re.compile(r"[^\w\s]")


def build_threshold(
query: str | None = None,
Expand Down Expand Up @@ -169,18 +173,32 @@ def build_threshold(
raise NotImplementedError(msg)


def _get_operator(query: str) -> tuple[Operator | None, str]:
operand = "".join(OPERAND_REGEX.findall(query))
op = OperatorRegistry.lookup(operand, no_error=True)
if op is not None:
return op, query.replace(op.operand, "", 1)
return None, query


def _read_string_threshold(query: str) -> tuple[str, str, float]:
value = re.findall(r"-?\d+\.?\d*", query)
if len(value) == 0:
msg = f"Cannot build threshold from '{query}'"
raise InvalidIcclimArgumentError(msg)
value = value[0]
value_index = query.find(value)
operator = query[0:value_index].strip()
if operator == "":
operator = None
unit = None if query.endswith(value) else query[value_index + len(value) :].strip()
return operator, unit, float(value)
op, no_op_query = _get_operator(query)
operand = op.operand if op else ""
if DOY_PERCENTILE_UNIT in no_op_query:
val = re.findall(VALUE_REGEX, no_op_query)[0]
unit = DOY_PERCENTILE_UNIT
elif PERIOD_PERCENTILE_UNIT in no_op_query:
val = re.findall(VALUE_REGEX, no_op_query)[0]
unit = PERIOD_PERCENTILE_UNIT
else:
try:
quantity = xc_units.Quantity(no_op_query)
except UndefinedUnitError as e:
msg = f"Could not build threshold from {query}"
raise InvalidIcclimArgumentError(msg) from e
val = quantity.m
unit = None if quantity.unitless else str(quantity.units)
return operand, unit, val


def _build_quantity(
Expand All @@ -202,8 +220,7 @@ def _build_quantity(
if operator is not None and operator != "":
msg = (
f"Cannot parse quantity '{quantity}'"
f" The operator {operator} is not needed here"
f" operator for this parameter."
f" The operator {operator} should be removed."
)
raise InvalidIcclimArgumentError(msg)
return xc_units.Quantity(value=value, units=unit)
Expand Down Expand Up @@ -332,7 +349,7 @@ def _read_bounded_threshold_query(query: str) -> ThresholdBuilderInput:
if link is None:
msg = f"No logical link found in {query}"
raise InvalidIcclimArgumentError(msg)
threshs = query.split(split_word)
threshs = [t.strip() for t in query.split(split_word)]
if len(threshs) != 2:
msg = (
"BoundedThreshold can only be built on 2"
Expand Down
2 changes: 1 addition & 1 deletion src/icclim/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -750,7 +750,7 @@ def read_indicator(user_index: UserIndexDict) -> GenericIndicator:
def read_thresholds(
user_index: UserIndexDict,
_build_threshold: Callable[[str | Threshold], Threshold],
) -> Threshold | None | Sequence[Threshold]:
) -> Threshold | None | list[Threshold]:
thresh = user_index.get("thresh", None)
if thresh is None or isinstance(thresh, Threshold):
return thresh
Expand Down
2 changes: 1 addition & 1 deletion src/icclim/models/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,4 @@ def catalog(cls) -> dict[str, T]:

@classmethod
def values(cls) -> list[T]:
return [v for k, v in cls.__dict__.items() if isinstance(v, cls._item_class)]
return [v for v in cls.__dict__.values() if isinstance(v, cls._item_class)]
2 changes: 1 addition & 1 deletion tests/test_generic_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,4 @@ def test_percentile():
resample_freq=FrequencyRegistry.MONTH,
is_compared_to_reference=False,
)
assert result[1] == -5
assert result[0] == -5
12 changes: 6 additions & 6 deletions tests/test_threshold.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,19 @@ def test_build_threshold__from_query():
assert isinstance(res, BasicThreshold)
assert res.operator == OperatorRegistry.GREATER
assert res.value == 10
assert res.unit == "degC"
assert res.unit == "°C"


def test_build_bounded_threshold__from_query():
res = build_threshold(">10degC and <20degC")
assert isinstance(res, BoundedThreshold)
assert res.left_threshold.operator == OperatorRegistry.GREATER
assert res.left_threshold.value == 10
assert res.left_threshold.unit == "degC"
assert res.left_threshold.unit == "°C"
assert res.logical_link == LogicalLinkRegistry.LOGICAL_AND
assert res.right_threshold.operator == OperatorRegistry.LOWER
assert res.right_threshold.value == 20
assert res.right_threshold.unit == "degC"
assert res.right_threshold.unit == "°C"


def test_build_bounded_threshold__unit_conversion():
Expand Down Expand Up @@ -83,7 +83,7 @@ def test_build_bounded_threshold__from_and():
assert isinstance(t3.left_threshold, BasicThreshold)
assert t3.left_threshold.operator == OperatorRegistry.GREATER
assert t3.left_threshold.value == 10
assert t3.left_threshold.unit == "degC"
assert t3.left_threshold.unit == "°C"
assert t3.logical_link == LogicalLinkRegistry.LOGICAL_AND
assert isinstance(t3.right_threshold, PercentileThreshold)
assert t3.right_threshold.is_ready is False
Expand All @@ -100,7 +100,7 @@ def test_build_bounded_threshold__from_or():
assert isinstance(t3.left_threshold, BasicThreshold)
assert t3.left_threshold.operator == OperatorRegistry.GREATER
assert t3.left_threshold.value == 10
assert t3.left_threshold.unit == "degC"
assert t3.left_threshold.unit == "°C"
assert t3.logical_link == LogicalLinkRegistry.LOGICAL_OR
assert isinstance(t3.right_threshold, PercentileThreshold)
assert t3.right_threshold.is_ready is False
Expand All @@ -120,7 +120,7 @@ def test_build_bounded_threshold__from_args():
assert isinstance(t3.left_threshold, BasicThreshold)
assert t3.left_threshold.operator == OperatorRegistry.GREATER
assert t3.left_threshold.value == 10
assert t3.left_threshold.unit == "degC"
assert t3.left_threshold.unit == "°C"
assert t3.logical_link == LogicalLinkRegistry.LOGICAL_OR
assert isinstance(t3.right_threshold, PercentileThreshold)
assert t3.right_threshold.is_ready is False
Expand Down

0 comments on commit e44e455

Please sign in to comment.