205 lines
8.5 KiB
Python
205 lines
8.5 KiB
Python
from datetime import datetime
|
|
import re
|
|
from typing import List, Optional, Tuple
|
|
|
|
class Attribute:
|
|
"""Base class for all attribute types."""
|
|
def __init__(
|
|
self,
|
|
attrib_name: str,
|
|
display_name: str,
|
|
html_input_type: str,
|
|
required: bool = False,
|
|
unique: bool = False,
|
|
primary: bool = False,
|
|
default_val: Optional[str] = None,
|
|
compareto: Optional[List[Tuple[str, str]]] = None,
|
|
):
|
|
self.attrib_name = attrib_name
|
|
self.display_name = display_name
|
|
self.html_input_type = html_input_type
|
|
self.required = required
|
|
self.unique = unique
|
|
self.primary = primary
|
|
self.default_val = default_val
|
|
self.compareto = compareto
|
|
|
|
def validate(self) -> Optional[str]:
|
|
"""Validate common attributes. Returns an error message if invalid, otherwise None."""
|
|
if not self.attrib_name:
|
|
return "Missing attribute name."
|
|
if not self.display_name:
|
|
return f"Missing display name for attribute '{self.attrib_name}'."
|
|
if not self.html_input_type:
|
|
return f"Missing input type for attribute '{self.attrib_name}'."
|
|
if self.html_input_type not in ["text", "number", "date", "select"]:
|
|
return f"Invalid input type for attribute '{self.attrib_name}'."
|
|
return None
|
|
|
|
|
|
class textAttribute(Attribute):
|
|
"""Class for text attributes."""
|
|
def __init__(
|
|
self,
|
|
attrib_name: str,
|
|
display_name: str,
|
|
regex: Optional[str] = None,
|
|
**kwargs
|
|
):
|
|
super().__init__(attrib_name, display_name, html_input_type="text", **kwargs)
|
|
self.regex = regex
|
|
|
|
def validate(self) -> Optional[str]:
|
|
"""Validate text-specific attributes."""
|
|
error = super().validate()
|
|
if error:
|
|
return error
|
|
if self.default_val is not None and self.regex is not None:
|
|
if not re.match(self.regex, str(self.default_val)):
|
|
return f"default_val does not match the regex pattern for attribute '{self.attrib_name}'."
|
|
return None
|
|
|
|
|
|
class intAttribute(Attribute):
|
|
"""Class for integer attributes."""
|
|
def __init__(
|
|
self,
|
|
attrib_name: str,
|
|
display_name: str,
|
|
min_val: Optional[int] = None,
|
|
max_val: Optional[int] = None,
|
|
**kwargs
|
|
):
|
|
super().__init__(attrib_name, display_name, html_input_type="number", **kwargs)
|
|
self.min_val = min_val
|
|
self.max_val = max_val
|
|
|
|
def validate(self) -> Optional[str]:
|
|
"""Validate integer-specific attributes."""
|
|
error = super().validate()
|
|
if error:
|
|
return error
|
|
if self.min_val is not None and not isinstance(self.min_val, int):
|
|
return f"min_val must be an integer for attribute '{self.attrib_name}'."
|
|
if self.max_val is not None and not isinstance(self.max_val, int):
|
|
return f"max_val must be an integer for attribute '{self.attrib_name}'."
|
|
if self.min_val is not None and self.max_val is not None and self.min_val > self.max_val:
|
|
return f"min_val cannot be greater than max_val for attribute '{self.attrib_name}'."
|
|
if self.default_val is not None and not isinstance(self.default_val, int):
|
|
return f"default_val must be an integer for attribute '{self.attrib_name}'."
|
|
if self.default_val is not None:
|
|
if self.min_val is not None and self.default_val < self.min_val:
|
|
return f"default_val cannot be less than min_val for attribute '{self.attrib_name}'."
|
|
if self.max_val is not None and self.default_val > self.max_val:
|
|
return f"default_val cannot be greater than max_val for attribute '{self.attrib_name}'."
|
|
return None
|
|
|
|
|
|
class floatAttribute(Attribute):
|
|
"""Class for float attributes."""
|
|
def __init__(
|
|
self,
|
|
attrib_name: str,
|
|
display_name: str,
|
|
min_val: Optional[float] = None,
|
|
max_val: Optional[float] = None,
|
|
**kwargs
|
|
):
|
|
super().__init__(attrib_name, display_name, html_input_type="number", **kwargs)
|
|
self.min_val = min_val
|
|
self.max_val = max_val
|
|
|
|
def validate(self) -> Optional[str]:
|
|
"""Validate float-specific attributes."""
|
|
error = super().validate()
|
|
if error:
|
|
return error
|
|
if self.min_val is not None and not isinstance(self.min_val, (int, float)):
|
|
return f"min_val must be a number for attribute '{self.attrib_name}'."
|
|
if self.max_val is not None and not isinstance(self.max_val, (int, float)):
|
|
return f"max_val must be a number for attribute '{self.attrib_name}'."
|
|
if self.min_val is not None and self.max_val is not None and self.min_val > self.max_val:
|
|
return f"min_val cannot be greater than max_val for attribute '{self.attrib_name}'."
|
|
if self.default_val is not None and not isinstance(self.default_val, (int, float)):
|
|
return f"default_val must be a number for attribute '{self.attrib_name}'."
|
|
if self.default_val is not None:
|
|
if self.min_val is not None and self.default_val < self.min_val:
|
|
return f"default_val cannot be less than min_val for attribute '{self.attrib_name}'."
|
|
if self.max_val is not None and self.default_val > self.max_val:
|
|
return f"default_val cannot be greater than max_val for attribute '{self.attrib_name}'."
|
|
return None
|
|
|
|
|
|
class dateAttribute(Attribute):
|
|
"""Class for date attributes."""
|
|
def __init__(
|
|
self,
|
|
attrib_name: str,
|
|
display_name: str,
|
|
min_val: Optional[str] = None,
|
|
max_val: Optional[str] = None,
|
|
**kwargs
|
|
):
|
|
super().__init__(attrib_name, display_name, html_input_type="date", **kwargs)
|
|
self.min_val = min_val
|
|
self.max_val = max_val
|
|
|
|
def _is_date(self, value: str) -> bool:
|
|
"""Check if a value is a valid date in YYYY-MM-DD format."""
|
|
try:
|
|
datetime.strptime(value, "%Y-%m-%d")
|
|
return True
|
|
except ValueError:
|
|
return False
|
|
|
|
def validate(self) -> Optional[str]:
|
|
"""Validate date-specific attributes."""
|
|
error = super().validate()
|
|
if error:
|
|
return error
|
|
if self.min_val is not None and not self._is_date(self.min_val):
|
|
return f"min_val must be a valid date (YYYY-MM-DD) for attribute '{self.attrib_name}'."
|
|
if self.max_val is not None and not self._is_date(self.max_val):
|
|
return f"max_val must be a valid date (YYYY-MM-DD) for attribute '{self.attrib_name}'."
|
|
if self.min_val is not None and self.max_val is not None:
|
|
min_date = datetime.strptime(self.min_val, "%Y-%m-%d")
|
|
max_date = datetime.strptime(self.max_val, "%Y-%m-%d")
|
|
if max_date < min_date:
|
|
return f"max_val cannot be earlier than min_val for attribute '{self.attrib_name}'."
|
|
if self.default_val is not None and not self._is_date(self.default_val):
|
|
return f"default_val must be a valid date (YYYY-MM-DD) for attribute '{self.attrib_name}'."
|
|
if self.default_val is not None:
|
|
default_date = datetime.strptime(self.default_val, "%Y-%m-%d")
|
|
if self.min_val is not None:
|
|
min_date = datetime.strptime(self.min_val, "%Y-%m-%d")
|
|
if default_date < min_date:
|
|
return f"default_val cannot be earlier than min_val for attribute '{self.attrib_name}'."
|
|
if self.max_val is not None:
|
|
max_date = datetime.strptime(self.max_val, "%Y-%m-%d")
|
|
if default_date > max_date:
|
|
return f"default_val cannot be later than max_val for attribute '{self.attrib_name}'."
|
|
return None
|
|
|
|
|
|
class selectAttribute(Attribute):
|
|
"""Class for select attributes."""
|
|
def __init__(
|
|
self,
|
|
attrib_name: str,
|
|
display_name: str,
|
|
options: List[str],
|
|
**kwargs
|
|
):
|
|
super().__init__(attrib_name, display_name, html_input_type="select", **kwargs)
|
|
self.options = options
|
|
|
|
def validate(self) -> Optional[str]:
|
|
"""Validate select-specific attributes."""
|
|
error = super().validate()
|
|
if error:
|
|
return error
|
|
if not self.options:
|
|
return f"options cannot be empty for attribute '{self.attrib_name}'."
|
|
if self.default_val is not None and self.default_val not in self.options:
|
|
return f"default_val must be one of the options for attribute '{self.attrib_name}'."
|
|
return None |