From d0bfae4171f0d280241949a928654c84e63ed006 Mon Sep 17 00:00:00 2001 From: Gris Ge Date: Mon, 29 Jun 2020 22:30:03 +0800 Subject: [PATCH] pretty state: Dumping state in the sorted order with priority For OVS bond port, we would like the `name` been shown before other properties. To achieve that, we sort the dict keys and honoring the priority list which means keys in `PRIORITY_LIST` will be shown before others. Currently the `PRIORITY_LIST` is: `("name", "type", "state", "enabled", "dns", "route-rules", "routes", "interfaces")` Test cases added. Signed-off-by: Gris Ge Signed-off-by: Till Maas --- libnmstate/prettystate.py | 94 ++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 51 deletions(-) diff --git a/libnmstate/prettystate.py b/libnmstate/prettystate.py index da57618..10e22d6 100644 --- a/libnmstate/prettystate.py +++ b/libnmstate/prettystate.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2018-2019 Red Hat, Inc. +# Copyright (c) 2018-2020 Red Hat, Inc. # # This file is part of nmstate # @@ -17,15 +17,29 @@ # along with this program. If not, see . # -from collections import OrderedDict +from collections.abc import Mapping +from collections.abc import Sequence from copy import deepcopy import difflib import json -from operator import itemgetter import yaml -from libnmstate.schema import Constants +from .schema import DNS +from .schema import Route +from .schema import RouteRule +from .schema import Interface + +PRIORITY_LIST = ( + "name", + "type", + "state", + "enabled", + DNS.KEY, + RouteRule.KEY, + Route.KEY, + Interface.KEY, +) def format_desired_current_state_diff(desired_state, current_state): @@ -57,8 +71,8 @@ def format_desired_current_state_diff(desired_state, current_state): class PrettyState: def __init__(self, state): - yaml.add_representer(OrderedDict, represent_ordereddict) - self.state = order_state(deepcopy(state)) + yaml.add_representer(dict, represent_dict) + self.state = _sort_with_priority(state) @property def yaml(self): @@ -71,35 +85,18 @@ class PrettyState: return json.dumps(self.state, indent=4, separators=(",", ": ")) -def represent_ordereddict(dumper, data): +def represent_dict(dumper, data): + """ + Represent dictionary with insert order """ - Represent OrderedDict as regular dictionary - - Source: https://stackoverflow.com/questions/16782112/can-pyyaml-dump-dict-items-in-non-alphabetical-order - """ # noqa: E501 value = [] for item_key, item_value in data.items(): node_key = dumper.represent_data(item_key) node_value = dumper.represent_data(item_value) - value.append((node_key, node_value)) - return yaml.nodes.MappingNode(u"tag:yaml.org,2002:map", value) - - -def order_state(state): - iface_states = state.pop(Constants.INTERFACES, None) - - state = order_iface_state(state) - - if iface_states is not None: - state[Constants.INTERFACES] = [ - order_iface_state(iface_state) - for iface_state in sorted(iface_states, key=itemgetter("name")) - ] - - return state + return yaml.nodes.MappingNode("tag:yaml.org,2002:map", value) def represent_unicode(_, data): @@ -112,30 +109,25 @@ def represent_unicode(_, data): """ return yaml.ScalarNode( - tag=u"tag:yaml.org,2002:str", value=data.encode("utf-8") + tag="tag:yaml.org,2002:str", value=data.encode("utf-8") ) -def order_iface_state(iface_state): - ordered_state = OrderedDict() - - for setting in ("name", "type", "state"): - try: - ordered_state[setting] = iface_state.pop(setting) - except KeyError: - pass - - for key, value in order_dict(iface_state).items(): - ordered_state[key] = value - - return ordered_state - - -def order_dict(dict_): - ordered_dict = OrderedDict() - for key, value in sorted(dict_.items()): - if isinstance(value, dict): - value = order_dict(value) - ordered_dict[key] = value - - return ordered_dict +def _sort_with_priority(data): + if isinstance(data, Sequence) and not isinstance(data, str): + return [_sort_with_priority(item) for item in data] + elif isinstance(data, Mapping): + new_data = {} + for key in sorted(data.keys(), key=_sort_with_priority_key_func): + new_data[key] = _sort_with_priority(data[key]) + return new_data + else: + return deepcopy(data) + + +def _sort_with_priority_key_func(key): + try: + priority = PRIORITY_LIST.index(key) + except ValueError: + priority = len(PRIORITY_LIST) + return (priority, key) -- 2.27.0