@@ -75,6 +75,7 @@ def loads(s: str, /, *, parse_float: ParseFloat = float) -> dict[str, Any]: # n
75
75
pos = 0
76
76
out = Output (NestedDict (), Flags ())
77
77
header : Key = ()
78
+ parse_float = make_safe_parse_float (parse_float )
78
79
79
80
# Parse one statement at a time
80
81
# (typically means one line in TOML source)
@@ -216,10 +217,9 @@ def append_nest_to_list(self, key: Key) -> None:
216
217
last_key = key [- 1 ]
217
218
if last_key in cont :
218
219
list_ = cont [last_key ]
219
- try :
220
- list_ .append ({})
221
- except AttributeError :
220
+ if not isinstance (list_ , list ):
222
221
raise KeyError ("An object other than list found behind this key" )
222
+ list_ .append ({})
223
223
else :
224
224
cont [last_key ] = [{}]
225
225
@@ -668,3 +668,24 @@ def coord_repr(src: str, pos: Pos) -> str:
668
668
669
669
def is_unicode_scalar_value (codepoint : int ) -> bool :
670
670
return (0 <= codepoint <= 55295 ) or (57344 <= codepoint <= 1114111 )
671
+
672
+
673
+ def make_safe_parse_float (parse_float : ParseFloat ) -> ParseFloat :
674
+ """A decorator to make `parse_float` safe.
675
+
676
+ `parse_float` must not return dicts or lists, because these types
677
+ would be mixed with parsed TOML tables and arrays, thus confusing
678
+ the parser. The returned decorated callable raises `ValueError`
679
+ instead of returning illegal types.
680
+ """
681
+ # The default `float` callable never returns illegal types. Optimize it.
682
+ if parse_float is float : # type: ignore[comparison-overlap]
683
+ return float
684
+
685
+ def safe_parse_float (float_str : str ) -> Any :
686
+ float_value = parse_float (float_str )
687
+ if isinstance (float_value , (dict , list )):
688
+ raise ValueError ("parse_float must not return dicts or lists" )
689
+ return float_value
690
+
691
+ return safe_parse_float
0 commit comments