comparison env/lib/python3.9/site-packages/ruamel/yaml/representer.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 # coding: utf-8
2
3 from __future__ import print_function, absolute_import, division
4
5
6 from ruamel.yaml.error import * # NOQA
7 from ruamel.yaml.nodes import * # NOQA
8 from ruamel.yaml.compat import text_type, binary_type, to_unicode, PY2, PY3
9 from ruamel.yaml.compat import ordereddict # type: ignore
10 from ruamel.yaml.compat import nprint, nprintf # NOQA
11 from ruamel.yaml.scalarstring import (
12 LiteralScalarString,
13 FoldedScalarString,
14 SingleQuotedScalarString,
15 DoubleQuotedScalarString,
16 PlainScalarString,
17 )
18 from ruamel.yaml.scalarint import ScalarInt, BinaryInt, OctalInt, HexInt, HexCapsInt
19 from ruamel.yaml.scalarfloat import ScalarFloat
20 from ruamel.yaml.scalarbool import ScalarBoolean
21 from ruamel.yaml.timestamp import TimeStamp
22
23 import datetime
24 import sys
25 import types
26
27 if PY3:
28 import copyreg
29 import base64
30 else:
31 import copy_reg as copyreg # type: ignore
32
33 if False: # MYPY
34 from typing import Dict, List, Any, Union, Text, Optional # NOQA
35
36 # fmt: off
37 __all__ = ['BaseRepresenter', 'SafeRepresenter', 'Representer',
38 'RepresenterError', 'RoundTripRepresenter']
39 # fmt: on
40
41
42 class RepresenterError(YAMLError):
43 pass
44
45
46 if PY2:
47
48 def get_classobj_bases(cls):
49 # type: (Any) -> Any
50 bases = [cls]
51 for base in cls.__bases__:
52 bases.extend(get_classobj_bases(base))
53 return bases
54
55
56 class BaseRepresenter(object):
57
58 yaml_representers = {} # type: Dict[Any, Any]
59 yaml_multi_representers = {} # type: Dict[Any, Any]
60
61 def __init__(self, default_style=None, default_flow_style=None, dumper=None):
62 # type: (Any, Any, Any, Any) -> None
63 self.dumper = dumper
64 if self.dumper is not None:
65 self.dumper._representer = self
66 self.default_style = default_style
67 self.default_flow_style = default_flow_style
68 self.represented_objects = {} # type: Dict[Any, Any]
69 self.object_keeper = [] # type: List[Any]
70 self.alias_key = None # type: Optional[int]
71 self.sort_base_mapping_type_on_output = True
72
73 @property
74 def serializer(self):
75 # type: () -> Any
76 try:
77 if hasattr(self.dumper, 'typ'):
78 return self.dumper.serializer
79 return self.dumper._serializer
80 except AttributeError:
81 return self # cyaml
82
83 def represent(self, data):
84 # type: (Any) -> None
85 node = self.represent_data(data)
86 self.serializer.serialize(node)
87 self.represented_objects = {}
88 self.object_keeper = []
89 self.alias_key = None
90
91 def represent_data(self, data):
92 # type: (Any) -> Any
93 if self.ignore_aliases(data):
94 self.alias_key = None
95 else:
96 self.alias_key = id(data)
97 if self.alias_key is not None:
98 if self.alias_key in self.represented_objects:
99 node = self.represented_objects[self.alias_key]
100 # if node is None:
101 # raise RepresenterError(
102 # "recursive objects are not allowed: %r" % data)
103 return node
104 # self.represented_objects[alias_key] = None
105 self.object_keeper.append(data)
106 data_types = type(data).__mro__
107 if PY2:
108 # if type(data) is types.InstanceType:
109 if isinstance(data, types.InstanceType):
110 data_types = get_classobj_bases(data.__class__) + list(data_types)
111 if data_types[0] in self.yaml_representers:
112 node = self.yaml_representers[data_types[0]](self, data)
113 else:
114 for data_type in data_types:
115 if data_type in self.yaml_multi_representers:
116 node = self.yaml_multi_representers[data_type](self, data)
117 break
118 else:
119 if None in self.yaml_multi_representers:
120 node = self.yaml_multi_representers[None](self, data)
121 elif None in self.yaml_representers:
122 node = self.yaml_representers[None](self, data)
123 else:
124 node = ScalarNode(None, text_type(data))
125 # if alias_key is not None:
126 # self.represented_objects[alias_key] = node
127 return node
128
129 def represent_key(self, data):
130 # type: (Any) -> Any
131 """
132 David Fraser: Extract a method to represent keys in mappings, so that
133 a subclass can choose not to quote them (for example)
134 used in represent_mapping
135 https://bitbucket.org/davidfraser/pyyaml/commits/d81df6eb95f20cac4a79eed95ae553b5c6f77b8c
136 """
137 return self.represent_data(data)
138
139 @classmethod
140 def add_representer(cls, data_type, representer):
141 # type: (Any, Any) -> None
142 if 'yaml_representers' not in cls.__dict__:
143 cls.yaml_representers = cls.yaml_representers.copy()
144 cls.yaml_representers[data_type] = representer
145
146 @classmethod
147 def add_multi_representer(cls, data_type, representer):
148 # type: (Any, Any) -> None
149 if 'yaml_multi_representers' not in cls.__dict__:
150 cls.yaml_multi_representers = cls.yaml_multi_representers.copy()
151 cls.yaml_multi_representers[data_type] = representer
152
153 def represent_scalar(self, tag, value, style=None, anchor=None):
154 # type: (Any, Any, Any, Any) -> Any
155 if style is None:
156 style = self.default_style
157 comment = None
158 if style and style[0] in '|>':
159 comment = getattr(value, 'comment', None)
160 if comment:
161 comment = [None, [comment]]
162 node = ScalarNode(tag, value, style=style, comment=comment, anchor=anchor)
163 if self.alias_key is not None:
164 self.represented_objects[self.alias_key] = node
165 return node
166
167 def represent_sequence(self, tag, sequence, flow_style=None):
168 # type: (Any, Any, Any) -> Any
169 value = [] # type: List[Any]
170 node = SequenceNode(tag, value, flow_style=flow_style)
171 if self.alias_key is not None:
172 self.represented_objects[self.alias_key] = node
173 best_style = True
174 for item in sequence:
175 node_item = self.represent_data(item)
176 if not (isinstance(node_item, ScalarNode) and not node_item.style):
177 best_style = False
178 value.append(node_item)
179 if flow_style is None:
180 if self.default_flow_style is not None:
181 node.flow_style = self.default_flow_style
182 else:
183 node.flow_style = best_style
184 return node
185
186 def represent_omap(self, tag, omap, flow_style=None):
187 # type: (Any, Any, Any) -> Any
188 value = [] # type: List[Any]
189 node = SequenceNode(tag, value, flow_style=flow_style)
190 if self.alias_key is not None:
191 self.represented_objects[self.alias_key] = node
192 best_style = True
193 for item_key in omap:
194 item_val = omap[item_key]
195 node_item = self.represent_data({item_key: item_val})
196 # if not (isinstance(node_item, ScalarNode) \
197 # and not node_item.style):
198 # best_style = False
199 value.append(node_item)
200 if flow_style is None:
201 if self.default_flow_style is not None:
202 node.flow_style = self.default_flow_style
203 else:
204 node.flow_style = best_style
205 return node
206
207 def represent_mapping(self, tag, mapping, flow_style=None):
208 # type: (Any, Any, Any) -> Any
209 value = [] # type: List[Any]
210 node = MappingNode(tag, value, flow_style=flow_style)
211 if self.alias_key is not None:
212 self.represented_objects[self.alias_key] = node
213 best_style = True
214 if hasattr(mapping, 'items'):
215 mapping = list(mapping.items())
216 if self.sort_base_mapping_type_on_output:
217 try:
218 mapping = sorted(mapping)
219 except TypeError:
220 pass
221 for item_key, item_value in mapping:
222 node_key = self.represent_key(item_key)
223 node_value = self.represent_data(item_value)
224 if not (isinstance(node_key, ScalarNode) and not node_key.style):
225 best_style = False
226 if not (isinstance(node_value, ScalarNode) and not node_value.style):
227 best_style = False
228 value.append((node_key, node_value))
229 if flow_style is None:
230 if self.default_flow_style is not None:
231 node.flow_style = self.default_flow_style
232 else:
233 node.flow_style = best_style
234 return node
235
236 def ignore_aliases(self, data):
237 # type: (Any) -> bool
238 return False
239
240
241 class SafeRepresenter(BaseRepresenter):
242 def ignore_aliases(self, data):
243 # type: (Any) -> bool
244 # https://docs.python.org/3/reference/expressions.html#parenthesized-forms :
245 # "i.e. two occurrences of the empty tuple may or may not yield the same object"
246 # so "data is ()" should not be used
247 if data is None or (isinstance(data, tuple) and data == ()):
248 return True
249 if isinstance(data, (binary_type, text_type, bool, int, float)):
250 return True
251 return False
252
253 def represent_none(self, data):
254 # type: (Any) -> Any
255 return self.represent_scalar(u'tag:yaml.org,2002:null', u'null')
256
257 if PY3:
258
259 def represent_str(self, data):
260 # type: (Any) -> Any
261 return self.represent_scalar(u'tag:yaml.org,2002:str', data)
262
263 def represent_binary(self, data):
264 # type: (Any) -> Any
265 if hasattr(base64, 'encodebytes'):
266 data = base64.encodebytes(data).decode('ascii')
267 else:
268 data = base64.encodestring(data).decode('ascii')
269 return self.represent_scalar(u'tag:yaml.org,2002:binary', data, style='|')
270
271 else:
272
273 def represent_str(self, data):
274 # type: (Any) -> Any
275 tag = None
276 style = None
277 try:
278 data = unicode(data, 'ascii')
279 tag = u'tag:yaml.org,2002:str'
280 except UnicodeDecodeError:
281 try:
282 data = unicode(data, 'utf-8')
283 tag = u'tag:yaml.org,2002:str'
284 except UnicodeDecodeError:
285 data = data.encode('base64')
286 tag = u'tag:yaml.org,2002:binary'
287 style = '|'
288 return self.represent_scalar(tag, data, style=style)
289
290 def represent_unicode(self, data):
291 # type: (Any) -> Any
292 return self.represent_scalar(u'tag:yaml.org,2002:str', data)
293
294 def represent_bool(self, data, anchor=None):
295 # type: (Any, Optional[Any]) -> Any
296 try:
297 value = self.dumper.boolean_representation[bool(data)]
298 except AttributeError:
299 if data:
300 value = u'true'
301 else:
302 value = u'false'
303 return self.represent_scalar(u'tag:yaml.org,2002:bool', value, anchor=anchor)
304
305 def represent_int(self, data):
306 # type: (Any) -> Any
307 return self.represent_scalar(u'tag:yaml.org,2002:int', text_type(data))
308
309 if PY2:
310
311 def represent_long(self, data):
312 # type: (Any) -> Any
313 return self.represent_scalar(u'tag:yaml.org,2002:int', text_type(data))
314
315 inf_value = 1e300
316 while repr(inf_value) != repr(inf_value * inf_value):
317 inf_value *= inf_value
318
319 def represent_float(self, data):
320 # type: (Any) -> Any
321 if data != data or (data == 0.0 and data == 1.0):
322 value = u'.nan'
323 elif data == self.inf_value:
324 value = u'.inf'
325 elif data == -self.inf_value:
326 value = u'-.inf'
327 else:
328 value = to_unicode(repr(data)).lower()
329 if getattr(self.serializer, 'use_version', None) == (1, 1):
330 if u'.' not in value and u'e' in value:
331 # Note that in some cases `repr(data)` represents a float number
332 # without the decimal parts. For instance:
333 # >>> repr(1e17)
334 # '1e17'
335 # Unfortunately, this is not a valid float representation according
336 # to the definition of the `!!float` tag in YAML 1.1. We fix
337 # this by adding '.0' before the 'e' symbol.
338 value = value.replace(u'e', u'.0e', 1)
339 return self.represent_scalar(u'tag:yaml.org,2002:float', value)
340
341 def represent_list(self, data):
342 # type: (Any) -> Any
343 # pairs = (len(data) > 0 and isinstance(data, list))
344 # if pairs:
345 # for item in data:
346 # if not isinstance(item, tuple) or len(item) != 2:
347 # pairs = False
348 # break
349 # if not pairs:
350 return self.represent_sequence(u'tag:yaml.org,2002:seq', data)
351
352 # value = []
353 # for item_key, item_value in data:
354 # value.append(self.represent_mapping(u'tag:yaml.org,2002:map',
355 # [(item_key, item_value)]))
356 # return SequenceNode(u'tag:yaml.org,2002:pairs', value)
357
358 def represent_dict(self, data):
359 # type: (Any) -> Any
360 return self.represent_mapping(u'tag:yaml.org,2002:map', data)
361
362 def represent_ordereddict(self, data):
363 # type: (Any) -> Any
364 return self.represent_omap(u'tag:yaml.org,2002:omap', data)
365
366 def represent_set(self, data):
367 # type: (Any) -> Any
368 value = {} # type: Dict[Any, None]
369 for key in data:
370 value[key] = None
371 return self.represent_mapping(u'tag:yaml.org,2002:set', value)
372
373 def represent_date(self, data):
374 # type: (Any) -> Any
375 value = to_unicode(data.isoformat())
376 return self.represent_scalar(u'tag:yaml.org,2002:timestamp', value)
377
378 def represent_datetime(self, data):
379 # type: (Any) -> Any
380 value = to_unicode(data.isoformat(' '))
381 return self.represent_scalar(u'tag:yaml.org,2002:timestamp', value)
382
383 def represent_yaml_object(self, tag, data, cls, flow_style=None):
384 # type: (Any, Any, Any, Any) -> Any
385 if hasattr(data, '__getstate__'):
386 state = data.__getstate__()
387 else:
388 state = data.__dict__.copy()
389 return self.represent_mapping(tag, state, flow_style=flow_style)
390
391 def represent_undefined(self, data):
392 # type: (Any) -> None
393 raise RepresenterError('cannot represent an object: %s' % (data,))
394
395
396 SafeRepresenter.add_representer(type(None), SafeRepresenter.represent_none)
397
398 SafeRepresenter.add_representer(str, SafeRepresenter.represent_str)
399
400 if PY2:
401 SafeRepresenter.add_representer(unicode, SafeRepresenter.represent_unicode)
402 else:
403 SafeRepresenter.add_representer(bytes, SafeRepresenter.represent_binary)
404
405 SafeRepresenter.add_representer(bool, SafeRepresenter.represent_bool)
406
407 SafeRepresenter.add_representer(int, SafeRepresenter.represent_int)
408
409 if PY2:
410 SafeRepresenter.add_representer(long, SafeRepresenter.represent_long)
411
412 SafeRepresenter.add_representer(float, SafeRepresenter.represent_float)
413
414 SafeRepresenter.add_representer(list, SafeRepresenter.represent_list)
415
416 SafeRepresenter.add_representer(tuple, SafeRepresenter.represent_list)
417
418 SafeRepresenter.add_representer(dict, SafeRepresenter.represent_dict)
419
420 SafeRepresenter.add_representer(set, SafeRepresenter.represent_set)
421
422 SafeRepresenter.add_representer(ordereddict, SafeRepresenter.represent_ordereddict)
423
424 if sys.version_info >= (2, 7):
425 import collections
426
427 SafeRepresenter.add_representer(
428 collections.OrderedDict, SafeRepresenter.represent_ordereddict
429 )
430
431 SafeRepresenter.add_representer(datetime.date, SafeRepresenter.represent_date)
432
433 SafeRepresenter.add_representer(datetime.datetime, SafeRepresenter.represent_datetime)
434
435 SafeRepresenter.add_representer(None, SafeRepresenter.represent_undefined)
436
437
438 class Representer(SafeRepresenter):
439 if PY2:
440
441 def represent_str(self, data):
442 # type: (Any) -> Any
443 tag = None
444 style = None
445 try:
446 data = unicode(data, 'ascii')
447 tag = u'tag:yaml.org,2002:str'
448 except UnicodeDecodeError:
449 try:
450 data = unicode(data, 'utf-8')
451 tag = u'tag:yaml.org,2002:python/str'
452 except UnicodeDecodeError:
453 data = data.encode('base64')
454 tag = u'tag:yaml.org,2002:binary'
455 style = '|'
456 return self.represent_scalar(tag, data, style=style)
457
458 def represent_unicode(self, data):
459 # type: (Any) -> Any
460 tag = None
461 try:
462 data.encode('ascii')
463 tag = u'tag:yaml.org,2002:python/unicode'
464 except UnicodeEncodeError:
465 tag = u'tag:yaml.org,2002:str'
466 return self.represent_scalar(tag, data)
467
468 def represent_long(self, data):
469 # type: (Any) -> Any
470 tag = u'tag:yaml.org,2002:int'
471 if int(data) is not data:
472 tag = u'tag:yaml.org,2002:python/long'
473 return self.represent_scalar(tag, to_unicode(data))
474
475 def represent_complex(self, data):
476 # type: (Any) -> Any
477 if data.imag == 0.0:
478 data = u'%r' % data.real
479 elif data.real == 0.0:
480 data = u'%rj' % data.imag
481 elif data.imag > 0:
482 data = u'%r+%rj' % (data.real, data.imag)
483 else:
484 data = u'%r%rj' % (data.real, data.imag)
485 return self.represent_scalar(u'tag:yaml.org,2002:python/complex', data)
486
487 def represent_tuple(self, data):
488 # type: (Any) -> Any
489 return self.represent_sequence(u'tag:yaml.org,2002:python/tuple', data)
490
491 def represent_name(self, data):
492 # type: (Any) -> Any
493 try:
494 name = u'%s.%s' % (data.__module__, data.__qualname__)
495 except AttributeError:
496 # probably PY2
497 name = u'%s.%s' % (data.__module__, data.__name__)
498 return self.represent_scalar(u'tag:yaml.org,2002:python/name:' + name, "")
499
500 def represent_module(self, data):
501 # type: (Any) -> Any
502 return self.represent_scalar(u'tag:yaml.org,2002:python/module:' + data.__name__, "")
503
504 if PY2:
505
506 def represent_instance(self, data):
507 # type: (Any) -> Any
508 # For instances of classic classes, we use __getinitargs__ and
509 # __getstate__ to serialize the data.
510
511 # If data.__getinitargs__ exists, the object must be reconstructed
512 # by calling cls(**args), where args is a tuple returned by
513 # __getinitargs__. Otherwise, the cls.__init__ method should never
514 # be called and the class instance is created by instantiating a
515 # trivial class and assigning to the instance's __class__ variable.
516
517 # If data.__getstate__ exists, it returns the state of the object.
518 # Otherwise, the state of the object is data.__dict__.
519
520 # We produce either a !!python/object or !!python/object/new node.
521 # If data.__getinitargs__ does not exist and state is a dictionary,
522 # we produce a !!python/object node . Otherwise we produce a
523 # !!python/object/new node.
524
525 cls = data.__class__
526 class_name = u'%s.%s' % (cls.__module__, cls.__name__)
527 args = None
528 state = None
529 if hasattr(data, '__getinitargs__'):
530 args = list(data.__getinitargs__())
531 if hasattr(data, '__getstate__'):
532 state = data.__getstate__()
533 else:
534 state = data.__dict__
535 if args is None and isinstance(state, dict):
536 return self.represent_mapping(
537 u'tag:yaml.org,2002:python/object:' + class_name, state
538 )
539 if isinstance(state, dict) and not state:
540 return self.represent_sequence(
541 u'tag:yaml.org,2002:python/object/new:' + class_name, args
542 )
543 value = {}
544 if bool(args):
545 value['args'] = args
546 value['state'] = state # type: ignore
547 return self.represent_mapping(
548 u'tag:yaml.org,2002:python/object/new:' + class_name, value
549 )
550
551 def represent_object(self, data):
552 # type: (Any) -> Any
553 # We use __reduce__ API to save the data. data.__reduce__ returns
554 # a tuple of length 2-5:
555 # (function, args, state, listitems, dictitems)
556
557 # For reconstructing, we calls function(*args), then set its state,
558 # listitems, and dictitems if they are not None.
559
560 # A special case is when function.__name__ == '__newobj__'. In this
561 # case we create the object with args[0].__new__(*args).
562
563 # Another special case is when __reduce__ returns a string - we don't
564 # support it.
565
566 # We produce a !!python/object, !!python/object/new or
567 # !!python/object/apply node.
568
569 cls = type(data)
570 if cls in copyreg.dispatch_table:
571 reduce = copyreg.dispatch_table[cls](data)
572 elif hasattr(data, '__reduce_ex__'):
573 reduce = data.__reduce_ex__(2)
574 elif hasattr(data, '__reduce__'):
575 reduce = data.__reduce__()
576 else:
577 raise RepresenterError('cannot represent object: %r' % (data,))
578 reduce = (list(reduce) + [None] * 5)[:5]
579 function, args, state, listitems, dictitems = reduce
580 args = list(args)
581 if state is None:
582 state = {}
583 if listitems is not None:
584 listitems = list(listitems)
585 if dictitems is not None:
586 dictitems = dict(dictitems)
587 if function.__name__ == '__newobj__':
588 function = args[0]
589 args = args[1:]
590 tag = u'tag:yaml.org,2002:python/object/new:'
591 newobj = True
592 else:
593 tag = u'tag:yaml.org,2002:python/object/apply:'
594 newobj = False
595 try:
596 function_name = u'%s.%s' % (function.__module__, function.__qualname__)
597 except AttributeError:
598 # probably PY2
599 function_name = u'%s.%s' % (function.__module__, function.__name__)
600 if not args and not listitems and not dictitems and isinstance(state, dict) and newobj:
601 return self.represent_mapping(
602 u'tag:yaml.org,2002:python/object:' + function_name, state
603 )
604 if not listitems and not dictitems and isinstance(state, dict) and not state:
605 return self.represent_sequence(tag + function_name, args)
606 value = {}
607 if args:
608 value['args'] = args
609 if state or not isinstance(state, dict):
610 value['state'] = state
611 if listitems:
612 value['listitems'] = listitems
613 if dictitems:
614 value['dictitems'] = dictitems
615 return self.represent_mapping(tag + function_name, value)
616
617
618 if PY2:
619 Representer.add_representer(str, Representer.represent_str)
620
621 Representer.add_representer(unicode, Representer.represent_unicode)
622
623 Representer.add_representer(long, Representer.represent_long)
624
625 Representer.add_representer(complex, Representer.represent_complex)
626
627 Representer.add_representer(tuple, Representer.represent_tuple)
628
629 Representer.add_representer(type, Representer.represent_name)
630
631 if PY2:
632 Representer.add_representer(types.ClassType, Representer.represent_name)
633
634 Representer.add_representer(types.FunctionType, Representer.represent_name)
635
636 Representer.add_representer(types.BuiltinFunctionType, Representer.represent_name)
637
638 Representer.add_representer(types.ModuleType, Representer.represent_module)
639
640 if PY2:
641 Representer.add_multi_representer(types.InstanceType, Representer.represent_instance)
642
643 Representer.add_multi_representer(object, Representer.represent_object)
644
645 Representer.add_multi_representer(type, Representer.represent_name)
646
647 from ruamel.yaml.comments import (
648 CommentedMap,
649 CommentedOrderedMap,
650 CommentedSeq,
651 CommentedKeySeq,
652 CommentedKeyMap,
653 CommentedSet,
654 comment_attrib,
655 merge_attrib,
656 TaggedScalar,
657 ) # NOQA
658
659
660 class RoundTripRepresenter(SafeRepresenter):
661 # need to add type here and write out the .comment
662 # in serializer and emitter
663
664 def __init__(self, default_style=None, default_flow_style=None, dumper=None):
665 # type: (Any, Any, Any) -> None
666 if not hasattr(dumper, 'typ') and default_flow_style is None:
667 default_flow_style = False
668 SafeRepresenter.__init__(
669 self,
670 default_style=default_style,
671 default_flow_style=default_flow_style,
672 dumper=dumper,
673 )
674
675 def ignore_aliases(self, data):
676 # type: (Any) -> bool
677 try:
678 if data.anchor is not None and data.anchor.value is not None:
679 return False
680 except AttributeError:
681 pass
682 return SafeRepresenter.ignore_aliases(self, data)
683
684 def represent_none(self, data):
685 # type: (Any) -> Any
686 if len(self.represented_objects) == 0 and not self.serializer.use_explicit_start:
687 # this will be open ended (although it is not yet)
688 return self.represent_scalar(u'tag:yaml.org,2002:null', u'null')
689 return self.represent_scalar(u'tag:yaml.org,2002:null', "")
690
691 def represent_literal_scalarstring(self, data):
692 # type: (Any) -> Any
693 tag = None
694 style = '|'
695 anchor = data.yaml_anchor(any=True)
696 if PY2 and not isinstance(data, unicode):
697 data = unicode(data, 'ascii')
698 tag = u'tag:yaml.org,2002:str'
699 return self.represent_scalar(tag, data, style=style, anchor=anchor)
700
701 represent_preserved_scalarstring = represent_literal_scalarstring
702
703 def represent_folded_scalarstring(self, data):
704 # type: (Any) -> Any
705 tag = None
706 style = '>'
707 anchor = data.yaml_anchor(any=True)
708 for fold_pos in reversed(getattr(data, 'fold_pos', [])):
709 if (
710 data[fold_pos] == ' '
711 and (fold_pos > 0 and not data[fold_pos - 1].isspace())
712 and (fold_pos < len(data) and not data[fold_pos + 1].isspace())
713 ):
714 data = data[:fold_pos] + '\a' + data[fold_pos:]
715 if PY2 and not isinstance(data, unicode):
716 data = unicode(data, 'ascii')
717 tag = u'tag:yaml.org,2002:str'
718 return self.represent_scalar(tag, data, style=style, anchor=anchor)
719
720 def represent_single_quoted_scalarstring(self, data):
721 # type: (Any) -> Any
722 tag = None
723 style = "'"
724 anchor = data.yaml_anchor(any=True)
725 if PY2 and not isinstance(data, unicode):
726 data = unicode(data, 'ascii')
727 tag = u'tag:yaml.org,2002:str'
728 return self.represent_scalar(tag, data, style=style, anchor=anchor)
729
730 def represent_double_quoted_scalarstring(self, data):
731 # type: (Any) -> Any
732 tag = None
733 style = '"'
734 anchor = data.yaml_anchor(any=True)
735 if PY2 and not isinstance(data, unicode):
736 data = unicode(data, 'ascii')
737 tag = u'tag:yaml.org,2002:str'
738 return self.represent_scalar(tag, data, style=style, anchor=anchor)
739
740 def represent_plain_scalarstring(self, data):
741 # type: (Any) -> Any
742 tag = None
743 style = ''
744 anchor = data.yaml_anchor(any=True)
745 if PY2 and not isinstance(data, unicode):
746 data = unicode(data, 'ascii')
747 tag = u'tag:yaml.org,2002:str'
748 return self.represent_scalar(tag, data, style=style, anchor=anchor)
749
750 def insert_underscore(self, prefix, s, underscore, anchor=None):
751 # type: (Any, Any, Any, Any) -> Any
752 if underscore is None:
753 return self.represent_scalar(u'tag:yaml.org,2002:int', prefix + s, anchor=anchor)
754 if underscore[0]:
755 sl = list(s)
756 pos = len(s) - underscore[0]
757 while pos > 0:
758 sl.insert(pos, '_')
759 pos -= underscore[0]
760 s = "".join(sl)
761 if underscore[1]:
762 s = '_' + s
763 if underscore[2]:
764 s += '_'
765 return self.represent_scalar(u'tag:yaml.org,2002:int', prefix + s, anchor=anchor)
766
767 def represent_scalar_int(self, data):
768 # type: (Any) -> Any
769 if data._width is not None:
770 s = '{:0{}d}'.format(data, data._width)
771 else:
772 s = format(data, 'd')
773 anchor = data.yaml_anchor(any=True)
774 return self.insert_underscore("", s, data._underscore, anchor=anchor)
775
776 def represent_binary_int(self, data):
777 # type: (Any) -> Any
778 if data._width is not None:
779 # cannot use '{:#0{}b}', that strips the zeros
780 s = '{:0{}b}'.format(data, data._width)
781 else:
782 s = format(data, 'b')
783 anchor = data.yaml_anchor(any=True)
784 return self.insert_underscore('0b', s, data._underscore, anchor=anchor)
785
786 def represent_octal_int(self, data):
787 # type: (Any) -> Any
788 if data._width is not None:
789 # cannot use '{:#0{}o}', that strips the zeros
790 s = '{:0{}o}'.format(data, data._width)
791 else:
792 s = format(data, 'o')
793 anchor = data.yaml_anchor(any=True)
794 return self.insert_underscore('0o', s, data._underscore, anchor=anchor)
795
796 def represent_hex_int(self, data):
797 # type: (Any) -> Any
798 if data._width is not None:
799 # cannot use '{:#0{}x}', that strips the zeros
800 s = '{:0{}x}'.format(data, data._width)
801 else:
802 s = format(data, 'x')
803 anchor = data.yaml_anchor(any=True)
804 return self.insert_underscore('0x', s, data._underscore, anchor=anchor)
805
806 def represent_hex_caps_int(self, data):
807 # type: (Any) -> Any
808 if data._width is not None:
809 # cannot use '{:#0{}X}', that strips the zeros
810 s = '{:0{}X}'.format(data, data._width)
811 else:
812 s = format(data, 'X')
813 anchor = data.yaml_anchor(any=True)
814 return self.insert_underscore('0x', s, data._underscore, anchor=anchor)
815
816 def represent_scalar_float(self, data):
817 # type: (Any) -> Any
818 """ this is way more complicated """
819 value = None
820 anchor = data.yaml_anchor(any=True)
821 if data != data or (data == 0.0 and data == 1.0):
822 value = u'.nan'
823 elif data == self.inf_value:
824 value = u'.inf'
825 elif data == -self.inf_value:
826 value = u'-.inf'
827 if value:
828 return self.represent_scalar(u'tag:yaml.org,2002:float', value, anchor=anchor)
829 if data._exp is None and data._prec > 0 and data._prec == data._width - 1:
830 # no exponent, but trailing dot
831 value = u'{}{:d}.'.format(data._m_sign if data._m_sign else "", abs(int(data)))
832 elif data._exp is None:
833 # no exponent, "normal" dot
834 prec = data._prec
835 ms = data._m_sign if data._m_sign else ""
836 # -1 for the dot
837 value = u'{}{:0{}.{}f}'.format(
838 ms, abs(data), data._width - len(ms), data._width - prec - 1
839 )
840 if prec == 0 or (prec == 1 and ms != ""):
841 value = value.replace(u'0.', u'.')
842 while len(value) < data._width:
843 value += u'0'
844 else:
845 # exponent
846 m, es = u'{:{}.{}e}'.format(
847 # data, data._width, data._width - data._prec + (1 if data._m_sign else 0)
848 data,
849 data._width,
850 data._width + (1 if data._m_sign else 0),
851 ).split('e')
852 w = data._width if data._prec > 0 else (data._width + 1)
853 if data < 0:
854 w += 1
855 m = m[:w]
856 e = int(es)
857 m1, m2 = m.split('.') # always second?
858 while len(m1) + len(m2) < data._width - (1 if data._prec >= 0 else 0):
859 m2 += u'0'
860 if data._m_sign and data > 0:
861 m1 = '+' + m1
862 esgn = u'+' if data._e_sign else ""
863 if data._prec < 0: # mantissa without dot
864 if m2 != u'0':
865 e -= len(m2)
866 else:
867 m2 = ""
868 while (len(m1) + len(m2) - (1 if data._m_sign else 0)) < data._width:
869 m2 += u'0'
870 e -= 1
871 value = m1 + m2 + data._exp + u'{:{}0{}d}'.format(e, esgn, data._e_width)
872 elif data._prec == 0: # mantissa with trailing dot
873 e -= len(m2)
874 value = (
875 m1 + m2 + u'.' + data._exp + u'{:{}0{}d}'.format(e, esgn, data._e_width)
876 )
877 else:
878 if data._m_lead0 > 0:
879 m2 = u'0' * (data._m_lead0 - 1) + m1 + m2
880 m1 = u'0'
881 m2 = m2[: -data._m_lead0] # these should be zeros
882 e += data._m_lead0
883 while len(m1) < data._prec:
884 m1 += m2[0]
885 m2 = m2[1:]
886 e -= 1
887 value = (
888 m1 + u'.' + m2 + data._exp + u'{:{}0{}d}'.format(e, esgn, data._e_width)
889 )
890
891 if value is None:
892 value = to_unicode(repr(data)).lower()
893 return self.represent_scalar(u'tag:yaml.org,2002:float', value, anchor=anchor)
894
895 def represent_sequence(self, tag, sequence, flow_style=None):
896 # type: (Any, Any, Any) -> Any
897 value = [] # type: List[Any]
898 # if the flow_style is None, the flow style tacked on to the object
899 # explicitly will be taken. If that is None as well the default flow
900 # style rules
901 try:
902 flow_style = sequence.fa.flow_style(flow_style)
903 except AttributeError:
904 flow_style = flow_style
905 try:
906 anchor = sequence.yaml_anchor()
907 except AttributeError:
908 anchor = None
909 node = SequenceNode(tag, value, flow_style=flow_style, anchor=anchor)
910 if self.alias_key is not None:
911 self.represented_objects[self.alias_key] = node
912 best_style = True
913 try:
914 comment = getattr(sequence, comment_attrib)
915 node.comment = comment.comment
916 # reset any comment already printed information
917 if node.comment and node.comment[1]:
918 for ct in node.comment[1]:
919 ct.reset()
920 item_comments = comment.items
921 for v in item_comments.values():
922 if v and v[1]:
923 for ct in v[1]:
924 ct.reset()
925 item_comments = comment.items
926 node.comment = comment.comment
927 try:
928 node.comment.append(comment.end)
929 except AttributeError:
930 pass
931 except AttributeError:
932 item_comments = {}
933 for idx, item in enumerate(sequence):
934 node_item = self.represent_data(item)
935 self.merge_comments(node_item, item_comments.get(idx))
936 if not (isinstance(node_item, ScalarNode) and not node_item.style):
937 best_style = False
938 value.append(node_item)
939 if flow_style is None:
940 if len(sequence) != 0 and self.default_flow_style is not None:
941 node.flow_style = self.default_flow_style
942 else:
943 node.flow_style = best_style
944 return node
945
946 def merge_comments(self, node, comments):
947 # type: (Any, Any) -> Any
948 if comments is None:
949 assert hasattr(node, 'comment')
950 return node
951 if getattr(node, 'comment', None) is not None:
952 for idx, val in enumerate(comments):
953 if idx >= len(node.comment):
954 continue
955 nc = node.comment[idx]
956 if nc is not None:
957 assert val is None or val == nc
958 comments[idx] = nc
959 node.comment = comments
960 return node
961
962 def represent_key(self, data):
963 # type: (Any) -> Any
964 if isinstance(data, CommentedKeySeq):
965 self.alias_key = None
966 return self.represent_sequence(u'tag:yaml.org,2002:seq', data, flow_style=True)
967 if isinstance(data, CommentedKeyMap):
968 self.alias_key = None
969 return self.represent_mapping(u'tag:yaml.org,2002:map', data, flow_style=True)
970 return SafeRepresenter.represent_key(self, data)
971
972 def represent_mapping(self, tag, mapping, flow_style=None):
973 # type: (Any, Any, Any) -> Any
974 value = [] # type: List[Any]
975 try:
976 flow_style = mapping.fa.flow_style(flow_style)
977 except AttributeError:
978 flow_style = flow_style
979 try:
980 anchor = mapping.yaml_anchor()
981 except AttributeError:
982 anchor = None
983 node = MappingNode(tag, value, flow_style=flow_style, anchor=anchor)
984 if self.alias_key is not None:
985 self.represented_objects[self.alias_key] = node
986 best_style = True
987 # no sorting! !!
988 try:
989 comment = getattr(mapping, comment_attrib)
990 node.comment = comment.comment
991 if node.comment and node.comment[1]:
992 for ct in node.comment[1]:
993 ct.reset()
994 item_comments = comment.items
995 for v in item_comments.values():
996 if v and v[1]:
997 for ct in v[1]:
998 ct.reset()
999 try:
1000 node.comment.append(comment.end)
1001 except AttributeError:
1002 pass
1003 except AttributeError:
1004 item_comments = {}
1005 merge_list = [m[1] for m in getattr(mapping, merge_attrib, [])]
1006 try:
1007 merge_pos = getattr(mapping, merge_attrib, [[0]])[0][0]
1008 except IndexError:
1009 merge_pos = 0
1010 item_count = 0
1011 if bool(merge_list):
1012 items = mapping.non_merged_items()
1013 else:
1014 items = mapping.items()
1015 for item_key, item_value in items:
1016 item_count += 1
1017 node_key = self.represent_key(item_key)
1018 node_value = self.represent_data(item_value)
1019 item_comment = item_comments.get(item_key)
1020 if item_comment:
1021 assert getattr(node_key, 'comment', None) is None
1022 node_key.comment = item_comment[:2]
1023 nvc = getattr(node_value, 'comment', None)
1024 if nvc is not None: # end comment already there
1025 nvc[0] = item_comment[2]
1026 nvc[1] = item_comment[3]
1027 else:
1028 node_value.comment = item_comment[2:]
1029 if not (isinstance(node_key, ScalarNode) and not node_key.style):
1030 best_style = False
1031 if not (isinstance(node_value, ScalarNode) and not node_value.style):
1032 best_style = False
1033 value.append((node_key, node_value))
1034 if flow_style is None:
1035 if ((item_count != 0) or bool(merge_list)) and self.default_flow_style is not None:
1036 node.flow_style = self.default_flow_style
1037 else:
1038 node.flow_style = best_style
1039 if bool(merge_list):
1040 # because of the call to represent_data here, the anchors
1041 # are marked as being used and thereby created
1042 if len(merge_list) == 1:
1043 arg = self.represent_data(merge_list[0])
1044 else:
1045 arg = self.represent_data(merge_list)
1046 arg.flow_style = True
1047 value.insert(merge_pos, (ScalarNode(u'tag:yaml.org,2002:merge', '<<'), arg))
1048 return node
1049
1050 def represent_omap(self, tag, omap, flow_style=None):
1051 # type: (Any, Any, Any) -> Any
1052 value = [] # type: List[Any]
1053 try:
1054 flow_style = omap.fa.flow_style(flow_style)
1055 except AttributeError:
1056 flow_style = flow_style
1057 try:
1058 anchor = omap.yaml_anchor()
1059 except AttributeError:
1060 anchor = None
1061 node = SequenceNode(tag, value, flow_style=flow_style, anchor=anchor)
1062 if self.alias_key is not None:
1063 self.represented_objects[self.alias_key] = node
1064 best_style = True
1065 try:
1066 comment = getattr(omap, comment_attrib)
1067 node.comment = comment.comment
1068 if node.comment and node.comment[1]:
1069 for ct in node.comment[1]:
1070 ct.reset()
1071 item_comments = comment.items
1072 for v in item_comments.values():
1073 if v and v[1]:
1074 for ct in v[1]:
1075 ct.reset()
1076 try:
1077 node.comment.append(comment.end)
1078 except AttributeError:
1079 pass
1080 except AttributeError:
1081 item_comments = {}
1082 for item_key in omap:
1083 item_val = omap[item_key]
1084 node_item = self.represent_data({item_key: item_val})
1085 # node_item.flow_style = False
1086 # node item has two scalars in value: node_key and node_value
1087 item_comment = item_comments.get(item_key)
1088 if item_comment:
1089 if item_comment[1]:
1090 node_item.comment = [None, item_comment[1]]
1091 assert getattr(node_item.value[0][0], 'comment', None) is None
1092 node_item.value[0][0].comment = [item_comment[0], None]
1093 nvc = getattr(node_item.value[0][1], 'comment', None)
1094 if nvc is not None: # end comment already there
1095 nvc[0] = item_comment[2]
1096 nvc[1] = item_comment[3]
1097 else:
1098 node_item.value[0][1].comment = item_comment[2:]
1099 # if not (isinstance(node_item, ScalarNode) \
1100 # and not node_item.style):
1101 # best_style = False
1102 value.append(node_item)
1103 if flow_style is None:
1104 if self.default_flow_style is not None:
1105 node.flow_style = self.default_flow_style
1106 else:
1107 node.flow_style = best_style
1108 return node
1109
1110 def represent_set(self, setting):
1111 # type: (Any) -> Any
1112 flow_style = False
1113 tag = u'tag:yaml.org,2002:set'
1114 # return self.represent_mapping(tag, value)
1115 value = [] # type: List[Any]
1116 flow_style = setting.fa.flow_style(flow_style)
1117 try:
1118 anchor = setting.yaml_anchor()
1119 except AttributeError:
1120 anchor = None
1121 node = MappingNode(tag, value, flow_style=flow_style, anchor=anchor)
1122 if self.alias_key is not None:
1123 self.represented_objects[self.alias_key] = node
1124 best_style = True
1125 # no sorting! !!
1126 try:
1127 comment = getattr(setting, comment_attrib)
1128 node.comment = comment.comment
1129 if node.comment and node.comment[1]:
1130 for ct in node.comment[1]:
1131 ct.reset()
1132 item_comments = comment.items
1133 for v in item_comments.values():
1134 if v and v[1]:
1135 for ct in v[1]:
1136 ct.reset()
1137 try:
1138 node.comment.append(comment.end)
1139 except AttributeError:
1140 pass
1141 except AttributeError:
1142 item_comments = {}
1143 for item_key in setting.odict:
1144 node_key = self.represent_key(item_key)
1145 node_value = self.represent_data(None)
1146 item_comment = item_comments.get(item_key)
1147 if item_comment:
1148 assert getattr(node_key, 'comment', None) is None
1149 node_key.comment = item_comment[:2]
1150 node_key.style = node_value.style = '?'
1151 if not (isinstance(node_key, ScalarNode) and not node_key.style):
1152 best_style = False
1153 if not (isinstance(node_value, ScalarNode) and not node_value.style):
1154 best_style = False
1155 value.append((node_key, node_value))
1156 best_style = best_style
1157 return node
1158
1159 def represent_dict(self, data):
1160 # type: (Any) -> Any
1161 """write out tag if saved on loading"""
1162 try:
1163 t = data.tag.value
1164 except AttributeError:
1165 t = None
1166 if t:
1167 if t.startswith('!!'):
1168 tag = 'tag:yaml.org,2002:' + t[2:]
1169 else:
1170 tag = t
1171 else:
1172 tag = u'tag:yaml.org,2002:map'
1173 return self.represent_mapping(tag, data)
1174
1175 def represent_list(self, data):
1176 # type: (Any) -> Any
1177 try:
1178 t = data.tag.value
1179 except AttributeError:
1180 t = None
1181 if t:
1182 if t.startswith('!!'):
1183 tag = 'tag:yaml.org,2002:' + t[2:]
1184 else:
1185 tag = t
1186 else:
1187 tag = u'tag:yaml.org,2002:seq'
1188 return self.represent_sequence(tag, data)
1189
1190 def represent_datetime(self, data):
1191 # type: (Any) -> Any
1192 inter = 'T' if data._yaml['t'] else ' '
1193 _yaml = data._yaml
1194 if _yaml['delta']:
1195 data += _yaml['delta']
1196 value = data.isoformat(inter)
1197 else:
1198 value = data.isoformat(inter)
1199 if _yaml['tz']:
1200 value += _yaml['tz']
1201 return self.represent_scalar(u'tag:yaml.org,2002:timestamp', to_unicode(value))
1202
1203 def represent_tagged_scalar(self, data):
1204 # type: (Any) -> Any
1205 try:
1206 tag = data.tag.value
1207 except AttributeError:
1208 tag = None
1209 try:
1210 anchor = data.yaml_anchor()
1211 except AttributeError:
1212 anchor = None
1213 return self.represent_scalar(tag, data.value, style=data.style, anchor=anchor)
1214
1215 def represent_scalar_bool(self, data):
1216 # type: (Any) -> Any
1217 try:
1218 anchor = data.yaml_anchor()
1219 except AttributeError:
1220 anchor = None
1221 return SafeRepresenter.represent_bool(self, data, anchor=anchor)
1222
1223
1224 RoundTripRepresenter.add_representer(type(None), RoundTripRepresenter.represent_none)
1225
1226 RoundTripRepresenter.add_representer(
1227 LiteralScalarString, RoundTripRepresenter.represent_literal_scalarstring
1228 )
1229
1230 RoundTripRepresenter.add_representer(
1231 FoldedScalarString, RoundTripRepresenter.represent_folded_scalarstring
1232 )
1233
1234 RoundTripRepresenter.add_representer(
1235 SingleQuotedScalarString, RoundTripRepresenter.represent_single_quoted_scalarstring
1236 )
1237
1238 RoundTripRepresenter.add_representer(
1239 DoubleQuotedScalarString, RoundTripRepresenter.represent_double_quoted_scalarstring
1240 )
1241
1242 RoundTripRepresenter.add_representer(
1243 PlainScalarString, RoundTripRepresenter.represent_plain_scalarstring
1244 )
1245
1246 RoundTripRepresenter.add_representer(ScalarInt, RoundTripRepresenter.represent_scalar_int)
1247
1248 RoundTripRepresenter.add_representer(BinaryInt, RoundTripRepresenter.represent_binary_int)
1249
1250 RoundTripRepresenter.add_representer(OctalInt, RoundTripRepresenter.represent_octal_int)
1251
1252 RoundTripRepresenter.add_representer(HexInt, RoundTripRepresenter.represent_hex_int)
1253
1254 RoundTripRepresenter.add_representer(HexCapsInt, RoundTripRepresenter.represent_hex_caps_int)
1255
1256 RoundTripRepresenter.add_representer(ScalarFloat, RoundTripRepresenter.represent_scalar_float)
1257
1258 RoundTripRepresenter.add_representer(ScalarBoolean, RoundTripRepresenter.represent_scalar_bool)
1259
1260 RoundTripRepresenter.add_representer(CommentedSeq, RoundTripRepresenter.represent_list)
1261
1262 RoundTripRepresenter.add_representer(CommentedMap, RoundTripRepresenter.represent_dict)
1263
1264 RoundTripRepresenter.add_representer(
1265 CommentedOrderedMap, RoundTripRepresenter.represent_ordereddict
1266 )
1267
1268 if sys.version_info >= (2, 7):
1269 import collections
1270
1271 RoundTripRepresenter.add_representer(
1272 collections.OrderedDict, RoundTripRepresenter.represent_ordereddict
1273 )
1274
1275 RoundTripRepresenter.add_representer(CommentedSet, RoundTripRepresenter.represent_set)
1276
1277 RoundTripRepresenter.add_representer(
1278 TaggedScalar, RoundTripRepresenter.represent_tagged_scalar
1279 )
1280
1281 RoundTripRepresenter.add_representer(TimeStamp, RoundTripRepresenter.represent_datetime)