Skip to content

Commit

Permalink
Merge pull request #90 from BIH-CEI/88-implement-post-init-in-date-an…
Browse files Browse the repository at this point in the history
…d-value-instance

88 implement post init in date and value instance
  • Loading branch information
frehburg authored Sep 18, 2024
2 parents 3c396ed + 325d23c commit f3ff7ea
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 40 deletions.
19 changes: 18 additions & 1 deletion src/phenopacket_mapper/data_standards/data_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from pathlib import Path
from types import MappingProxyType
from typing import Union, List, Literal, Dict
import warnings

from phenopacket_mapper.data_standards import CodeSystem
from phenopacket_mapper.data_standards.date import Date
Expand Down Expand Up @@ -72,10 +73,12 @@ def validate(self) -> bool:
:return: True if the instance is valid, False otherwise
"""
if self.field.required and self.value is None:
warnings.warn(f"Field {self.field.name} is required but has no value")
return False
if self.value is not None and self.field.value_set:
if self.value in self.field.value_set:
return True
warnings.warn(f"Value {self.value} is not in the value set of field {self.field.name}")
return False


Expand Down Expand Up @@ -189,9 +192,16 @@ class DataModelInstance:
:ivar data_model: The `DataModel` object that defines the data model for this instance
:ivar values: A list of `DataFieldValue` objects, each adhering to the `DataField` definition in the `DataModel`
:ivar compliance: Compliance level to enforce when validating the instance. If 'soft', the instance can have extra
fields that are not in the DataModel. If 'hard', the instance must have all fields in the
DataModel.
"""
data_model: DataModel
values: List[DataFieldValue]
compliance: Literal['soft', 'hard'] = 'soft'

def __post_init__(self):
self.validate()

def validate(self) -> bool:
"""Validates the data model instance based on data model definition
Expand All @@ -201,7 +211,14 @@ def validate(self) -> bool:
:return: True if the instance is valid, False otherwise
"""
error_msg = f"Instance values do not comply with their respective fields' valuesets. {self}"
for v in self.values:
if not v.validate():
return False
if self.compliance == 'hard':
raise ValueError(error_msg)
elif self.compliance == 'soft':
warnings.warn(error_msg)
return False
else:
raise ValueError(f"Compliance level {self.compliance} is not valid")
return True
61 changes: 22 additions & 39 deletions src/phenopacket_mapper/data_standards/date.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from dataclasses import dataclass
from dataclasses import dataclass, field
from datetime import datetime
from typing import Tuple, Union, Literal

Expand All @@ -21,7 +21,7 @@ def _check_invalid_padd_zeros(value: int, places: int = 2, valid_range: Tuple[in
return f'{value:0{places}d}'


@dataclass
@dataclass(init=True, eq=True, order=True, repr=False, slots=True)
class Date:
"""Data class for Date
Expand All @@ -35,44 +35,27 @@ class Date:
:ivar minute: the minute of the date
:ivar second: the second of the date
"""
year: int
month: int
day: int
hour: int
minute: int
second: int

def __init__(
self,
year: int = 0, month: int = 0, day: int = 0,
hour: int = 0, minute: int = 0, second: int = 0
):
"""
Constructor for Date class
Initializes the fields and their string representations, padding them with zeros if necessary. If no values are
provided, the fields are initialized to 0.
:param year: year 0-9999
:param month: 1 - 12
:param day: 1 - 31
:param hour:
:param minute:
:param second:
"""
self.year = year
self.month = month
self.day = day
self.hour = hour
self.minute = minute
self.second = second
self.year_str = _check_invalid_padd_zeros(year)
self.month_str = _check_invalid_padd_zeros(month, valid_range=(0, 12))
self.day_str = _check_invalid_padd_zeros(day, valid_range=(0, 31))
year: int = field(default=0)
month: int = field(default=0)
day: int = field(default=0)
hour: int = field(default=0)
minute: int = field(default=0)
second: int = field(default=0)
year_str: str = field(init=False)
month_str: str = field(init=False)
day_str: str = field(init=False)
hour_str: str = field(init=False)
minute_str: str = field(init=False)
second_str: str = field(init=False)

def __post_init__(self):
self.year_str = _check_invalid_padd_zeros(self.year)
self.month_str = _check_invalid_padd_zeros(self.month, valid_range=(0, 12))
self.day_str = _check_invalid_padd_zeros(self.day, valid_range=(0, 31))
self._check_invalid_day_month_combinations()
self.hour_str = _check_invalid_padd_zeros(hour, valid_range=(0, 23))
self.minute_str = _check_invalid_padd_zeros(minute, valid_range=(0, 59))
self.second_str = _check_invalid_padd_zeros(second, valid_range=(0, 59))
self.hour_str = _check_invalid_padd_zeros(self.hour, valid_range=(0, 23))
self.minute_str = _check_invalid_padd_zeros(self.minute, valid_range=(0, 59))
self.second_str = _check_invalid_padd_zeros(self.second, valid_range=(0, 59))

def _check_invalid_day_month_combinations(self):
# check month specific day month combinations
Expand Down

0 comments on commit f3ff7ea

Please sign in to comment.