Source code for ts_lib_parsy_components.value_unit

from dataclasses import dataclass
from typing import Callable, Generator, Optional

from task_script_utils.parse import to_float
from ts_ids_core.schema import RawValueUnit
from ts_lib_parsy import Parser, generate, regex, seq, success
from ts_lib_units import Unit, UnitParser

from ts_lib_parsy_components.base import scientific_or_float

_optional_open_bracket = regex(r"[\[\(]?").desc("open bracket")
_optional_close_bracket = regex(r"[\]\)]?").desc("close bracket")
_optional_spaces = regex("[ \t]*").desc("spaces and tabs")

_unit = regex(r"[\w/μ°Å%]+").desc("unit")


[docs] @dataclass class ValueUnitParser: """Parsers for raw value unit strings Args: unit_parser: A UnitParser object. value_fn: A parser for the raw value string. unit_fn: A parser for the raw unit string. float_converter: A function to convert the raw value string to a float. default_unit: The default unit to use if no unit is found. """ unit_parser: UnitParser value_parser: Parser[str] = scientific_or_float raw_unit_parser: Parser[str] = _unit float_converter: Callable[[str], Optional[float]] = to_float default_unit: str = Unit.ARBITRARY_UNIT
[docs] def value_optional_unit(self) -> Parser[RawValueUnit]: """Create a parser for RawValueUnit objects where the unit is optional with a default. Returns: A parser for RawValueUnit objects. """ return self.value_unit() | self.value()
[docs] def value_unit(self, raw_unit: Optional[str] = None) -> Parser[RawValueUnit]: """Create a parser for RawValueUnit objects, with a required unit. By default this function assumes that the unit appears after the value in the stream. If the unit appears elsewhere in the file, the `raw_unit` kwarg can be provided. The returned parser will parse the value string from the stream, but the input `raw_unit` will be used as the raw unit string, instead of parsing it from the stream. Keyword Arguments: `raw_unit` -- A raw unit string to accompany with value (default: {None}) Returns: A parser for RawValueUnit objects. """ @generate def parser() -> Generator[Parser[str], str, RawValueUnit]: """Parse a raw value unit string to a RawValueUnit object.""" if raw_unit is not None: # If raw_unit is provided, we don't need to parse it from the stream raw_value_parser = self.value_parser + success(" " + raw_unit) else: # If raw_unit is not provided, we parse it from the stream raw_value_parser = ( self.value_parser + _optional_spaces + _optional_open_bracket + self.raw_unit_parser + _optional_close_bracket ) raw_value = yield raw_value_parser extract_unit_parser = ( _optional_spaces >> _optional_open_bracket >> self.raw_unit_parser << _optional_close_bracket ) value, unit = seq(self.value_parser, extract_unit_parser).parse(raw_value) return RawValueUnit( raw_value=raw_value, value=self.float_converter(value), unit=self.unit_parser.parse(unit), ) return parser
[docs] def value(self, unit: Optional[Unit] = None) -> Parser[RawValueUnit]: """Create a parser for RawValueUnit objects, with a default unit. By default the unit is taken from the `default_unit` attribute. If you wish to override this default, you can provide a `unit` kwarg. Keyword Arguments: unit -- The unit to store alongside the value (default: {None}) Returns: A parser for RawValueUnit objects. """ @generate def parser() -> Generator[Parser[str], str, RawValueUnit]: """Parse a raw value string to a RawValueUnit object.""" value = yield self.value_parser return RawValueUnit( raw_value=value, value=self.float_converter(value), unit=unit or self.default_unit, ) return parser