Skip to content

Commit

Permalink
Add validate to DataType to check value against min/max
Browse files Browse the repository at this point in the history
  • Loading branch information
evalott100 committed Nov 21, 2024
1 parent e9b776b commit 546934a
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 19 deletions.
14 changes: 8 additions & 6 deletions src/fastcs/attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from enum import Enum
from typing import Any, Generic, Protocol, runtime_checkable

from .datatypes import ATTRIBUTE_TYPES, AttrCallback, DataType, T, validate_value
from .datatypes import ATTRIBUTE_TYPES, AttrCallback, DataType, T


class AttrMode(Enum):
Expand Down Expand Up @@ -126,15 +126,17 @@ def __init__(
allowed_values=allowed_values, # type: ignore
description=description,
)
self._value: T = datatype.dtype() if initial_value is None else initial_value
self._value: T = (
datatype.initial_value if initial_value is None else initial_value
)
self._update_callback: AttrCallback[T] | None = None
self._updater = handler

def get(self) -> T:
return self._value

async def set(self, value: T) -> None:
self._value = self._datatype.dtype(validate_value(self._datatype, value))
self._value = self._datatype.validate(value)

if self._update_callback is not None:
await self._update_callback(self._value)
Expand Down Expand Up @@ -177,11 +179,11 @@ async def process(self, value: T) -> None:

async def process_without_display_update(self, value: T) -> None:
if self._process_callback is not None:
await self._process_callback(self._datatype.dtype(value))
await self._process_callback(self._datatype.validate(value))

async def update_display_without_process(self, value: T) -> None:
if self._write_display_callback is not None:
await self._write_display_callback(self._datatype.dtype(value))
await self._write_display_callback(self._datatype.validate(value))

def set_process_callback(self, callback: AttrCallback[T] | None) -> None:
self._process_callback = callback
Expand Down Expand Up @@ -221,6 +223,6 @@ def __init__(
)

async def process(self, value: T) -> None:
await self.set(validate_value(self._datatype, value))
await self.set(value)

await super().process(value) # type: ignore
27 changes: 14 additions & 13 deletions src/fastcs/datatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from dataclasses import dataclass
from typing import Generic, TypeVar

T_Numerical = TypeVar("T_Numerical", int, float)
T = TypeVar("T", int, float, bool, str)
ATTRIBUTE_TYPES: tuple[type] = T.__constraints__ # type: ignore

Expand All @@ -21,8 +22,13 @@ class DataType(Generic[T]):
def dtype(self) -> type[T]: # Using property due to lack of Generic ClassVars
pass

def validate(self, value: T) -> T:
"""Validate a value against fields in the datatype."""
return value

T_Numerical = TypeVar("T_Numerical", int, float)
@property
def initial_value(self) -> T:
return self.dtype()


@dataclass(frozen=True)
Expand All @@ -33,6 +39,13 @@ class _Numerical(DataType[T_Numerical]):
min_alarm: int | None = None
max_alarm: int | None = None

def validate(self, value: T_Numerical) -> T_Numerical:
if self.min is not None and value < self.min:
raise ValueError(f"Value {value} is less than minimum {self.min}")

Check warning on line 44 in src/fastcs/datatypes.py

View check run for this annotation

Codecov / codecov/patch

src/fastcs/datatypes.py#L44

Added line #L44 was not covered by tests
if self.max is not None and value > self.max:
raise ValueError(f"Value {value} is greater than maximum {self.max}")

Check warning on line 46 in src/fastcs/datatypes.py

View check run for this annotation

Codecov / codecov/patch

src/fastcs/datatypes.py#L46

Added line #L46 was not covered by tests
return value


@dataclass(frozen=True)
class Int(_Numerical[int]):
Expand Down Expand Up @@ -73,15 +86,3 @@ class String(DataType[str]):
@property
def dtype(self) -> type[str]:
return str


def validate_value(datatype: DataType[T], value: T) -> T:
"""Validate a value against a datatype."""

if isinstance(datatype, (Int | Float)):
assert isinstance(value, (int | float)), f"Value {value} is not a number"
if datatype.min is not None and value < datatype.min:
raise ValueError(f"Value {value} is less than minimum {datatype.min}")
if datatype.max is not None and value > datatype.max:
raise ValueError(f"Value {value} is greater than maximum {datatype.max}")
return value

0 comments on commit 546934a

Please sign in to comment.