Skip to content

Commit 4be4b0a

Browse files
authored
Update annotationlib.py
Fix inconsistent set ordering in annotations (GH-133682)
1 parent 1cef6e5 commit 4be4b0a

File tree

1 file changed

+42
-9
lines changed

1 file changed

+42
-9
lines changed

Lib/annotationlib.py

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -371,11 +371,33 @@ def __convert_to_ast(self, other):
371371
elif type(other) in (list, tuple, set):
372372
extra_names = {}
373373
elts = []
374-
for elt in other:
375-
new_elt, new_extra_names = self.__convert_to_ast(elt)
376-
if new_extra_names is not None:
377-
extra_names.update(new_extra_names)
378-
elts.append(new_elt)
374+
375+
# For sets, we need to ensure consistent ordering
376+
if type(other) is set:
377+
# For sets of types, sort by __name__
378+
if all(isinstance(x, type) for x in other):
379+
# Sort the elements by name
380+
sorted_elts = sorted(other, key=lambda x: x.__name__)
381+
for elt in sorted_elts:
382+
new_elt, new_extra_names = self.__convert_to_ast(elt)
383+
if new_extra_names is not None:
384+
extra_names.update(new_extra_names)
385+
elts.append(new_elt)
386+
else:
387+
# For other sets, just use the original order
388+
for elt in other:
389+
new_elt, new_extra_names = self.__convert_to_ast(elt)
390+
if new_extra_names is not None:
391+
extra_names.update(new_extra_names)
392+
elts.append(new_elt)
393+
else:
394+
# For lists and tuples, preserve the original order
395+
for elt in other:
396+
new_elt, new_extra_names = self.__convert_to_ast(elt)
397+
if new_extra_names is not None:
398+
extra_names.update(new_extra_names)
399+
elts.append(new_elt)
400+
379401
ast_class = {list: ast.List, tuple: ast.Tuple, set: ast.Set}[type(other)]
380402
return ast_class(elts), extra_names
381403
else:
@@ -817,6 +839,10 @@ def _stringify_single(anno):
817839
return anno
818840
elif isinstance(anno, _Template):
819841
return ast.unparse(_template_to_ast(anno))
842+
elif isinstance(anno, set) and all(isinstance(x, type) for x in anno):
843+
# Sort set elements by name to ensure consistent ordering
844+
sorted_elements = sorted(anno, key=lambda x: x.__name__)
845+
return "{" + ", ".join(x.__name__ for x in sorted_elements) + "}"
820846
else:
821847
return repr(anno)
822848

@@ -1022,10 +1048,17 @@ def annotations_to_string(annotations):
10221048
10231049
Always returns a fresh a dictionary.
10241050
"""
1025-
return {
1026-
n: t if isinstance(t, str) else type_repr(t)
1027-
for n, t in annotations.items()
1028-
}
1051+
result = {}
1052+
for n, t in annotations.items():
1053+
if isinstance(t, str):
1054+
result[n] = t
1055+
elif isinstance(t, set) and all(isinstance(x, type) for x in t):
1056+
# Sort set elements by name to ensure consistent ordering
1057+
sorted_elements = sorted(t, key=lambda x: x.__name__)
1058+
result[n] = "{" + ", ".join(x.__name__ for x in sorted_elements) + "}"
1059+
else:
1060+
result[n] = type_repr(t)
1061+
return result
10291062

10301063

10311064
def _get_and_call_annotate(obj, format):

0 commit comments

Comments
 (0)