Skip to content

Commit 9be0c00

Browse files
committed
Line of Dict of Elements
Overwrite validation and model dump.
1 parent ac4f4bd commit 9be0c00

File tree

2 files changed

+52
-4
lines changed

2 files changed

+52
-4
lines changed

schema/BaseElement.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ class BaseElement(BaseModel):
1212
# not only when an instance of BaseElement is created
1313
model_config = ConfigDict(validate_assignment=True)
1414

15-
# Unique element name
16-
name: Optional[str] = None
15+
# element name
16+
name: str

schema/Line.py

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
from pydantic import BaseModel, ConfigDict, Field
2-
from typing import Annotated, List, Literal, Union
1+
from pydantic import BaseModel, ConfigDict, Field, field_validator
2+
from typing import Annotated, Dict, List, Literal, Union
33

44
from schema.BaseElement import BaseElement
55
from schema.ThickElement import ThickElement
@@ -30,5 +30,53 @@ class Line(BaseModel):
3030
]
3131

3232

33+
@field_validator("line", mode="before")
34+
@classmethod
35+
def parse_list_of_dicts(cls, value):
36+
"""This method inserts the key of the one-key dictionary into
37+
the name attribute of the elements"""
38+
if not isinstance(value, list):
39+
raise TypeError("line must be a list")
40+
41+
if value and isinstance(value[0], BaseModel):
42+
# Already a list of models; nothing to do
43+
return value
44+
45+
# Otherwise, treat as list of dicts
46+
elements = []
47+
for item_dict in value:
48+
if not (isinstance(item_dict, dict) and len(item_dict) == 1):
49+
raise ValueError(f"Each line element must be a dict with exactly one key, the name of the element, but we got: {item_dict!r}")
50+
[(name, fields)] = item_dict.items()
51+
52+
# an element is either a reference string to another element or a dict
53+
if not isinstance(fields, dict) and not isinstance(fields, str):
54+
raise ValueError(f"Value for element key '{name}' must be a dict or str (got {fields!r})")
55+
56+
# Insert the name into the fields dict
57+
fields["name"] = name
58+
elements.append(fields)
59+
return elements
60+
61+
62+
def model_dump(self, *args, **kwargs):
63+
"""This makes sure the element name property is moved out and up to a one-key dictionary"""
64+
# Use default dump for non-line fields
65+
data = super().model_dump(*args, **kwargs)
66+
67+
# Reformat 'line' field as list of single-key dicts
68+
new_line = []
69+
for elem in self.line:
70+
# The element's name is the dict key; dump all other fields except 'name'
71+
elem_dict = elem.model_dump(exclude={"name"}, **kwargs)
72+
name = getattr(elem, "name", None)
73+
if name is None:
74+
raise ValueError("Element missing 'name' attribute")
75+
new_line.append({name: elem_dict})
76+
77+
data["line"] = new_line
78+
return data
79+
80+
3381
# Avoid circular import issues
3482
Line.model_rebuild()

0 commit comments

Comments
 (0)