88import tomli
99from pydantic import (
1010 BaseModel ,
11+ SerializationInfo ,
1112 computed_field ,
1213 model_serializer ,
1314 model_validator ,
@@ -28,16 +29,29 @@ class FieldBase(BaseModel):
2829 tagged : bool = True
2930
3031 @model_serializer (mode = "wrap" )
31- def _serialize (self , handler : Any ) -> dict [str , Any ]:
32+ def _serialize (self , handler : Any , info : SerializationInfo ) -> dict [str , Any ]:
3233 data = handler (self )
33- data .pop ("name" , None ) # name is the dict key in the parent container
34+ if info .context and info .context .get ("strip_names" ):
35+ data .pop ("name" , None )
3436 # `type` has a frozen default so exclude_defaults=True drops it; restore it.
3537 if "type" not in data and "type" in type (self ).model_fields :
3638 data = {"type" : getattr (self , "type" ), ** data }
3739 return data
3840
41+ def dump (self , * , strip_names : bool = True , ** kwargs ) -> dict [str , Any ]:
42+ if strip_names :
43+ kwargs ["context" ] = {** (kwargs .get ("context" ) or {}), "strip_names" : True }
44+ return self .model_dump (** kwargs )
45+
46+ def dump_json (self , * , strip_names : bool = True , ** kwargs ) -> str :
47+ if strip_names :
48+ kwargs ["context" ] = {** (kwargs .get ("context" ) or {}), "strip_names" : True }
49+ return self .model_dump_json (** kwargs )
50+
3951 @classmethod
40- def from_dict (cls , d : dict , strict : bool = False ) -> "FieldBase" :
52+ def from_dict (cls , d : dict , name : str | None = None , strict : bool = False ) -> "FieldBase" :
53+ if name is not None :
54+ d = {"name" : name , ** d }
4155 type_name = d .get ("type" )
4256 type_map : dict [str | None , type [FieldBase ]] = {
4357 "keyword" : Keyword ,
@@ -131,13 +145,14 @@ class List(FieldBase):
131145 shape : list [str ] = []
132146
133147 @model_serializer (mode = "wrap" )
134- def _serialize (self , handler : Any ) -> dict [str , Any ]:
148+ def _serialize (self , handler : Any , info : SerializationInfo ) -> dict [str , Any ]:
135149 data = handler (self )
136- data .pop ("name" , None ) # name is the dict key in Block.fields
150+ if info .context and info .context .get ("strip_names" ):
151+ data .pop ("name" , None )
137152 if "type" not in data :
138153 data = {"type" : "list" , ** data }
139- # item.name is stripped by FieldBase._serialize since item is a FieldBase subclass,
140- # but item is not stored as a dict key — re-inject its name .
154+ # item is stored as an attribute, not a dict key, so its name is never
155+ # implicit — always re-inject it regardless of strip_names .
141156 if "item" in data and isinstance (data ["item" ], dict ):
142157 data ["item" ] = {"name" : self .item .name , ** data ["item" ]}
143158 return data
@@ -359,6 +374,16 @@ def _serialize(self, handler: Any) -> dict[str, Any]:
359374 data .pop ("name" , None ) # name is the dict key in ComponentBase.blocks
360375 return data
361376
377+ def dump (self , * , strip_names : bool = True , ** kwargs ) -> dict [str , Any ]:
378+ if strip_names :
379+ kwargs ["context" ] = {** (kwargs .get ("context" ) or {}), "strip_names" : True }
380+ return self .model_dump (** kwargs )
381+
382+ def dump_json (self , * , strip_names : bool = True , ** kwargs ) -> str :
383+ if strip_names :
384+ kwargs ["context" ] = {** (kwargs .get ("context" ) or {}), "strip_names" : True }
385+ return self .model_dump_json (** kwargs )
386+
362387 @property
363388 def optional (self ) -> bool :
364389 return all (f .optional for f in self .fields .values ())
0 commit comments