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