@@ -82,7 +82,9 @@ def _merge_configs(
8282 logger .debug (f'section `{ "." .join (sections )} ` already exists in { config } , skipping' )
8383 sections .pop ()
8484
85- def _sanitize_section (section : str ) -> str :
85+ def _sanitize_section (section : Any ) -> Any :
86+ if not isinstance (section , str ):
87+ return section
8688 if convert_keys_to_snake_case :
8789 logger .debug (f'converting section `{ section } ` to snake case' )
8890 section = _to_snake (section )
@@ -135,6 +137,7 @@ class ExtraBase(BaseModel):
135137 @model_validator (mode = 'before' )
136138 @classmethod
137139 def validator (cls , values : Any ) -> Any :
140+ values = {str (k ): v for k , v in values .items ()}
138141 if cls .model_config .get ('extra' ) == 'allow' :
139142 extra , valid = {}, {}
140143 for key , value in values .items ():
@@ -155,6 +158,11 @@ def extra_flat(self) -> Any:
155158 extra_flat .update (data )
156159 return extra_flat
157160
161+ def is_identifier (data : Any ) -> bool :
162+ if not isinstance (data , str ):
163+ return False
164+ return not keyword .iskeyword (data ) and data .isidentifier ()
165+
158166 def _model_and_stub_from_dict (
159167 name : str , data : Dict [str , Any ], path : Optional [List [str ]] = None
160168 ) -> Tuple [Type [ExtraBase ], str ]:
@@ -168,38 +176,35 @@ def _model_and_stub_from_dict(
168176 nested_stubs = []
169177 py_type : Any
170178 for section , entry in data .items ():
179+ if not is_identifier (section ):
180+ continue
171181 if isinstance (entry , Dict ):
172182 nested_model , nested_stub = _model_and_stub_from_dict (section , entry , path + [name ])
173- if not keyword .iskeyword (section ) and section .isidentifier ():
174- stub_lines .append (f' { section } : { class_name + section .capitalize ()} ' )
175- nested_stubs .append (nested_stub )
183+ stub_lines .append (f' { section } : { class_name + section .capitalize ()} ' )
184+ nested_stubs .append (nested_stub )
176185 fields [section ] = (nested_model , entry )
177186 elif isinstance (entry , list ) and entry :
178187 first_item = entry [0 ]
179188 if isinstance (first_item , Dict ):
180189 nested_model , nested_stub = _model_and_stub_from_dict (
181190 f'{ section .capitalize ()} _item' , first_item , path + [name ]
182191 )
183- if not keyword .iskeyword (section ) and section .isidentifier ():
184- stub_lines .append (f' { section } : list[{ class_name + section .capitalize ()} _item]' )
185- nested_stubs .append (nested_stub )
192+ stub_lines .append (f' { section } : list[{ class_name + section .capitalize ()} _item]' )
193+ nested_stubs .append (nested_stub )
186194 fields [section ] = (List [nested_model ], entry ) # type: ignore
187195 else :
188196 py_type = type (first_item )
189- if not keyword .iskeyword (section ) and section .isidentifier ():
190- stub_lines .append (f' { section } : list[{ py_type .__name__ } ]' )
197+ stub_lines .append (f' { section } : list[{ py_type .__name__ } ]' )
191198 fields [section ] = (List [py_type ], entry )
192199 elif isinstance (entry , list ):
193- if not keyword .iskeyword (section ) and section .isidentifier ():
194- stub_lines .append (f' { section } : list[Any]' )
200+ stub_lines .append (f' { section } : list[Any]' )
195201 fields [section ] = (List [Any ], entry )
196202 else :
197203 py_type = type (entry )
198- if not keyword .iskeyword (section ) and section .isidentifier ():
199- stub_lines .append (f' { section } : { py_type .__name__ } ' )
204+ stub_lines .append (f' { section } : { py_type .__name__ } ' )
200205 fields [section ] = (py_type , entry )
201206 if len (stub_lines ) == 1 :
202- stub_lines [ 0 ] += ' ...'
207+ stub_lines = [ f'class { class_name } (dict[Any, Any]): ...']
203208 stub_code = '\n \n ' .join (nested_stubs + ['\n ' .join (stub_lines )])
204209 return create_model (name , ** fields , __base__ = ExtraBase ), stub_code
205210
0 commit comments