Source code for iota2.learning.utils

#!/usr/bin/env python3

# =========================================================================
#   Program:   iota2
#
#   Copyright (c) CESBIO. All rights reserved.
#
#   See LICENSE for details.
#
#   This software is distributed WITHOUT ANY WARRANTY; without even
#   the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
#   PURPOSE.  See the above copyright notices for more information.
#
# =========================================================================
"""Utility classes for labels"""
import re
from typing import ClassVar

import pandas as pd
from pydantic import BaseModel, validator


[docs]class I2Label(BaseModel): """Utility class to define labels.""" separator: ClassVar[str] = "_" sensor_name: str feat_name: str @validator("sensor_name", "feat_name") @classmethod def val_sensor_name(cls, value: str) -> str: """Validate sensor_name and feat_name attributes, values are lowered.""" pattern = r"[a-zA-z]*[0-9]*" matches = re.findall(pattern, value)[0:-1] if "" in matches: raise ValueError( f"sensor_name and feat_name must match regular expression '{pattern}'" ) if cls.separator in value: raise ValueError( f"'{cls.separator}' forbidden in sensor_name and feat_name " ) return value.lower() def __str__(self) -> str: return f"{self.sensor_name}{self.separator}{self.feat_name}"
[docs]class I2TemporalLabel(I2Label): """Utility class to define temporal labels.""" date: str @validator("date") @classmethod def val_date(cls, value: str) -> str: """Validate date attribute, returned as YYYYMMDD.""" # let pandas guess the incoming date format value_pd = pd.to_datetime(value, infer_datetime_format=True) out: str = value_pd.strftime("%Y%m%d") return out def __str__(self) -> str: return f"{self.sensor_name}{self.separator}{self.feat_name}{self.separator}{self.date}"
I2LabelAlias = I2Label | I2TemporalLabel
[docs]def i2_label_factory(label: str) -> I2LabelAlias: """Generate labels object.""" sep = I2Label.separator if len(label.split(sep)) == 2: out_label = I2Label.parse_obj(dict(zip(I2Label.__fields__, label.split(sep)))) elif len(label.split(sep)) == 3: out_label = I2TemporalLabel.parse_obj( dict(zip(I2TemporalLabel.__fields__, label.split(sep))) ) else: expected_templab = I2TemporalLabel.construct( sensor_name="sensorname", feat_name="featurename", date="date" ) expected_lab = I2Label.construct( sensor_name="sensorname", feat_name="featurename" ) raise ValueError( "Label is not formatted correctly. " f"Format labels as {expected_templab} " f"or {expected_lab}" ) return out_label # type: ignore
# mypy infers out_label as Any due to pydantic typing from parse_obj() method