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 |