koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 1 | __doc__ = "functions for make pretty yaml files" |
| 2 | __all__ = ['dumps'] |
| 3 | |
| 4 | |
koder aka kdanilov | f4b82c2 | 2015-04-11 13:35:25 +0300 | [diff] [blame] | 5 | def dumps_simple(val): |
koder aka kdanilov | 4af1c1d | 2015-05-18 15:48:58 +0300 | [diff] [blame] | 6 | bad_symbols = set(" \r\t\n,':{}[]><;") |
koder aka kdanilov | f4b82c2 | 2015-04-11 13:35:25 +0300 | [diff] [blame] | 7 | |
| 8 | if isinstance(val, basestring): |
koder aka kdanilov | 4af1c1d | 2015-05-18 15:48:58 +0300 | [diff] [blame] | 9 | if isinstance(val, unicode): |
| 10 | val = val.encode('utf8') |
| 11 | |
koder aka kdanilov | 7248c7b | 2015-05-31 22:53:03 +0300 | [diff] [blame] | 12 | try: |
| 13 | float(val) |
| 14 | val = repr(val) |
| 15 | except ValueError: |
| 16 | if len(bad_symbols & set(val)) != 0: |
| 17 | val = repr(val) |
| 18 | |
koder aka kdanilov | f4b82c2 | 2015-04-11 13:35:25 +0300 | [diff] [blame] | 19 | return val |
| 20 | elif val is True: |
| 21 | return 'true' |
| 22 | elif val is False: |
| 23 | return 'false' |
| 24 | elif val is None: |
| 25 | return 'null' |
| 26 | |
| 27 | return str(val) |
| 28 | |
| 29 | |
| 30 | def is_simple(val): |
| 31 | simple_type = isinstance(val, (str, unicode, int, long, bool, float)) |
| 32 | return simple_type or val is None |
| 33 | |
| 34 | |
| 35 | def all_nums(vals): |
| 36 | return all(isinstance(val, (int, float, long)) for val in vals) |
| 37 | |
| 38 | |
koder aka kdanilov | 4af1c1d | 2015-05-18 15:48:58 +0300 | [diff] [blame] | 39 | def dumpv(data, tab_sz=4, width=160, min_width=40): |
koder aka kdanilov | f4b82c2 | 2015-04-11 13:35:25 +0300 | [diff] [blame] | 40 | tab = ' ' * tab_sz |
| 41 | |
| 42 | if width < min_width: |
| 43 | width = min_width |
| 44 | |
| 45 | res = [] |
| 46 | if is_simple(data): |
| 47 | return [dumps_simple(data)] |
| 48 | |
| 49 | if isinstance(data, (list, tuple)): |
| 50 | if all(map(is_simple, data)): |
| 51 | if all_nums(data): |
koder aka kdanilov | a047e1b | 2015-04-21 23:16:59 +0300 | [diff] [blame] | 52 | one_line = "[{0}]".format(", ".join(map(dumps_simple, data))) |
koder aka kdanilov | f4b82c2 | 2015-04-11 13:35:25 +0300 | [diff] [blame] | 53 | else: |
koder aka kdanilov | a047e1b | 2015-04-21 23:16:59 +0300 | [diff] [blame] | 54 | one_line = "[{0}]".format(",".join(map(dumps_simple, data))) |
koder aka kdanilov | 4af1c1d | 2015-05-18 15:48:58 +0300 | [diff] [blame] | 55 | elif len(data) == 0: |
| 56 | one_line = "[]" |
koder aka kdanilov | f4b82c2 | 2015-04-11 13:35:25 +0300 | [diff] [blame] | 57 | else: |
| 58 | one_line = None |
| 59 | |
| 60 | if one_line is None or len(one_line) > width: |
| 61 | pref = "-" + ' ' * (tab_sz - 1) |
| 62 | |
| 63 | for val in data: |
| 64 | items = dumpv(val, tab_sz, width - tab_sz, min_width) |
| 65 | items = [pref + items[0]] + \ |
| 66 | [tab + item for item in items[1:]] |
| 67 | res.extend(items) |
| 68 | else: |
| 69 | res.append(one_line) |
| 70 | elif isinstance(data, dict): |
koder aka kdanilov | 4af1c1d | 2015-05-18 15:48:58 +0300 | [diff] [blame] | 71 | if len(data) == 0: |
| 72 | res.append("{}") |
| 73 | else: |
| 74 | assert all(map(is_simple, data.keys())) |
koder aka kdanilov | f4b82c2 | 2015-04-11 13:35:25 +0300 | [diff] [blame] | 75 | |
koder aka kdanilov | 4af1c1d | 2015-05-18 15:48:58 +0300 | [diff] [blame] | 76 | one_line = None |
| 77 | if all(map(is_simple, data.values())): |
| 78 | one_line = ", ".join( |
| 79 | "{0}: {1}".format(dumps_simple(k), dumps_simple(v)) |
| 80 | for k, v in sorted(data.items())) |
| 81 | one_line = "{" + one_line + "}" |
| 82 | if len(one_line) > width: |
| 83 | one_line = None |
koder aka kdanilov | f4b82c2 | 2015-04-11 13:35:25 +0300 | [diff] [blame] | 84 | |
koder aka kdanilov | 4af1c1d | 2015-05-18 15:48:58 +0300 | [diff] [blame] | 85 | if one_line is None: |
| 86 | for k, v in data.items(): |
| 87 | key_str = dumps_simple(k) + ": " |
| 88 | val_res = dumpv(v, tab_sz, width - tab_sz, min_width) |
| 89 | |
| 90 | if len(val_res) == 1 and \ |
| 91 | len(key_str + val_res[0]) < width and \ |
koder aka kdanilov | bb6d6cd | 2015-06-20 02:55:07 +0300 | [diff] [blame] | 92 | not isinstance(v, dict) and \ |
| 93 | not val_res[0].strip().startswith('-'): |
koder aka kdanilov | 4af1c1d | 2015-05-18 15:48:58 +0300 | [diff] [blame] | 94 | res.append(key_str + val_res[0]) |
| 95 | else: |
| 96 | res.append(key_str) |
| 97 | res.extend(tab + i for i in val_res) |
koder aka kdanilov | f4b82c2 | 2015-04-11 13:35:25 +0300 | [diff] [blame] | 98 | else: |
koder aka kdanilov | 4af1c1d | 2015-05-18 15:48:58 +0300 | [diff] [blame] | 99 | res.append(one_line) |
koder aka kdanilov | f4b82c2 | 2015-04-11 13:35:25 +0300 | [diff] [blame] | 100 | else: |
koder aka kdanilov | 4af1c1d | 2015-05-18 15:48:58 +0300 | [diff] [blame] | 101 | try: |
| 102 | get_yamable = data.get_yamable |
| 103 | except AttributeError: |
| 104 | raise ValueError("Can't pack {0!r}".format(data)) |
| 105 | res = dumpv(get_yamable(), tab_sz, width, min_width) |
koder aka kdanilov | f4b82c2 | 2015-04-11 13:35:25 +0300 | [diff] [blame] | 106 | |
| 107 | return res |
| 108 | |
| 109 | |
| 110 | def dumps(data, tab_sz=4, width=120, min_width=40): |
| 111 | return "\n".join(dumpv(data, tab_sz, width, min_width)) |