From 1f6a119bcc3d63e979bc4de9d619e0d5ca555b12 Mon Sep 17 00:00:00 2001 From: Lukas Date: Sun, 28 Jun 2026 16:07:20 +0200 Subject: [PATCH] fix: parse dict strings from Robot Framework in ConfigUpdate Robot Framework's Create Dictionary converts nested dicts like {'enabled': False} to string representation. Parse these strings before Pydantic validation. Also handle Pydantic models passed directly from unit tests. --- src/server/models/config.py | 53 +++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/server/models/config.py b/src/server/models/config.py index 7f765f4..b3fb26f 100644 --- a/src/server/models/config.py +++ b/src/server/models/config.py @@ -289,6 +289,59 @@ class ConfigUpdate(BaseModel): scan_key_overrides: Optional[Dict[str, str]] = None other: Optional[Dict[str, Any]] = None + @classmethod + def _parse_dict_field(cls, v): + """Parse a field that may arrive as a malformed string from Robot Framework. + + Robot Framework's Create Dictionary converts Python-style nested dicts + like {'enabled': False} into their string representation. Handle that here + before Pydantic's type validation runs. Also handles Pydantic models being + passed directly (from unit tests). + """ + # Pydantic model - convert to dict first + if hasattr(v, 'model_dump'): + return v.model_dump() + if hasattr(v, 'dict'): + return v.dict() + # Already a dict + if isinstance(v, dict): + return v + # String - try parsing + if isinstance(v, str): + for parse_fn in (json.loads, ast.literal_eval): + try: + parsed = parse_fn(v) + if isinstance(parsed, dict): + return parsed + except Exception: + pass + return v + + @model_validator(mode="before") + @classmethod + def _pre_validate(cls, data): + """Handle malformed dict strings from Robot Framework and Pydantic models passed directly. + + Robot Framework's Create Dictionary converts Python-style nested dicts + like {'enabled': False} into their string representation. + Unit tests may pass Pydantic model instances directly. + Both cases need conversion before type validation. + """ + if isinstance(data, dict): + data = dict(data) # make mutable + for field in ("name", "data_dir", "scheduler", "logging", "backup", "nfo", "scan_key_overrides", "other"): + if field in data: + v = data[field] + # Pydantic model - convert to dict + if hasattr(v, "model_dump"): + data[field] = v.model_dump() + # String from Robot Framework - try parsing + elif isinstance(v, str): + parsed = cls._parse_dict_field(v) + if isinstance(parsed, dict): + data[field] = parsed + return data + def apply_to(self, current: AppConfig) -> AppConfig: """Return a new AppConfig with updates applied to the current config.