Skip to content

Commit eeb96fa

Browse files
Only copy the items if they are sorted, and check the keys before sorting
The three writers now use a common helper. It builds a list only if the items are sorted, and if skipkeys is false it checks the type of keys before sorting, so that a dict with mixed keys is reported as "keys must be strings" instead of failing to compare the keys. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 9d970c8 commit eeb96fa

1 file changed

Lines changed: 28 additions & 19 deletions

File tree

Lib/plistlib.py

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,25 @@ def _date_to_string(d, aware_datetime):
159159
d.hour, d.minute, d.second
160160
)
161161

162+
def _dict_items(d, sort_keys, skipkeys):
163+
"""Return the (key, value) pairs of a dict, sorted if needed.
164+
165+
Sorting fails for keys of different types, so non-string keys are
166+
removed or reported before sorting.
167+
"""
168+
items = d.items()
169+
if sort_keys:
170+
if skipkeys:
171+
items = [item for item in items if isinstance(item[0], str)]
172+
items.sort()
173+
else:
174+
for key in d:
175+
if not isinstance(key, str):
176+
raise TypeError("keys must be strings")
177+
items = sorted(items)
178+
return items
179+
180+
162181
def _escape(text):
163182
m = _controlCharPat.search(text)
164183
if m is not None:
@@ -388,14 +407,11 @@ def write_bytes(self, data):
388407
def write_dict(self, d):
389408
if d:
390409
self.begin_element("dict")
391-
items = d.items()
392-
if self._skipkeys:
393-
items = [(k, v) for k, v in items if isinstance(k, str)]
394-
if self._sort_keys:
395-
items = sorted(items)
396-
410+
items = _dict_items(d, self._sort_keys, self._skipkeys)
397411
for key, value in items:
398412
if not isinstance(key, str):
413+
if self._skipkeys:
414+
continue
399415
raise TypeError("keys must be strings")
400416
self.simple_element("key", key)
401417
self.write_value(value)
@@ -717,14 +733,11 @@ def _flatten(self, value):
717733
if isinstance(value, (dict, frozendict)):
718734
keys = []
719735
values = []
720-
items = value.items()
721-
if self._skipkeys:
722-
items = [(k, v) for k, v in items if isinstance(k, str)]
723-
if self._sort_keys:
724-
items = sorted(items)
725-
736+
items = _dict_items(value, self._sort_keys, self._skipkeys)
726737
for k, v in items:
727738
if not isinstance(k, str):
739+
if self._skipkeys:
740+
continue
728741
raise TypeError("keys must be strings")
729742
keys.append(k)
730743
values.append(v)
@@ -838,15 +851,11 @@ def _write_object(self, value):
838851
elif isinstance(value, (dict, frozendict)):
839852
keyRefs, valRefs = [], []
840853

841-
rootItems = value.items()
842-
if self._skipkeys:
843-
rootItems = [(k, v) for k, v in rootItems
844-
if isinstance(k, str)]
845-
if self._sort_keys:
846-
rootItems = sorted(rootItems)
847-
854+
rootItems = _dict_items(value, self._sort_keys, self._skipkeys)
848855
for k, v in rootItems:
849856
if not isinstance(k, str):
857+
if self._skipkeys:
858+
continue
850859
raise TypeError("keys must be strings")
851860
keyRefs.append(self._getrefnum(k))
852861
valRefs.append(self._getrefnum(v))

0 commit comments

Comments
 (0)