From 308b838468fd679685c8fd281f3cd1a3ce263afb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tina=20M=C3=BCller?= Date: Fri, 16 Mar 2018 23:25:44 +0100 Subject: [PATCH] Allow to turn off sorting keys in Dumper --- lib/yaml/__init__.py | 4 ++-- lib/yaml/cyaml.py | 12 ++++++------ lib/yaml/dumper.py | 12 ++++++------ lib/yaml/representer.py | 6 ++++-- lib3/yaml/__init__.py | 4 ++-- lib3/yaml/cyaml.py | 12 ++++++------ lib3/yaml/dumper.py | 12 ++++++------ lib3/yaml/representer.py | 12 +++++++----- tests/data/mapping.sort | 6 ++++++ tests/data/mapping.sorted | 6 ++++++ tests/lib/test_sort_keys.py | 28 ++++++++++++++++++++++++++++ tests/lib/test_yaml.py | 1 + tests/lib3/test_sort_keys.py | 29 +++++++++++++++++++++++++++++ tests/lib3/test_yaml.py | 1 + 14 files changed, 110 insertions(+), 35 deletions(-) create mode 100644 tests/data/mapping.sort create mode 100644 tests/data/mapping.sorted create mode 100644 tests/lib/test_sort_keys.py create mode 100644 tests/lib3/test_sort_keys.py diff --git a/lib/yaml/__init__.py b/lib/yaml/__init__.py index 4f83ae1d..61c0a784 100644 --- a/lib/yaml/__init__.py +++ b/lib/yaml/__init__.py @@ -165,7 +165,7 @@ def dump_all(documents, stream=None, Dumper=Dumper, canonical=None, indent=None, width=None, allow_unicode=None, line_break=None, encoding='utf-8', explicit_start=None, explicit_end=None, - version=None, tags=None): + version=None, tags=None, sort_keys=True): """ Serialize a sequence of Python objects into a YAML stream. If stream is None, return the produced string instead. @@ -183,7 +183,7 @@ def dump_all(documents, stream=None, Dumper=Dumper, canonical=canonical, indent=indent, width=width, allow_unicode=allow_unicode, line_break=line_break, encoding=encoding, version=version, tags=tags, - explicit_start=explicit_start, explicit_end=explicit_end) + explicit_start=explicit_start, explicit_end=explicit_end, sort_keys=sort_keys) try: dumper.open() for data in documents: diff --git a/lib/yaml/cyaml.py b/lib/yaml/cyaml.py index 68dcd751..9be4b7f7 100644 --- a/lib/yaml/cyaml.py +++ b/lib/yaml/cyaml.py @@ -39,14 +39,14 @@ def __init__(self, stream, canonical=None, indent=None, width=None, allow_unicode=None, line_break=None, encoding=None, explicit_start=None, explicit_end=None, - version=None, tags=None): + version=None, tags=None, sort_keys=True): CEmitter.__init__(self, stream, canonical=canonical, indent=indent, width=width, encoding=encoding, allow_unicode=allow_unicode, line_break=line_break, explicit_start=explicit_start, explicit_end=explicit_end, version=version, tags=tags) Representer.__init__(self, default_style=default_style, - default_flow_style=default_flow_style) + default_flow_style=default_flow_style, sort_keys=sort_keys) Resolver.__init__(self) class CSafeDumper(CEmitter, SafeRepresenter, Resolver): @@ -56,14 +56,14 @@ def __init__(self, stream, canonical=None, indent=None, width=None, allow_unicode=None, line_break=None, encoding=None, explicit_start=None, explicit_end=None, - version=None, tags=None): + version=None, tags=None, sort_keys=True): CEmitter.__init__(self, stream, canonical=canonical, indent=indent, width=width, encoding=encoding, allow_unicode=allow_unicode, line_break=line_break, explicit_start=explicit_start, explicit_end=explicit_end, version=version, tags=tags) SafeRepresenter.__init__(self, default_style=default_style, - default_flow_style=default_flow_style) + default_flow_style=default_flow_style, sort_keys=sort_keys) Resolver.__init__(self) class CDumper(CEmitter, Serializer, Representer, Resolver): @@ -73,13 +73,13 @@ def __init__(self, stream, canonical=None, indent=None, width=None, allow_unicode=None, line_break=None, encoding=None, explicit_start=None, explicit_end=None, - version=None, tags=None): + version=None, tags=None, sort_keys=True): CEmitter.__init__(self, stream, canonical=canonical, indent=indent, width=width, encoding=encoding, allow_unicode=allow_unicode, line_break=line_break, explicit_start=explicit_start, explicit_end=explicit_end, version=version, tags=tags) Representer.__init__(self, default_style=default_style, - default_flow_style=default_flow_style) + default_flow_style=default_flow_style, sort_keys=sort_keys) Resolver.__init__(self) diff --git a/lib/yaml/dumper.py b/lib/yaml/dumper.py index f811d2c9..6fa7855d 100644 --- a/lib/yaml/dumper.py +++ b/lib/yaml/dumper.py @@ -13,7 +13,7 @@ def __init__(self, stream, canonical=None, indent=None, width=None, allow_unicode=None, line_break=None, encoding=None, explicit_start=None, explicit_end=None, - version=None, tags=None): + version=None, tags=None, sort_keys=True): Emitter.__init__(self, stream, canonical=canonical, indent=indent, width=width, allow_unicode=allow_unicode, line_break=line_break) @@ -21,7 +21,7 @@ def __init__(self, stream, explicit_start=explicit_start, explicit_end=explicit_end, version=version, tags=tags) Representer.__init__(self, default_style=default_style, - default_flow_style=default_flow_style) + default_flow_style=default_flow_style, sort_keys=sort_keys) Resolver.__init__(self) class SafeDumper(Emitter, Serializer, SafeRepresenter, Resolver): @@ -31,7 +31,7 @@ def __init__(self, stream, canonical=None, indent=None, width=None, allow_unicode=None, line_break=None, encoding=None, explicit_start=None, explicit_end=None, - version=None, tags=None): + version=None, tags=None, sort_keys=True): Emitter.__init__(self, stream, canonical=canonical, indent=indent, width=width, allow_unicode=allow_unicode, line_break=line_break) @@ -39,7 +39,7 @@ def __init__(self, stream, explicit_start=explicit_start, explicit_end=explicit_end, version=version, tags=tags) SafeRepresenter.__init__(self, default_style=default_style, - default_flow_style=default_flow_style) + default_flow_style=default_flow_style, sort_keys=sort_keys) Resolver.__init__(self) class Dumper(Emitter, Serializer, Representer, Resolver): @@ -49,7 +49,7 @@ def __init__(self, stream, canonical=None, indent=None, width=None, allow_unicode=None, line_break=None, encoding=None, explicit_start=None, explicit_end=None, - version=None, tags=None): + version=None, tags=None, sort_keys=True): Emitter.__init__(self, stream, canonical=canonical, indent=indent, width=width, allow_unicode=allow_unicode, line_break=line_break) @@ -57,6 +57,6 @@ def __init__(self, stream, explicit_start=explicit_start, explicit_end=explicit_end, version=version, tags=tags) Representer.__init__(self, default_style=default_style, - default_flow_style=default_flow_style) + default_flow_style=default_flow_style, sort_keys=sort_keys) Resolver.__init__(self) diff --git a/lib/yaml/representer.py b/lib/yaml/representer.py index f249f083..3432cc7e 100644 --- a/lib/yaml/representer.py +++ b/lib/yaml/representer.py @@ -17,9 +17,10 @@ class BaseRepresenter(object): yaml_representers = {} yaml_multi_representers = {} - def __init__(self, default_style=None, default_flow_style=None): + def __init__(self, default_style=None, default_flow_style=None, sort_keys=True): self.default_style = default_style self.default_flow_style = default_flow_style + self.sort_keys = sort_keys self.represented_objects = {} self.object_keeper = [] self.alias_key = None @@ -117,7 +118,8 @@ def represent_mapping(self, tag, mapping, flow_style=None): best_style = True if hasattr(mapping, 'items'): mapping = mapping.items() - mapping.sort() + if self.sort_keys: + mapping.sort() for item_key, item_value in mapping: node_key = self.represent_data(item_key) node_value = self.represent_data(item_value) diff --git a/lib3/yaml/__init__.py b/lib3/yaml/__init__.py index 25927851..4bf10430 100644 --- a/lib3/yaml/__init__.py +++ b/lib3/yaml/__init__.py @@ -164,7 +164,7 @@ def dump_all(documents, stream=None, Dumper=Dumper, canonical=None, indent=None, width=None, allow_unicode=None, line_break=None, encoding=None, explicit_start=None, explicit_end=None, - version=None, tags=None): + version=None, tags=None, sort_keys=True): """ Serialize a sequence of Python objects into a YAML stream. If stream is None, return the produced string instead. @@ -181,7 +181,7 @@ def dump_all(documents, stream=None, Dumper=Dumper, canonical=canonical, indent=indent, width=width, allow_unicode=allow_unicode, line_break=line_break, encoding=encoding, version=version, tags=tags, - explicit_start=explicit_start, explicit_end=explicit_end) + explicit_start=explicit_start, explicit_end=explicit_end, sort_keys=sort_keys) try: dumper.open() for data in documents: diff --git a/lib3/yaml/cyaml.py b/lib3/yaml/cyaml.py index d5cb87e9..6c4beafd 100644 --- a/lib3/yaml/cyaml.py +++ b/lib3/yaml/cyaml.py @@ -39,14 +39,14 @@ def __init__(self, stream, canonical=None, indent=None, width=None, allow_unicode=None, line_break=None, encoding=None, explicit_start=None, explicit_end=None, - version=None, tags=None): + version=None, tags=None, sort_keys=True): CEmitter.__init__(self, stream, canonical=canonical, indent=indent, width=width, encoding=encoding, allow_unicode=allow_unicode, line_break=line_break, explicit_start=explicit_start, explicit_end=explicit_end, version=version, tags=tags) Representer.__init__(self, default_style=default_style, - default_flow_style=default_flow_style) + default_flow_style=default_flow_style, sort_keys=sort_keys) Resolver.__init__(self) class CSafeDumper(CEmitter, SafeRepresenter, Resolver): @@ -56,14 +56,14 @@ def __init__(self, stream, canonical=None, indent=None, width=None, allow_unicode=None, line_break=None, encoding=None, explicit_start=None, explicit_end=None, - version=None, tags=None): + version=None, tags=None, sort_keys=True): CEmitter.__init__(self, stream, canonical=canonical, indent=indent, width=width, encoding=encoding, allow_unicode=allow_unicode, line_break=line_break, explicit_start=explicit_start, explicit_end=explicit_end, version=version, tags=tags) SafeRepresenter.__init__(self, default_style=default_style, - default_flow_style=default_flow_style) + default_flow_style=default_flow_style, sort_keys=sort_keys) Resolver.__init__(self) class CDumper(CEmitter, Serializer, Representer, Resolver): @@ -73,13 +73,13 @@ def __init__(self, stream, canonical=None, indent=None, width=None, allow_unicode=None, line_break=None, encoding=None, explicit_start=None, explicit_end=None, - version=None, tags=None): + version=None, tags=None, sort_keys=True): CEmitter.__init__(self, stream, canonical=canonical, indent=indent, width=width, encoding=encoding, allow_unicode=allow_unicode, line_break=line_break, explicit_start=explicit_start, explicit_end=explicit_end, version=version, tags=tags) Representer.__init__(self, default_style=default_style, - default_flow_style=default_flow_style) + default_flow_style=default_flow_style, sort_keys=sort_keys) Resolver.__init__(self) diff --git a/lib3/yaml/dumper.py b/lib3/yaml/dumper.py index 0b691287..b17ffa30 100644 --- a/lib3/yaml/dumper.py +++ b/lib3/yaml/dumper.py @@ -13,7 +13,7 @@ def __init__(self, stream, canonical=None, indent=None, width=None, allow_unicode=None, line_break=None, encoding=None, explicit_start=None, explicit_end=None, - version=None, tags=None): + version=None, tags=None, sort_keys=True): Emitter.__init__(self, stream, canonical=canonical, indent=indent, width=width, allow_unicode=allow_unicode, line_break=line_break) @@ -21,7 +21,7 @@ def __init__(self, stream, explicit_start=explicit_start, explicit_end=explicit_end, version=version, tags=tags) Representer.__init__(self, default_style=default_style, - default_flow_style=default_flow_style) + default_flow_style=default_flow_style, sort_keys=sort_keys) Resolver.__init__(self) class SafeDumper(Emitter, Serializer, SafeRepresenter, Resolver): @@ -31,7 +31,7 @@ def __init__(self, stream, canonical=None, indent=None, width=None, allow_unicode=None, line_break=None, encoding=None, explicit_start=None, explicit_end=None, - version=None, tags=None): + version=None, tags=None, sort_keys=True): Emitter.__init__(self, stream, canonical=canonical, indent=indent, width=width, allow_unicode=allow_unicode, line_break=line_break) @@ -39,7 +39,7 @@ def __init__(self, stream, explicit_start=explicit_start, explicit_end=explicit_end, version=version, tags=tags) SafeRepresenter.__init__(self, default_style=default_style, - default_flow_style=default_flow_style) + default_flow_style=default_flow_style, sort_keys=sort_keys) Resolver.__init__(self) class Dumper(Emitter, Serializer, Representer, Resolver): @@ -49,7 +49,7 @@ def __init__(self, stream, canonical=None, indent=None, width=None, allow_unicode=None, line_break=None, encoding=None, explicit_start=None, explicit_end=None, - version=None, tags=None): + version=None, tags=None, sort_keys=True): Emitter.__init__(self, stream, canonical=canonical, indent=indent, width=width, allow_unicode=allow_unicode, line_break=line_break) @@ -57,6 +57,6 @@ def __init__(self, stream, explicit_start=explicit_start, explicit_end=explicit_end, version=version, tags=tags) Representer.__init__(self, default_style=default_style, - default_flow_style=default_flow_style) + default_flow_style=default_flow_style, sort_keys=sort_keys) Resolver.__init__(self) diff --git a/lib3/yaml/representer.py b/lib3/yaml/representer.py index 483005f4..2f230bb8 100644 --- a/lib3/yaml/representer.py +++ b/lib3/yaml/representer.py @@ -15,8 +15,9 @@ class BaseRepresenter: yaml_representers = {} yaml_multi_representers = {} - def __init__(self, default_style=None, default_flow_style=None): + def __init__(self, default_style=None, default_flow_style=None, sort_keys=True): self.default_style = default_style + self.sort_keys = sort_keys self.default_flow_style = default_flow_style self.represented_objects = {} self.object_keeper = [] @@ -107,10 +108,11 @@ def represent_mapping(self, tag, mapping, flow_style=None): best_style = True if hasattr(mapping, 'items'): mapping = list(mapping.items()) - try: - mapping = sorted(mapping) - except TypeError: - pass + if self.sort_keys: + try: + mapping = sorted(mapping) + except TypeError: + pass for item_key, item_value in mapping: node_key = self.represent_data(item_key) node_value = self.represent_data(item_value) diff --git a/tests/data/mapping.sort b/tests/data/mapping.sort new file mode 100644 index 00000000..802ba1ad --- /dev/null +++ b/tests/data/mapping.sort @@ -0,0 +1,6 @@ +z: 1 +a: 2 +y: 3 +b: 4 +x: 5 +c: 6 diff --git a/tests/data/mapping.sorted b/tests/data/mapping.sorted new file mode 100644 index 00000000..b3dd3464 --- /dev/null +++ b/tests/data/mapping.sorted @@ -0,0 +1,6 @@ +a: 2 +b: 4 +c: 6 +x: 5 +y: 3 +z: 1 diff --git a/tests/lib/test_sort_keys.py b/tests/lib/test_sort_keys.py new file mode 100644 index 00000000..0afe1546 --- /dev/null +++ b/tests/lib/test_sort_keys.py @@ -0,0 +1,28 @@ +import yaml +import pprint +import sys + +def test_sort_keys(input_filename, sorted_filename, verbose=False): + input = open(input_filename, 'rb').read().decode('utf-8') + sorted = open(sorted_filename, 'rb').read().decode('utf-8') + data = yaml.load(input) + dump_sorted = yaml.dump(data, default_flow_style=False, sort_keys=True) + dump_unsorted = yaml.dump(data, default_flow_style=False, sort_keys=False) + dump_unsorted = yaml.dump(data, default_flow_style=False, sort_keys=False, Dumper=yaml.SafeDumper) + if verbose: + print("INPUT:") + print(input) + print("DATA:") + print(data) + + assert dump_sorted == sorted + + + + +test_sort_keys.unittest = ['.sort', '.sorted'] + +if __name__ == '__main__': + import test_appliance + test_appliance.run(globals()) + diff --git a/tests/lib/test_yaml.py b/tests/lib/test_yaml.py index 09273687..e26342d6 100644 --- a/tests/lib/test_yaml.py +++ b/tests/lib/test_yaml.py @@ -11,6 +11,7 @@ from test_representer import * from test_recursive import * from test_input_output import * +from test_sort_keys import * if __name__ == '__main__': import test_appliance diff --git a/tests/lib3/test_sort_keys.py b/tests/lib3/test_sort_keys.py new file mode 100644 index 00000000..6c517774 --- /dev/null +++ b/tests/lib3/test_sort_keys.py @@ -0,0 +1,29 @@ +import yaml +import pprint +import sys + +def test_sort_keys(input_filename, sorted_filename, verbose=False): + input = open(input_filename, 'rb').read().decode('utf-8') + sorted = open(sorted_filename, 'rb').read().decode('utf-8') + data = yaml.load(input) + dump_sorted = yaml.dump(data, default_flow_style=False, sort_keys=True) + dump_unsorted = yaml.dump(data, default_flow_style=False, sort_keys=False) + dump_unsorted_safe = yaml.dump(data, default_flow_style=False, sort_keys=False, Dumper=yaml.SafeDumper) + if verbose: + print("INPUT:") + print(input) + print("DATA:") + print(data) + + assert dump_sorted == sorted + + if sys.version_info>=(3,7): + assert dump_unsorted == input + assert dump_unsorted_safe == input + +test_sort_keys.unittest = ['.sort', '.sorted'] + +if __name__ == '__main__': + import test_appliance + test_appliance.run(globals()) + diff --git a/tests/lib3/test_yaml.py b/tests/lib3/test_yaml.py index 09273687..e26342d6 100644 --- a/tests/lib3/test_yaml.py +++ b/tests/lib3/test_yaml.py @@ -11,6 +11,7 @@ from test_representer import * from test_recursive import * from test_input_output import * +from test_sort_keys import * if __name__ == '__main__': import test_appliance