Source code for fgen.data_models.multi_return

"""
Data model of a return value that contains multiple values
"""
from __future__ import annotations

from typing import Any, Optional, Union

from attrs import define, field

from fgen.data_models.unitless_value import UnitlessValue


[docs]@define class MultiReturn: # type: ignore # mypy confused by converter """ Data model for a return type that returns more than one value This defines the returned values' units, Fortran data type and other metadata. It is the combination of a :obj:`UnitlessValueDefinition` and information about the units of each returned value. """ definition: UnitlessValue """Definition of the value's key information""" unit: Optional[tuple[str, ...]] = field( # type: ignore # mypy confused by converter default=None, converter=lambda x: tuple(x) if x is not None and not isinstance(x, str) else x, ) """ Units of the returned values The units must be able to parsed by `pint` and be present in the :obj:`pint.UnitRegistry` being used by the application (normal rules for pint). Some examples include: "kg", "1 / month". A unit is required for all numeric-types (i.e. integer, real, complex). For non-numeric values, the unit is unused. """ dynamic_unit: Union[bool, str] = False """ Whether the units should be inferred dynamically, rather than statically Support for this is currently not implemented. If you require this feature, please raise an issue. """ @unit.validator def _check_unit(self, attribute: Any, value: tuple[str, ...] | None) -> None: if self.dynamic_unit: raise NotImplementedError() if self.definition.is_numeric_type: if value is None: raise ValueError( # noqa: TRY003 f"A unit is required for: {self.definition.name}" ) if not isinstance(value, tuple) or not all( isinstance(v, str) for v in value ): raise TypeError( # noqa: TRY003 f"The unit for {self.definition.name} must be a tuple of strings, " f"received: {value!r}" ) dimension_attribute_spec = ( self.definition.as_fortran_data_type().dimension_attribute_specification ) if dimension_attribute_spec is None: raise ValueError( # noqa: TRY003 "The Fortran method must return " "more than one value for this to work. " f"{self.definition.fortran_type=}" ) dimensions = dimension_attribute_spec.dimensions if len(dimensions) > 1: raise NotImplementedError( "Not sure which way to put the dimensions/units to make this work" ) if len(value) != dimensions[0]: raise ValueError( # noqa: TRY003 "The number of return units " "should match the number of returned values. " f"{value=} {dimensions=} {self.definition.fortran_type=}" ) @property def requires_units(self) -> bool: """ Whether this value requires units or not Returns ------- ``True`` if this value requires units, ``False`` otherwise. """ return (not self.dynamic_unit) and self.definition.is_numeric_type