1717- Several routines use an object-identity `visited` set to avoid infinite recursion when user inputs contain cycles.
1818"""
1919
20+ import copy
2021import typing as t
2122from collections import deque
2223from collections .abc import Mapping as ABCMapping
@@ -46,6 +47,13 @@ def _numeric_key_pairs(mapping: t.Mapping[t.Any, t.Any]) -> t.List[t.Tuple[int,
4647 return pairs
4748
4849
50+ def _copy_overflow_append_value (value : t .Any ) -> t .Any :
51+ """Copy container values before storing them in an overflow append slot."""
52+ if isinstance (value , (ABCMapping , list , tuple )):
53+ return copy .copy (value )
54+ return value
55+
56+
4957@dataclass
5058class _MergeFrame :
5159 target : t .Any
@@ -523,6 +531,14 @@ def combine(
523531 """
524532 Concatenate two values, treating non-sequences as singletons.
525533
534+ Normal list/tuple inputs are flattened into the combined result. When
535+ ``a`` is already an :class:`OverflowDict`, however, ``b`` is appended as
536+ one value at the next numeric key, even if ``b`` is a list, tuple, or
537+ another :class:`OverflowDict`. This preserves qs parity for duplicate
538+ values after list-limit overflow: a later comma-split or bracket-array
539+ payload remains a nested value instead of being flattened into the
540+ overflowed container.
541+
526542 If `list_limit` is exceeded, converts the list to an `OverflowDict`
527543 (a dict with numeric keys) to prevent memory exhaustion.
528544 When `options` is provided, its ``list_limit`` controls when a list is
@@ -537,33 +553,15 @@ def combine(
537553 list to :class:`OverflowDict`.
538554 """
539555 if Utils .is_overflow (a ):
540- # a is already an OverflowDict. Append b to a *copy* at the next numeric index.
541- # We assume sequential keys; len(a_copy) gives the next index.
556+ # a is already an OverflowDict. Append b as one value at the next numeric index.
542557 orig_a = t .cast (OverflowDict , a )
543558 a_copy = orig_a .__class__ ({k : v for k , v in orig_a .items () if not isinstance (v , Undefined )})
544559 # Use max key + 1 to handle sparse dicts safely, rather than len(a)
545560 key_pairs = _numeric_key_pairs (a_copy )
546561 idx = (max (key for key , _ in key_pairs ) + 1 ) if key_pairs else 0
547562
548- if isinstance (orig_a , CommaOverflowDict ):
549- if not isinstance (b , Undefined ):
550- a_copy [str (idx )] = b
551- elif isinstance (b , (list , tuple )):
552- for item in b :
553- if not isinstance (item , Undefined ):
554- a_copy [str (idx )] = item
555- idx += 1
556- elif Utils .is_overflow (b ):
557- b = t .cast (OverflowDict , b )
558- # Iterate in numeric key order to preserve list semantics
559- for _ , k in sorted (_numeric_key_pairs (b ), key = lambda item : item [0 ]):
560- val = b [k ]
561- if not isinstance (val , Undefined ):
562- a_copy [str (idx )] = val
563- idx += 1
564- else :
565- if not isinstance (b , Undefined ):
566- a_copy [str (idx )] = b
563+ if not isinstance (b , Undefined ):
564+ a_copy [str (idx )] = _copy_overflow_append_value (b )
567565 return a_copy
568566
569567 # Normal combination: flatten lists/tuples
0 commit comments