Skip to main content
Glama
settings_model_generator.py5.94 kB
""" Dynamic model generator based on CONFIG_METADATA Generates SQLModel classes dynamically from configuration metadata, eliminating hardcoded model definitions. """ from typing import Dict, Any, Optional, Type, Tuple from sqlmodel import SQLModel, Field from pydantic import field_validator, create_model from config.constants import CONFIG_METADATA, ConfigType class SettingModelGenerator: """Dynamic model generator""" @staticmethod def _get_python_type(config_type: ConfigType, required: bool = True) -> Type: """Convert ConfigType to Python type""" type_mapping = { ConfigType.STRING: str, ConfigType.INTEGER: int, ConfigType.FLOAT: float, ConfigType.BOOLEAN: bool } base_type = type_mapping[config_type] return base_type if required else Optional[base_type] @staticmethod def _create_encrypted_property(field_name: str): """Create property method for encrypted fields""" from .crypto import crypto_manager encrypted_field_name = f"{field_name}_encrypted" def getter(self): encrypted_value = getattr(self, encrypted_field_name, None) if not encrypted_value: return "" if field_name.endswith('_key') else "" return crypto_manager.decrypt(encrypted_value) def setter(self, value: str): encrypted_value = crypto_manager.encrypt(value) if value else "" setattr(self, encrypted_field_name, encrypted_value) return property(getter, setter) @classmethod def _generate_filed( cls, key: str, metadata: Dict[str, Any], is_optional: bool = False ) -> Tuple[Type, Field]: metadata = CONFIG_METADATA[key] field_type = None field_properties : Dict[str, Any] = {} if metadata.get('sensitive', False): field_type = cls._get_python_type(ConfigType.STRING, metadata.get('required', False)) if not metadata.get('required', False): field_properties['default'] = None else: field_type = cls._get_python_type(metadata['type'], metadata.get('required', False)) if 'default' in metadata: field_properties['default'] = metadata['default'] elif not metadata.get('required', False): field_properties['default'] = None if metadata.get('nullable', False): field_properties['nullable'] = True # Handle validation, validation rules are defined in metadata if metadata.get('validation'): for key, value in metadata['validation'].items(): field_properties[key] = value # If optional field, set default value to None and make it nullable if is_optional: field_properties['default'] = None field_properties['nullable'] = True if field_properties: return field_type, Field(**field_properties) else: return field_type, Field() @classmethod def create_setting_model(cls) -> Type[SQLModel]: """Dynamically create Setting model""" from .crypto import crypto_manager # Prepare field definitions fields = {} # Add id field fields['id'] = (Optional[int], Field(default=None, primary_key=True)) # Handle configuration fields for key, metadata in CONFIG_METADATA.items(): field_key = key if not metadata.get('sensitive', False) else f"{key}_encrypted" field_type, field = cls._generate_filed(key, metadata) fields[field_key] = (field_type, field) # Use create_model to create base model Setting = create_model( 'Setting', __base__=SQLModel, __cls_kwargs__={"table": True}, **fields ) # Add properties for sensitive fields for key, metadata in CONFIG_METADATA.items(): if metadata.get('sensitive', False): prop = cls._create_encrypted_property(key) setattr(Setting, key, prop) return Setting @classmethod def create_setting_response_model(cls) -> Type[SQLModel]: """Dynamically create SettingResponse model""" # Use create_model to create response model fields = {'id': (int, ...)} for key, metadata in CONFIG_METADATA.items(): # Response models use original key names (sensitive fields are accessed through properties for decryption) field_type = cls._get_python_type(metadata['type'], required=False) default_value = metadata.get('default') if default_value is not None: fields[key] = (field_type, default_value) else: fields[key] = (field_type, None) return create_model( 'SettingResponse', __base__=SQLModel, **fields ) @classmethod def create_setting_update_model(cls) -> Type[SQLModel]: """Dynamically create SettingUpdate model""" fields = {} for key, metadata in CONFIG_METADATA.items(): # All fields in update model are optional field_type, field = cls._generate_filed(key, metadata, is_optional=True) fields[key] = (field_type, field) # Create model SettingUpdate = create_model( 'SettingUpdate', __base__=SQLModel, **fields ) return SettingUpdate # Generate model instances Setting = SettingModelGenerator.create_setting_model() SettingResponse = SettingModelGenerator.create_setting_response_model() SettingUpdate = SettingModelGenerator.create_setting_update_model()

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/itcook/graphiti-mcp-pro'

If you have feedback or need assistance with the MCP directory API, please join our Discord server