Source code for simstack.util.generate_ui_schema

from typing import Union


[docs] def generate_ui_schema(cls): """ Generates a UI schema that uses GenericForm for fields with ui_schema function. Also preserves any existing UI schema configurations from the class. Args: cls: The model class to generate UI schema for Returns: dict: The generated UI schema """ # Get base UI schema from the class if it exists base_schema = cls.ui_base_schema() if hasattr(cls, "ui_base_schema") else {} # Process each field in the model for field_name, field in cls.model_fields.items(): field_type = field.annotation # Unwrap Optional type to get the underlying type if hasattr(field_type, "__origin__") and field_type.__origin__ is Union: # Optional[X] is implemented as Union[X, None] args = field_type.__args__ if len(args) == 2 and args[1] is type(None): field_type = args[0] # Handle Lists by checking their inner type is_list = hasattr(field_type, "__origin__") and field_type.__origin__ is list if is_list: field_type = field_type.__args__[0] # Check for Optional inside List if hasattr(field_type, "__origin__") and field_type.__origin__ is Union: args = field_type.__args__ if len(args) == 2 and args[1] is type(None): field_type = args[0] # Check if field type has ui_schema method (this is true for all simstack_model classes) if hasattr(field_type, "ui_schema"): module_path = field_type.__module__ full_path = f"{module_path}.{field_type.__name__}" # if simstack is in the module path, skip all elements after the last simstack occurrence if "simstack" in module_path: full_path = ".".join( module_path[module_path.rfind("simstack") :].split(".") + [field_type.__name__] ) field_schema = field_type.ui_schema() # get the field schema for the field # Don't override if there's already a UI configuration for this field if field_name not in base_schema: if "ui:field" in field_schema: # If the field schema already has a ui:field, use it if is_list: base_schema[field_name] = {"items": field_schema} else: base_schema[field_name] = field_schema else: # Check if field type is a list ui_ref = { "ui:field": "GenericFormField", "ui:options": { "model": full_path, }, } # in rjsf the ui_scheme for list element must be in "items" key if is_list: base_schema[field_name] = {"items": ui_ref} else: ui_ref["ui:options"]["accordion"] = "true" base_schema[field_name] = ui_ref # Always hide the id field if it exists if "id" not in base_schema: base_schema["id"] = {"ui:widget": "hidden"} return base_schema