@@ -101,31 +101,28 @@ def test_make_engine_value_converter_basic_types():
101101 converter = build_engine_value_converter (engine_type_in_py )
102102 assert converter (value ) == value
103103
104- def test_make_engine_value_converter_struct ():
105- converter = build_engine_value_converter (Order )
106- # All fields match
107- engine_val = ["O123" , "mixed nuts" , 25.0 , "default_extra" ]
108- assert converter (engine_val ) == Order ("O123" , "mixed nuts" , 25.0 , "default_extra" )
109- # Extra field in Python dataclass (should ignore extra)
110- engine_val_extra = ["O123" , "mixed nuts" , 25.0 , "default_extra" , "unexpected" ]
111- assert converter (engine_val_extra ) == Order ("O123" , "mixed nuts" , 25.0 , "default_extra" )
112- # Fewer fields in engine value (should fill with default, so provide all fields)
113- engine_val_short = ["O123" , "mixed nuts" , 0.0 , "default_extra" ]
114- assert converter (engine_val_short ) == Order ("O123" , "mixed nuts" , 0.0 , "default_extra" )
115- # More fields in engine value (should ignore extra)
116- engine_val_long = ["O123" , "mixed nuts" , 25.0 , "unexpected" ]
117- assert converter (engine_val_long ) == Order ("O123" , "mixed nuts" , 25.0 , "unexpected" )
118- # Truly extra field (should ignore the fifth field)
119- engine_val_extra_long = ["O123" , "mixed nuts" , 25.0 , "default_extra" , "ignored" ]
120- assert converter (engine_val_extra_long ) == Order ("O123" , "mixed nuts" , 25.0 , "default_extra" )
121-
122- def test_make_engine_value_converter_struct_field_order ():
123- # Engine fields in different order
124- # Use encode_enriched_type to avoid manual mistakes
125- converter = build_engine_value_converter (Order )
126- # Provide all fields in the correct order
127- engine_val = ["O123" , "mixed nuts" , 25.0 , "default_extra" ]
128- assert converter (engine_val ) == Order ("O123" , "mixed nuts" , 25.0 , "default_extra" )
104+ @pytest .mark .parametrize (
105+ "converter_type, engine_val, expected" ,
106+ [
107+ # All fields match
108+ (Order , ["O123" , "mixed nuts" , 25.0 , "default_extra" ], Order ("O123" , "mixed nuts" , 25.0 , "default_extra" )),
109+ # Extra field in engine value (should ignore extra)
110+ (Order , ["O123" , "mixed nuts" , 25.0 , "default_extra" , "unexpected" ], Order ("O123" , "mixed nuts" , 25.0 , "default_extra" )),
111+ # Fewer fields in engine value (should fill with default)
112+ (Order , ["O123" , "mixed nuts" , 0.0 , "default_extra" ], Order ("O123" , "mixed nuts" , 0.0 , "default_extra" )),
113+ # More fields in engine value (should ignore extra)
114+ (Order , ["O123" , "mixed nuts" , 25.0 , "unexpected" ], Order ("O123" , "mixed nuts" , 25.0 , "unexpected" )),
115+ # Truly extra field (should ignore the fifth field)
116+ (Order , ["O123" , "mixed nuts" , 25.0 , "default_extra" , "ignored" ], Order ("O123" , "mixed nuts" , 25.0 , "default_extra" )),
117+ # Missing optional field in engine value (tags=None)
118+ (Customer , ["Alice" , ["O1" , "item1" , 10.0 , "default_extra" ], None ], Customer ("Alice" , Order ("O1" , "item1" , 10.0 , "default_extra" ), None )),
119+ # Extra field in engine value for Customer (should ignore)
120+ (Customer , ["Alice" , ["O1" , "item1" , 10.0 , "default_extra" ], [["vip" ]], "extra" ], Customer ("Alice" , Order ("O1" , "item1" , 10.0 , "default_extra" ), [Tag ("vip" )])),
121+ ]
122+ )
123+ def test_struct_conversion_cases (converter_type , engine_val , expected ):
124+ converter = build_engine_value_converter (converter_type )
125+ assert converter (engine_val ) == expected
129126
130127def test_make_engine_value_converter_collections ():
131128 # List of structs
@@ -152,74 +149,6 @@ def test_make_engine_value_converter_collections():
152149 2
153150 )
154151
155- def test_make_engine_value_converter_defaults_and_missing_fields ():
156- # Missing optional field in engine value
157- converter = build_engine_value_converter (Customer )
158- engine_val = ["Alice" , ["O1" , "item1" , 10.0 , "default_extra" ], None ] # tags explicitly None
159- assert converter (engine_val ) == Customer ("Alice" , Order ("O1" , "item1" , 10.0 , "default_extra" ), None )
160- # Extra field in engine value (should ignore)
161- engine_val = ["Alice" , ["O1" , "item1" , 10.0 , "default_extra" ], [["vip" ]], "extra" ]
162- assert converter (engine_val ) == Customer ("Alice" , Order ("O1" , "item1" , 10.0 , "default_extra" ), [Tag ("vip" )])
163-
164- def test_engine_python_schema_field_order ():
165- """
166- Engine and Python dataclasses have the same fields but different order.
167- Converter should map by field name, not order.
168- """
169- @dataclass
170- class EngineOrder :
171- id : str
172- name : str
173- price : float
174- @dataclass
175- class PythonOrder :
176- name : str
177- id : str
178- price : float
179- extra : str = "default"
180- converter = build_engine_value_converter (EngineOrder , PythonOrder )
181- engine_val = ["O123" , "mixed nuts" , 25.0 ] # matches EngineOrder order
182- assert converter (engine_val ) == PythonOrder ("mixed nuts" , "O123" , 25.0 , "default" )
183-
184- def test_engine_python_schema_extra_field ():
185- """
186- Python dataclass has an extra field not present in engine schema.
187- Converter should fill with default value.
188- """
189- @dataclass
190- class EngineOrder :
191- id : str
192- name : str
193- @dataclass
194- class PythonOrder :
195- id : str
196- name : str
197- price : float = 0.0
198- converter = build_engine_value_converter (EngineOrder , PythonOrder )
199- engine_val = ["O123" , "mixed nuts" ]
200- assert converter (engine_val ) == PythonOrder ("O123" , "mixed nuts" , 0.0 )
201-
202- def test_engine_python_schema_missing_field ():
203- """
204- Engine dataclass has a field missing in Python dataclass.
205- Converter should ignore the missing field.
206- """
207- from dataclasses import dataclass
208- @dataclass
209- class EngineOrder :
210- id : str
211- name : str
212- price : float
213- @dataclass
214- class PythonOrder :
215- id : str
216- name : str
217- converter = build_engine_value_converter (EngineOrder , PythonOrder )
218- engine_val = ["O123" , "mixed nuts" , 25.0 ]
219- assert converter (engine_val ) == PythonOrder ("O123" , "mixed nuts" )
220-
221-
222-
223152def make_engine_order (fields ):
224153 return make_dataclass ('EngineOrder' , fields )
225154
@@ -269,6 +198,30 @@ def make_python_order(fields, defaults=None):
269198 ["unexpected" , "mixed nuts" , 25.0 ],
270199 ("mixed nuts" , 25.0 ),
271200 ),
201+ # Field order difference (should map by name)
202+ (
203+ [("id" , str ), ("name" , str ), ("price" , float )],
204+ [("name" , str ), ("id" , str ), ("price" , float ), ("extra" , str )],
205+ {"extra" : "default" },
206+ ["O123" , "mixed nuts" , 25.0 ],
207+ ("mixed nuts" , "O123" , 25.0 , "default" ),
208+ ),
209+ # Extra field (Python has extra field with default)
210+ (
211+ [("id" , str ), ("name" , str )],
212+ [("id" , str ), ("name" , str ), ("price" , float )],
213+ {"price" : 0.0 },
214+ ["O123" , "mixed nuts" ],
215+ ("O123" , "mixed nuts" , 0.0 ),
216+ ),
217+ # Missing field (Engine has extra field)
218+ (
219+ [("id" , str ), ("name" , str ), ("price" , float )],
220+ [("id" , str ), ("name" , str )],
221+ {},
222+ ["O123" , "mixed nuts" , 25.0 ],
223+ ("O123" , "mixed nuts" ),
224+ ),
272225 ]
273226)
274227def test_field_position_cases (engine_fields , python_fields , python_defaults , engine_val , expected_python_val ):
0 commit comments