@@ -1036,3 +1036,61 @@ def test_literal_dicts_msgspec():
10361036def test_literal_dicts_tomllib ():
10371037 """Dicts with keys that aren't subclasses of `type` work."""
10381038 test_literal_dicts (tomllib_make_converter )
1039+
1040+
1041+ @pytest .mark .parametrize (
1042+ "converter_factory" ,
1043+ [
1044+ json_make_converter ,
1045+ pyyaml_make_converter ,
1046+ ],
1047+ )
1048+ def test_decimal_round_trip (converter_factory : Callable [[], Converter ]):
1049+ """decimal.Decimal fields are serialized as strings and round-trip correctly."""
1050+ from decimal import Decimal
1051+
1052+ @define
1053+ class Order :
1054+ amount : Decimal
1055+
1056+ converter = converter_factory ()
1057+ order = Order (amount = Decimal ("19.99" ))
1058+
1059+ unstructured = converter .unstructure (order )
1060+ assert unstructured ["amount" ] == "19.99"
1061+ assert isinstance (unstructured ["amount" ], str )
1062+
1063+ restored = converter .structure (unstructured , Order )
1064+ assert restored == order
1065+ assert isinstance (restored .amount , Decimal )
1066+
1067+
1068+ def test_decimal_precision_preserved_json ():
1069+ """Decimal precision is preserved (not lost to float) in the json converter."""
1070+ from decimal import Decimal
1071+
1072+ @define
1073+ class Foo :
1074+ value : Decimal
1075+
1076+ converter = json_make_converter ()
1077+ # This value cannot be represented exactly as a float
1078+ original = Foo (value = Decimal ("0.1" ) + Decimal ("0.2" ))
1079+ restored = converter .structure (converter .unstructure (original ), Foo )
1080+ assert restored .value == original .value
1081+
1082+
1083+ def test_decimal_json_dumps_loads ():
1084+ """decimal.Decimal works end-to-end with JsonConverter.dumps()/loads()."""
1085+ from decimal import Decimal
1086+
1087+ @define
1088+ class Invoice :
1089+ total : Decimal
1090+ tax : Decimal
1091+
1092+ converter = json_make_converter ()
1093+ invoice = Invoice (total = Decimal ("99.99" ), tax = Decimal ("8.50" ))
1094+ s = converter .dumps (invoice )
1095+ restored = converter .loads (s , Invoice )
1096+ assert restored == invoice
0 commit comments