# Copyright (c) 2025 Patrick Motsch # All rights reserved. """ Type definitions and utilities for frontend_options attribute. The frontend_options attribute supports two formats: 1. Static List: A list of option dictionaries for static options 2. String Reference: A string identifier that references dynamic options from /api/options/{optionsName} """ from typing import List, Dict, Any, Union try: from typing import TypeAlias # Python 3.10+ except ImportError: from typing_extensions import TypeAlias # Python < 3.10 # Type definition for a single option item OptionItem: TypeAlias = Dict[str, Any] """ Single option item format: { "value": str, # The value to be stored/returned "label": { # Multilingual labels "en": str, "fr": str, ... } } """ # Type definition for frontend_options - can be either a list or string reference FrontendOptions: TypeAlias = Union[List[OptionItem], str] """ frontend_options can be either: 1. List[OptionItem]: Static list of options Example: [{"value": "a", "label": {"en": "All", "fr": "Tous"}}] 2. str: String reference to dynamic options API Example: "user.role" -> Frontend fetches from /api/options/user.role """ def isStringReference(frontendOptions: FrontendOptions) -> bool: """ Check if frontend_options is a string reference (dynamic) or a list (static). Args: frontendOptions: The frontend_options value to check Returns: True if it's a string reference, False if it's a list """ return isinstance(frontendOptions, str) def isStaticList(frontendOptions: FrontendOptions) -> bool: """ Check if frontend_options is a static list or a string reference. Args: frontendOptions: The frontend_options value to check Returns: True if it's a static list, False if it's a string reference """ return isinstance(frontendOptions, list) def validateFrontendOptions(frontendOptions: FrontendOptions) -> bool: """ Validate that frontend_options is in the correct format. Args: frontendOptions: The frontend_options value to validate Returns: True if valid, False otherwise """ if isinstance(frontendOptions, str): # String reference: should be a non-empty string return bool(frontendOptions.strip()) elif isinstance(frontendOptions, list): # Static list: should contain option dictionaries if not frontendOptions: return True # Empty list is valid (no options) for option in frontendOptions: if not isinstance(option, dict): return False if "value" not in option: return False if "label" not in option: return False if not isinstance(option["label"], dict): return False return True else: return False def getOptionsName(frontendOptions: FrontendOptions) -> str: """ Get the options name from a string reference. Args: frontendOptions: The frontend_options value (must be a string reference) Returns: The options name (e.g., "user.role") Raises: ValueError: If frontendOptions is not a string reference """ if not isStringReference(frontendOptions): raise ValueError(f"frontend_options is not a string reference: {type(frontendOptions)}") return frontendOptions def getStaticOptions(frontendOptions: FrontendOptions) -> List[OptionItem]: """ Get the static options list. Args: frontendOptions: The frontend_options value (must be a static list) Returns: The list of option items Raises: ValueError: If frontendOptions is not a static list """ if not isStaticList(frontendOptions): raise ValueError(f"frontend_options is not a static list: {type(frontendOptions)}") return frontendOptions