Update xjson.py from prjxray Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com>
diff --git a/utils/xjson.py b/utils/xjson.py index 77eaf51..32f74ce 100755 --- a/utils/xjson.py +++ b/utils/xjson.py
@@ -4,6 +4,8 @@ import re import sys +from collections import OrderedDict + def extract_numbers(s): """ @@ -22,32 +24,67 @@ def sort(data): - # FIXME: We assume that a list is a tileconn.json format... - if isinstance(data, list) and len(data) > 0 and 'wire_pairs' in data[0]: - for o in data: - o['wire_pairs'].sort( - key=lambda o: (extract_numbers(o[0]), extract_numbers(o[1]))) + """Sort data types via "natural" numbers. - data.sort(key=lambda o: (o['tile_types'], o['grid_deltas'])) - else: + Supports all the basic Python data types. + >>> o = sort({ + ... 't1': {'c','b'}, # Set + ... 't2': ('a2', 'a10', 'e'), # Tuple + ... 't3': [5, 3, 2], # List + ... 't4': { # Dictionary + ... 'a4': ('b2', 'b3'), + ... 'a2': ['c1', 'c2', 'c0', 'c10'], + ... }, + ... 't5': ['a1b5', 'a2b1', 'a1b1'], + ... }) + >>> for t in o: + ... print(t+':', o[t]) + t1: ('b', 'c') + t2: ('a2', 'a10', 'e') + t3: (5, 3, 2) + t4: OrderedDict([('a2', ('c1', 'c2', 'c0', 'c10')), ('a4', ('b2', 'b3'))]) + t5: ('a1b5', 'a2b1', 'a1b1') - def walker(o, f): - if isinstance(o, dict): - for i in o.values(): - walker(i, f) - elif isinstance(o, list): - for i in o: - walker(i, f) - f(o) + Don't mangle "pairs" + >>> sort([('b', 'c'), ('2', '1')]) + (('b', 'c'), ('2', '1')) + """ - def f(o): - if isinstance(o, list): - if len(o) > 2: - strings = all(isinstance(x, str) for x in o) - if strings: - o.sort() + def key(o): + if o is None: + return None + elif isinstance(o, str): + return extract_numbers(o) + elif isinstance(o, int): + return o + elif isinstance(o, (list, tuple)): + return tuple(key(i) for i in o) + elif isinstance(o, dict): + return tuple((key(k), key(v)) for k, v in o.items()) + elif isinstance(o, set): + return tuple(key(k) for k in o) + raise ValueError(repr(o)) - walker(data, f) + def rsorter(o): + if isinstance(o, dict): + nitems = [] + for k, v in o.items(): + nitems.append((key(k), k, rsorter(v))) + nitems.sort(key=lambda n: n[0]) + + new_dict = OrderedDict() + for _, k, v in nitems: + new_dict[k] = v + return new_dict + + elif isinstance(o, set): + return tuple(sorted((rsorter(v) for v in o), key=key)) + elif isinstance(o, (tuple, list)): + return tuple(rsorter(v) for v in o) + else: + return o + + return rsorter(data) def pprint(f, data): @@ -55,8 +92,8 @@ if not isinstance(f, io.TextIOBase): detach = True f = io.TextIOWrapper(f) - sort(data) - json.dump(data, f, sort_keys=True, indent=4) + data = sort(data) + json.dump(data, f, indent=4) f.write('\n') f.flush() if detach: