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.
This commit is contained in:
@@ -289,6 +289,59 @@ class ConfigUpdate(BaseModel):
|
|||||||
scan_key_overrides: Optional[Dict[str, str]] = None
|
scan_key_overrides: Optional[Dict[str, str]] = None
|
||||||
other: Optional[Dict[str, Any]] = 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:
|
def apply_to(self, current: AppConfig) -> AppConfig:
|
||||||
"""Return a new AppConfig with updates applied to the current config.
|
"""Return a new AppConfig with updates applied to the current config.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user