Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/pyaml/__init__.py @ 5:9b1c78e6ba9c draft default tip
"planemo upload commit 6c0a8142489327ece472c84e558c47da711a9142"
| author | shellac |
|---|---|
| date | Mon, 01 Jun 2020 08:59:25 -0400 |
| parents | 79f47841a781 |
| children |
comparison
equal
deleted
inserted
replaced
| 4:79f47841a781 | 5:9b1c78e6ba9c |
|---|---|
| 1 # -*- coding: utf-8 -*- | |
| 2 from __future__ import unicode_literals, print_function | |
| 3 | |
| 4 import itertools as it, operator as op, functools as ft | |
| 5 from collections import defaultdict, OrderedDict, namedtuple | |
| 6 import os, sys, io, re | |
| 7 | |
| 8 import yaml | |
| 9 | |
| 10 if sys.version_info.major > 2: unicode = str | |
| 11 | |
| 12 | |
| 13 class PrettyYAMLDumper(yaml.dumper.SafeDumper): | |
| 14 | |
| 15 def __init__(self, *args, **kws): | |
| 16 self.pyaml_force_embed = kws.pop('force_embed', False) | |
| 17 self.pyaml_string_val_style = kws.pop('string_val_style', None) | |
| 18 self.pyaml_sort_dicts = kws.pop('sort_dicts', True) | |
| 19 return super(PrettyYAMLDumper, self).__init__(*args, **kws) | |
| 20 | |
| 21 def represent_odict(dumper, data): | |
| 22 value = list() | |
| 23 node = yaml.nodes.MappingNode( | |
| 24 'tag:yaml.org,2002:map', value, flow_style=None ) | |
| 25 if dumper.alias_key is not None: | |
| 26 dumper.represented_objects[dumper.alias_key] = node | |
| 27 for item_key, item_value in data.items(): | |
| 28 node_key = dumper.represent_data(item_key) | |
| 29 node_value = dumper.represent_data(item_value) | |
| 30 value.append((node_key, node_value)) | |
| 31 node.flow_style = False | |
| 32 return node | |
| 33 | |
| 34 def represent_undefined(dumper, data): | |
| 35 if isinstance(data, tuple) and hasattr(data, '_make') and hasattr(data, '_asdict'): | |
| 36 return dumper.represent_odict(data._asdict()) # assuming namedtuple | |
| 37 elif isinstance(data, OrderedDict): return dumper.represent_odict(data) | |
| 38 elif isinstance(data, dict): return dumper.represent_dict(data) | |
| 39 elif callable(getattr(data, 'tolist', None)): return dumper.represent_data(data.tolist()) | |
| 40 return super(PrettyYAMLDumper, dumper).represent_undefined(data) | |
| 41 | |
| 42 def represent_dict(dumper, data): | |
| 43 if not dumper.pyaml_sort_dicts: return dumper.represent_odict(data) | |
| 44 return super(PrettyYAMLDumper, dumper).represent_dict(data) | |
| 45 | |
| 46 def serialize_node(self, node, parent, index): | |
| 47 if self.pyaml_force_embed: self.serialized_nodes.clear() | |
| 48 return super(PrettyYAMLDumper, self).serialize_node(node, parent, index) | |
| 49 | |
| 50 @staticmethod | |
| 51 def pyaml_transliterate(string): | |
| 52 if not all(ord(c) < 128 for c in string): | |
| 53 from unidecode import unidecode | |
| 54 string = unidecode(string) | |
| 55 string_new = '' | |
| 56 for ch in string: | |
| 57 if '0' <= ch <= '9' or 'A' <= ch <= 'Z' or 'a' <= ch <= 'z' or ch in '-_': string_new += ch | |
| 58 else: string_new += '_' | |
| 59 return string_new.lower() | |
| 60 | |
| 61 def anchor_node(self, node, hint=list()): | |
| 62 if node in self.anchors: | |
| 63 if self.anchors[node] is None and not self.pyaml_force_embed: | |
| 64 self.anchors[node] = self.generate_anchor(node)\ | |
| 65 if not hint else '{}'.format( | |
| 66 self.pyaml_transliterate( | |
| 67 '_-_'.join(map(op.attrgetter('value'), hint)) ) ) | |
| 68 else: | |
| 69 self.anchors[node] = None | |
| 70 if isinstance(node, yaml.nodes.SequenceNode): | |
| 71 for item in node.value: | |
| 72 self.anchor_node(item) | |
| 73 elif isinstance(node, yaml.nodes.MappingNode): | |
| 74 for key, value in node.value: | |
| 75 self.anchor_node(key) | |
| 76 self.anchor_node(value, hint=hint+[key]) | |
| 77 | |
| 78 PrettyYAMLDumper.add_representer(dict, PrettyYAMLDumper.represent_dict) | |
| 79 PrettyYAMLDumper.add_representer(defaultdict, PrettyYAMLDumper.represent_dict) | |
| 80 PrettyYAMLDumper.add_representer(OrderedDict, PrettyYAMLDumper.represent_odict) | |
| 81 PrettyYAMLDumper.add_representer(set, PrettyYAMLDumper.represent_list) | |
| 82 PrettyYAMLDumper.add_representer(None, PrettyYAMLDumper.represent_undefined) | |
| 83 | |
| 84 if sys.version_info.major >= 3: | |
| 85 try: import pathlib | |
| 86 except ImportError: pass | |
| 87 else: | |
| 88 PrettyYAMLDumper.add_representer( | |
| 89 type(pathlib.Path('')), lambda cls,o: cls.represent_data(str(o)) ) | |
| 90 | |
| 91 | |
| 92 class UnsafePrettyYAMLDumper(PrettyYAMLDumper): | |
| 93 | |
| 94 def expect_block_sequence(self): | |
| 95 self.increase_indent(flow=False, indentless=False) | |
| 96 self.state = self.expect_first_block_sequence_item | |
| 97 | |
| 98 def expect_block_sequence_item(self, first=False): | |
| 99 if not first and isinstance(self.event, yaml.events.SequenceEndEvent): | |
| 100 self.indent = self.indents.pop() | |
| 101 self.state = self.states.pop() | |
| 102 else: | |
| 103 self.write_indent() | |
| 104 self.write_indicator('-', True, indention=True) | |
| 105 self.states.append(self.expect_block_sequence_item) | |
| 106 self.expect_node(sequence=True) | |
| 107 | |
| 108 def choose_scalar_style(self): | |
| 109 is_dict_key = self.states[-1] == self.expect_block_mapping_simple_value | |
| 110 if is_dict_key: | |
| 111 # Don't mess-up (replace) styles for dict keys, if possible | |
| 112 if self.pyaml_string_val_style: self.event.style = 'plain' | |
| 113 else: | |
| 114 # Make sure we don't create "key: null" mapping accidentally | |
| 115 if self.event.value.endswith(':'): self.event.style = "'" | |
| 116 return super(UnsafePrettyYAMLDumper, self).choose_scalar_style()\ | |
| 117 if self.event.style != 'plain' else ("'" if ' ' in self.event.value else None) | |
| 118 | |
| 119 def represent_stringish(dumper, data): | |
| 120 # Will crash on bytestrings with weird chars in them, | |
| 121 # because we can't tell if it's supposed to be e.g. utf-8 readable string | |
| 122 # or an arbitrary binary buffer, and former one *must* be pretty-printed | |
| 123 # PyYAML's Representer.represent_str does the guesswork and !!binary or !!python/str | |
| 124 # Explicit crash on any bytes object might be more sane, but also annoying | |
| 125 # Use something like base64 to encode such buffer values instead | |
| 126 # Having such binary stuff pretty much everywhere on unix (e.g. paths) kinda sucks | |
| 127 data = unicode(data) # read the comment above | |
| 128 | |
| 129 # Try to use '|' style for multiline data, | |
| 130 # quoting it with 'literal' if lines are too long anyway, | |
| 131 # not sure if Emitter.analyze_scalar can also provide useful info here | |
| 132 style = dumper.pyaml_string_val_style | |
| 133 if not style: | |
| 134 style = 'plain' | |
| 135 if '\n' in data or not data or data == '-' or data[0] in '!&*[' or '#' in data: | |
| 136 style = 'literal' | |
| 137 if '\n' in data[:-1]: | |
| 138 for line in data.splitlines(): | |
| 139 if len(line) > dumper.best_width: break | |
| 140 else: style = '|' | |
| 141 | |
| 142 return yaml.representer.ScalarNode('tag:yaml.org,2002:str', data, style=style) | |
| 143 | |
| 144 for str_type in {bytes, unicode}: | |
| 145 UnsafePrettyYAMLDumper.add_representer( | |
| 146 str_type, UnsafePrettyYAMLDumper.represent_stringish ) | |
| 147 | |
| 148 UnsafePrettyYAMLDumper.add_representer( | |
| 149 type(None), lambda s,o: s.represent_scalar('tag:yaml.org,2002:null', '') ) | |
| 150 | |
| 151 def add_representer(*args, **kws): | |
| 152 PrettyYAMLDumper.add_representer(*args, **kws) | |
| 153 UnsafePrettyYAMLDumper.add_representer(*args, **kws) | |
| 154 | |
| 155 | |
| 156 def dump_add_vspacing(buff, vspacing): | |
| 157 'Post-processing to add some nice-ish spacing for deeper map/list levels.' | |
| 158 if isinstance(vspacing, int): | |
| 159 vspacing = ['\n']*(vspacing+1) | |
| 160 buff.seek(0) | |
| 161 result = list() | |
| 162 for line in buff: | |
| 163 level = 0 | |
| 164 line = line.decode('utf-8') | |
| 165 result.append(line) | |
| 166 if ':' in line or re.search(r'---(\s*$|\s)', line): | |
| 167 while line.startswith(' '): | |
| 168 level, line = level + 1, line[2:] | |
| 169 if len(vspacing) > level and len(result) != 1: | |
| 170 vspace = vspacing[level] | |
| 171 result.insert( -1, vspace | |
| 172 if not isinstance(vspace, int) else '\n'*vspace ) | |
| 173 buff.seek(0), buff.truncate() | |
| 174 buff.write(''.join(result).encode('utf-8')) | |
| 175 | |
| 176 | |
| 177 def dump_all(data, *dump_args, **dump_kws): | |
| 178 return dump(data, *dump_args, multiple_docs=True, **dump_kws) | |
| 179 | |
| 180 def dump( data, dst=unicode, safe=False, force_embed=False, vspacing=None, | |
| 181 string_val_style=None, sort_dicts=True, multiple_docs=False, **pyyaml_kws ): | |
| 182 buff = io.BytesIO() | |
| 183 Dumper = PrettyYAMLDumper if safe else UnsafePrettyYAMLDumper | |
| 184 Dumper = ft.partial( Dumper, | |
| 185 force_embed=force_embed, string_val_style=string_val_style, sort_dicts=sort_dicts ) | |
| 186 if not multiple_docs: data = [data] | |
| 187 else: pyyaml_kws.setdefault('explicit_start', True) | |
| 188 yaml.dump_all( data, buff, Dumper=Dumper, | |
| 189 default_flow_style=False, allow_unicode=True, encoding='utf-8', **pyyaml_kws ) | |
| 190 | |
| 191 if vspacing is not None: | |
| 192 dump_add_vspacing(buff, vspacing) | |
| 193 | |
| 194 buff = buff.getvalue() | |
| 195 if dst is bytes: return buff | |
| 196 elif dst is unicode: return buff.decode('utf-8') | |
| 197 else: | |
| 198 try: dst.write(b'') # tests if dst is unicode- or bytestream | |
| 199 except: dst.write(buff.decode('utf-8')) | |
| 200 else: dst.write(buff) | |
| 201 | |
| 202 def dumps(data, **dump_kws): | |
| 203 return dump(data, dst=bytes, **dump_kws) | |
| 204 | |
| 205 def pprint(*data, **dump_kws): | |
| 206 dst = dump_kws.pop('file', dump_kws.pop('dst', sys.stdout)) | |
| 207 if len(data) == 1: data, = data | |
| 208 dump(data, dst=dst, **dump_kws) | |
| 209 | |
| 210 p, _p = pprint, print | |
| 211 print = pprint # pyaml.print() won't work without "from __future__ import print_function" |
