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