Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/ruamel/yaml/constructor.py @ 0:26e78fe6e8c4 draft
"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
| author | shellac |
|---|---|
| date | Sat, 02 May 2020 07:14:21 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:26e78fe6e8c4 |
|---|---|
| 1 # coding: utf-8 | |
| 2 | |
| 3 from __future__ import print_function, absolute_import, division | |
| 4 | |
| 5 import datetime | |
| 6 import base64 | |
| 7 import binascii | |
| 8 import re | |
| 9 import sys | |
| 10 import types | |
| 11 import warnings | |
| 12 | |
| 13 # fmt: off | |
| 14 from ruamel.yaml.error import (MarkedYAMLError, MarkedYAMLFutureWarning, | |
| 15 MantissaNoDotYAML1_1Warning) | |
| 16 from ruamel.yaml.nodes import * # NOQA | |
| 17 from ruamel.yaml.nodes import (SequenceNode, MappingNode, ScalarNode) | |
| 18 from ruamel.yaml.compat import (utf8, builtins_module, to_str, PY2, PY3, # NOQA | |
| 19 ordereddict, text_type, nprint, nprintf, version_tnf, | |
| 20 Hashable, MutableSequence, MutableMapping) | |
| 21 from ruamel.yaml.comments import * # NOQA | |
| 22 from ruamel.yaml.comments import (CommentedMap, CommentedOrderedMap, CommentedSet, | |
| 23 CommentedKeySeq, CommentedSeq, TaggedScalar, | |
| 24 CommentedKeyMap) | |
| 25 from ruamel.yaml.scalarstring import (SingleQuotedScalarString, DoubleQuotedScalarString, | |
| 26 LiteralScalarString, FoldedScalarString, | |
| 27 PlainScalarString, ScalarString,) | |
| 28 from ruamel.yaml.scalarint import ScalarInt, BinaryInt, OctalInt, HexInt, HexCapsInt | |
| 29 from ruamel.yaml.scalarfloat import ScalarFloat | |
| 30 from ruamel.yaml.scalarbool import ScalarBoolean | |
| 31 from ruamel.yaml.timestamp import TimeStamp | |
| 32 from ruamel.yaml.util import RegExp | |
| 33 | |
| 34 if False: # MYPY | |
| 35 from typing import Any, Dict, List, Set, Generator, Union, Optional # NOQA | |
| 36 | |
| 37 | |
| 38 __all__ = ['BaseConstructor', 'SafeConstructor', 'Constructor', | |
| 39 'ConstructorError', 'RoundTripConstructor'] | |
| 40 # fmt: on | |
| 41 | |
| 42 | |
| 43 class ConstructorError(MarkedYAMLError): | |
| 44 pass | |
| 45 | |
| 46 | |
| 47 class DuplicateKeyFutureWarning(MarkedYAMLFutureWarning): | |
| 48 pass | |
| 49 | |
| 50 | |
| 51 class DuplicateKeyError(MarkedYAMLFutureWarning): | |
| 52 pass | |
| 53 | |
| 54 | |
| 55 class BaseConstructor(object): | |
| 56 | |
| 57 yaml_constructors = {} # type: Dict[Any, Any] | |
| 58 yaml_multi_constructors = {} # type: Dict[Any, Any] | |
| 59 | |
| 60 def __init__(self, preserve_quotes=None, loader=None): | |
| 61 # type: (Optional[bool], Any) -> None | |
| 62 self.loader = loader | |
| 63 if self.loader is not None and getattr(self.loader, '_constructor', None) is None: | |
| 64 self.loader._constructor = self | |
| 65 self.loader = loader | |
| 66 self.yaml_base_dict_type = dict | |
| 67 self.yaml_base_list_type = list | |
| 68 self.constructed_objects = {} # type: Dict[Any, Any] | |
| 69 self.recursive_objects = {} # type: Dict[Any, Any] | |
| 70 self.state_generators = [] # type: List[Any] | |
| 71 self.deep_construct = False | |
| 72 self._preserve_quotes = preserve_quotes | |
| 73 self.allow_duplicate_keys = version_tnf((0, 15, 1), (0, 16)) | |
| 74 | |
| 75 @property | |
| 76 def composer(self): | |
| 77 # type: () -> Any | |
| 78 if hasattr(self.loader, 'typ'): | |
| 79 return self.loader.composer | |
| 80 try: | |
| 81 return self.loader._composer | |
| 82 except AttributeError: | |
| 83 sys.stdout.write('slt {}\n'.format(type(self))) | |
| 84 sys.stdout.write('slc {}\n'.format(self.loader._composer)) | |
| 85 sys.stdout.write('{}\n'.format(dir(self))) | |
| 86 raise | |
| 87 | |
| 88 @property | |
| 89 def resolver(self): | |
| 90 # type: () -> Any | |
| 91 if hasattr(self.loader, 'typ'): | |
| 92 return self.loader.resolver | |
| 93 return self.loader._resolver | |
| 94 | |
| 95 def check_data(self): | |
| 96 # type: () -> Any | |
| 97 # If there are more documents available? | |
| 98 return self.composer.check_node() | |
| 99 | |
| 100 def get_data(self): | |
| 101 # type: () -> Any | |
| 102 # Construct and return the next document. | |
| 103 if self.composer.check_node(): | |
| 104 return self.construct_document(self.composer.get_node()) | |
| 105 | |
| 106 def get_single_data(self): | |
| 107 # type: () -> Any | |
| 108 # Ensure that the stream contains a single document and construct it. | |
| 109 node = self.composer.get_single_node() | |
| 110 if node is not None: | |
| 111 return self.construct_document(node) | |
| 112 return None | |
| 113 | |
| 114 def construct_document(self, node): | |
| 115 # type: (Any) -> Any | |
| 116 data = self.construct_object(node) | |
| 117 while bool(self.state_generators): | |
| 118 state_generators = self.state_generators | |
| 119 self.state_generators = [] | |
| 120 for generator in state_generators: | |
| 121 for _dummy in generator: | |
| 122 pass | |
| 123 self.constructed_objects = {} | |
| 124 self.recursive_objects = {} | |
| 125 self.deep_construct = False | |
| 126 return data | |
| 127 | |
| 128 def construct_object(self, node, deep=False): | |
| 129 # type: (Any, bool) -> Any | |
| 130 """deep is True when creating an object/mapping recursively, | |
| 131 in that case want the underlying elements available during construction | |
| 132 """ | |
| 133 if node in self.constructed_objects: | |
| 134 return self.constructed_objects[node] | |
| 135 if deep: | |
| 136 old_deep = self.deep_construct | |
| 137 self.deep_construct = True | |
| 138 if node in self.recursive_objects: | |
| 139 return self.recursive_objects[node] | |
| 140 # raise ConstructorError( | |
| 141 # None, None, 'found unconstructable recursive node', node.start_mark | |
| 142 # ) | |
| 143 self.recursive_objects[node] = None | |
| 144 constructor = None # type: Any | |
| 145 tag_suffix = None | |
| 146 if node.tag in self.yaml_constructors: | |
| 147 constructor = self.yaml_constructors[node.tag] | |
| 148 else: | |
| 149 for tag_prefix in self.yaml_multi_constructors: | |
| 150 if node.tag.startswith(tag_prefix): | |
| 151 tag_suffix = node.tag[len(tag_prefix) :] | |
| 152 constructor = self.yaml_multi_constructors[tag_prefix] | |
| 153 break | |
| 154 else: | |
| 155 if None in self.yaml_multi_constructors: | |
| 156 tag_suffix = node.tag | |
| 157 constructor = self.yaml_multi_constructors[None] | |
| 158 elif None in self.yaml_constructors: | |
| 159 constructor = self.yaml_constructors[None] | |
| 160 elif isinstance(node, ScalarNode): | |
| 161 constructor = self.__class__.construct_scalar | |
| 162 elif isinstance(node, SequenceNode): | |
| 163 constructor = self.__class__.construct_sequence | |
| 164 elif isinstance(node, MappingNode): | |
| 165 constructor = self.__class__.construct_mapping | |
| 166 if tag_suffix is None: | |
| 167 data = constructor(self, node) | |
| 168 else: | |
| 169 data = constructor(self, tag_suffix, node) | |
| 170 if isinstance(data, types.GeneratorType): | |
| 171 generator = data | |
| 172 data = next(generator) | |
| 173 if self.deep_construct: | |
| 174 for _dummy in generator: | |
| 175 pass | |
| 176 else: | |
| 177 self.state_generators.append(generator) | |
| 178 self.constructed_objects[node] = data | |
| 179 del self.recursive_objects[node] | |
| 180 if deep: | |
| 181 self.deep_construct = old_deep | |
| 182 return data | |
| 183 | |
| 184 def construct_scalar(self, node): | |
| 185 # type: (Any) -> Any | |
| 186 if not isinstance(node, ScalarNode): | |
| 187 raise ConstructorError( | |
| 188 None, None, 'expected a scalar node, but found %s' % node.id, node.start_mark | |
| 189 ) | |
| 190 return node.value | |
| 191 | |
| 192 def construct_sequence(self, node, deep=False): | |
| 193 # type: (Any, bool) -> Any | |
| 194 """deep is True when creating an object/mapping recursively, | |
| 195 in that case want the underlying elements available during construction | |
| 196 """ | |
| 197 if not isinstance(node, SequenceNode): | |
| 198 raise ConstructorError( | |
| 199 None, None, 'expected a sequence node, but found %s' % node.id, node.start_mark | |
| 200 ) | |
| 201 return [self.construct_object(child, deep=deep) for child in node.value] | |
| 202 | |
| 203 def construct_mapping(self, node, deep=False): | |
| 204 # type: (Any, bool) -> Any | |
| 205 """deep is True when creating an object/mapping recursively, | |
| 206 in that case want the underlying elements available during construction | |
| 207 """ | |
| 208 if not isinstance(node, MappingNode): | |
| 209 raise ConstructorError( | |
| 210 None, None, 'expected a mapping node, but found %s' % node.id, node.start_mark | |
| 211 ) | |
| 212 total_mapping = self.yaml_base_dict_type() | |
| 213 if getattr(node, 'merge', None) is not None: | |
| 214 todo = [(node.merge, False), (node.value, False)] | |
| 215 else: | |
| 216 todo = [(node.value, True)] | |
| 217 for values, check in todo: | |
| 218 mapping = self.yaml_base_dict_type() # type: Dict[Any, Any] | |
| 219 for key_node, value_node in values: | |
| 220 # keys can be list -> deep | |
| 221 key = self.construct_object(key_node, deep=True) | |
| 222 # lists are not hashable, but tuples are | |
| 223 if not isinstance(key, Hashable): | |
| 224 if isinstance(key, list): | |
| 225 key = tuple(key) | |
| 226 if PY2: | |
| 227 try: | |
| 228 hash(key) | |
| 229 except TypeError as exc: | |
| 230 raise ConstructorError( | |
| 231 'while constructing a mapping', | |
| 232 node.start_mark, | |
| 233 'found unacceptable key (%s)' % exc, | |
| 234 key_node.start_mark, | |
| 235 ) | |
| 236 else: | |
| 237 if not isinstance(key, Hashable): | |
| 238 raise ConstructorError( | |
| 239 'while constructing a mapping', | |
| 240 node.start_mark, | |
| 241 'found unhashable key', | |
| 242 key_node.start_mark, | |
| 243 ) | |
| 244 | |
| 245 value = self.construct_object(value_node, deep=deep) | |
| 246 if check: | |
| 247 if self.check_mapping_key(node, key_node, mapping, key, value): | |
| 248 mapping[key] = value | |
| 249 else: | |
| 250 mapping[key] = value | |
| 251 total_mapping.update(mapping) | |
| 252 return total_mapping | |
| 253 | |
| 254 def check_mapping_key(self, node, key_node, mapping, key, value): | |
| 255 # type: (Any, Any, Any, Any, Any) -> bool | |
| 256 """return True if key is unique""" | |
| 257 if key in mapping: | |
| 258 if not self.allow_duplicate_keys: | |
| 259 mk = mapping.get(key) | |
| 260 if PY2: | |
| 261 if isinstance(key, unicode): | |
| 262 key = key.encode('utf-8') | |
| 263 if isinstance(value, unicode): | |
| 264 value = value.encode('utf-8') | |
| 265 if isinstance(mk, unicode): | |
| 266 mk = mk.encode('utf-8') | |
| 267 args = [ | |
| 268 'while constructing a mapping', | |
| 269 node.start_mark, | |
| 270 'found duplicate key "{}" with value "{}" ' | |
| 271 '(original value: "{}")'.format(key, value, mk), | |
| 272 key_node.start_mark, | |
| 273 """ | |
| 274 To suppress this check see: | |
| 275 http://yaml.readthedocs.io/en/latest/api.html#duplicate-keys | |
| 276 """, | |
| 277 """\ | |
| 278 Duplicate keys will become an error in future releases, and are errors | |
| 279 by default when using the new API. | |
| 280 """, | |
| 281 ] | |
| 282 if self.allow_duplicate_keys is None: | |
| 283 warnings.warn(DuplicateKeyFutureWarning(*args)) | |
| 284 else: | |
| 285 raise DuplicateKeyError(*args) | |
| 286 return False | |
| 287 return True | |
| 288 | |
| 289 def check_set_key(self, node, key_node, setting, key): | |
| 290 # type: (Any, Any, Any, Any, Any) -> None | |
| 291 if key in setting: | |
| 292 if not self.allow_duplicate_keys: | |
| 293 if PY2: | |
| 294 if isinstance(key, unicode): | |
| 295 key = key.encode('utf-8') | |
| 296 args = [ | |
| 297 'while constructing a set', | |
| 298 node.start_mark, | |
| 299 'found duplicate key "{}"'.format(key), | |
| 300 key_node.start_mark, | |
| 301 """ | |
| 302 To suppress this check see: | |
| 303 http://yaml.readthedocs.io/en/latest/api.html#duplicate-keys | |
| 304 """, | |
| 305 """\ | |
| 306 Duplicate keys will become an error in future releases, and are errors | |
| 307 by default when using the new API. | |
| 308 """, | |
| 309 ] | |
| 310 if self.allow_duplicate_keys is None: | |
| 311 warnings.warn(DuplicateKeyFutureWarning(*args)) | |
| 312 else: | |
| 313 raise DuplicateKeyError(*args) | |
| 314 | |
| 315 def construct_pairs(self, node, deep=False): | |
| 316 # type: (Any, bool) -> Any | |
| 317 if not isinstance(node, MappingNode): | |
| 318 raise ConstructorError( | |
| 319 None, None, 'expected a mapping node, but found %s' % node.id, node.start_mark | |
| 320 ) | |
| 321 pairs = [] | |
| 322 for key_node, value_node in node.value: | |
| 323 key = self.construct_object(key_node, deep=deep) | |
| 324 value = self.construct_object(value_node, deep=deep) | |
| 325 pairs.append((key, value)) | |
| 326 return pairs | |
| 327 | |
| 328 @classmethod | |
| 329 def add_constructor(cls, tag, constructor): | |
| 330 # type: (Any, Any) -> None | |
| 331 if 'yaml_constructors' not in cls.__dict__: | |
| 332 cls.yaml_constructors = cls.yaml_constructors.copy() | |
| 333 cls.yaml_constructors[tag] = constructor | |
| 334 | |
| 335 @classmethod | |
| 336 def add_multi_constructor(cls, tag_prefix, multi_constructor): | |
| 337 # type: (Any, Any) -> None | |
| 338 if 'yaml_multi_constructors' not in cls.__dict__: | |
| 339 cls.yaml_multi_constructors = cls.yaml_multi_constructors.copy() | |
| 340 cls.yaml_multi_constructors[tag_prefix] = multi_constructor | |
| 341 | |
| 342 | |
| 343 class SafeConstructor(BaseConstructor): | |
| 344 def construct_scalar(self, node): | |
| 345 # type: (Any) -> Any | |
| 346 if isinstance(node, MappingNode): | |
| 347 for key_node, value_node in node.value: | |
| 348 if key_node.tag == u'tag:yaml.org,2002:value': | |
| 349 return self.construct_scalar(value_node) | |
| 350 return BaseConstructor.construct_scalar(self, node) | |
| 351 | |
| 352 def flatten_mapping(self, node): | |
| 353 # type: (Any) -> Any | |
| 354 """ | |
| 355 This implements the merge key feature http://yaml.org/type/merge.html | |
| 356 by inserting keys from the merge dict/list of dicts if not yet | |
| 357 available in this node | |
| 358 """ | |
| 359 merge = [] # type: List[Any] | |
| 360 index = 0 | |
| 361 while index < len(node.value): | |
| 362 key_node, value_node = node.value[index] | |
| 363 if key_node.tag == u'tag:yaml.org,2002:merge': | |
| 364 if merge: # double << key | |
| 365 if self.allow_duplicate_keys: | |
| 366 del node.value[index] | |
| 367 index += 1 | |
| 368 continue | |
| 369 args = [ | |
| 370 'while constructing a mapping', | |
| 371 node.start_mark, | |
| 372 'found duplicate key "{}"'.format(key_node.value), | |
| 373 key_node.start_mark, | |
| 374 """ | |
| 375 To suppress this check see: | |
| 376 http://yaml.readthedocs.io/en/latest/api.html#duplicate-keys | |
| 377 """, | |
| 378 """\ | |
| 379 Duplicate keys will become an error in future releases, and are errors | |
| 380 by default when using the new API. | |
| 381 """, | |
| 382 ] | |
| 383 if self.allow_duplicate_keys is None: | |
| 384 warnings.warn(DuplicateKeyFutureWarning(*args)) | |
| 385 else: | |
| 386 raise DuplicateKeyError(*args) | |
| 387 del node.value[index] | |
| 388 if isinstance(value_node, MappingNode): | |
| 389 self.flatten_mapping(value_node) | |
| 390 merge.extend(value_node.value) | |
| 391 elif isinstance(value_node, SequenceNode): | |
| 392 submerge = [] | |
| 393 for subnode in value_node.value: | |
| 394 if not isinstance(subnode, MappingNode): | |
| 395 raise ConstructorError( | |
| 396 'while constructing a mapping', | |
| 397 node.start_mark, | |
| 398 'expected a mapping for merging, but found %s' % subnode.id, | |
| 399 subnode.start_mark, | |
| 400 ) | |
| 401 self.flatten_mapping(subnode) | |
| 402 submerge.append(subnode.value) | |
| 403 submerge.reverse() | |
| 404 for value in submerge: | |
| 405 merge.extend(value) | |
| 406 else: | |
| 407 raise ConstructorError( | |
| 408 'while constructing a mapping', | |
| 409 node.start_mark, | |
| 410 'expected a mapping or list of mappings for merging, ' | |
| 411 'but found %s' % value_node.id, | |
| 412 value_node.start_mark, | |
| 413 ) | |
| 414 elif key_node.tag == u'tag:yaml.org,2002:value': | |
| 415 key_node.tag = u'tag:yaml.org,2002:str' | |
| 416 index += 1 | |
| 417 else: | |
| 418 index += 1 | |
| 419 if bool(merge): | |
| 420 node.merge = merge # separate merge keys to be able to update without duplicate | |
| 421 node.value = merge + node.value | |
| 422 | |
| 423 def construct_mapping(self, node, deep=False): | |
| 424 # type: (Any, bool) -> Any | |
| 425 """deep is True when creating an object/mapping recursively, | |
| 426 in that case want the underlying elements available during construction | |
| 427 """ | |
| 428 if isinstance(node, MappingNode): | |
| 429 self.flatten_mapping(node) | |
| 430 return BaseConstructor.construct_mapping(self, node, deep=deep) | |
| 431 | |
| 432 def construct_yaml_null(self, node): | |
| 433 # type: (Any) -> Any | |
| 434 self.construct_scalar(node) | |
| 435 return None | |
| 436 | |
| 437 # YAML 1.2 spec doesn't mention yes/no etc any more, 1.1 does | |
| 438 bool_values = { | |
| 439 u'yes': True, | |
| 440 u'no': False, | |
| 441 u'y': True, | |
| 442 u'n': False, | |
| 443 u'true': True, | |
| 444 u'false': False, | |
| 445 u'on': True, | |
| 446 u'off': False, | |
| 447 } | |
| 448 | |
| 449 def construct_yaml_bool(self, node): | |
| 450 # type: (Any) -> bool | |
| 451 value = self.construct_scalar(node) | |
| 452 return self.bool_values[value.lower()] | |
| 453 | |
| 454 def construct_yaml_int(self, node): | |
| 455 # type: (Any) -> int | |
| 456 value_s = to_str(self.construct_scalar(node)) | |
| 457 value_s = value_s.replace('_', "") | |
| 458 sign = +1 | |
| 459 if value_s[0] == '-': | |
| 460 sign = -1 | |
| 461 if value_s[0] in '+-': | |
| 462 value_s = value_s[1:] | |
| 463 if value_s == '0': | |
| 464 return 0 | |
| 465 elif value_s.startswith('0b'): | |
| 466 return sign * int(value_s[2:], 2) | |
| 467 elif value_s.startswith('0x'): | |
| 468 return sign * int(value_s[2:], 16) | |
| 469 elif value_s.startswith('0o'): | |
| 470 return sign * int(value_s[2:], 8) | |
| 471 elif self.resolver.processing_version == (1, 1) and value_s[0] == '0': | |
| 472 return sign * int(value_s, 8) | |
| 473 elif self.resolver.processing_version == (1, 1) and ':' in value_s: | |
| 474 digits = [int(part) for part in value_s.split(':')] | |
| 475 digits.reverse() | |
| 476 base = 1 | |
| 477 value = 0 | |
| 478 for digit in digits: | |
| 479 value += digit * base | |
| 480 base *= 60 | |
| 481 return sign * value | |
| 482 else: | |
| 483 return sign * int(value_s) | |
| 484 | |
| 485 inf_value = 1e300 | |
| 486 while inf_value != inf_value * inf_value: | |
| 487 inf_value *= inf_value | |
| 488 nan_value = -inf_value / inf_value # Trying to make a quiet NaN (like C99). | |
| 489 | |
| 490 def construct_yaml_float(self, node): | |
| 491 # type: (Any) -> float | |
| 492 value_so = to_str(self.construct_scalar(node)) | |
| 493 value_s = value_so.replace('_', "").lower() | |
| 494 sign = +1 | |
| 495 if value_s[0] == '-': | |
| 496 sign = -1 | |
| 497 if value_s[0] in '+-': | |
| 498 value_s = value_s[1:] | |
| 499 if value_s == '.inf': | |
| 500 return sign * self.inf_value | |
| 501 elif value_s == '.nan': | |
| 502 return self.nan_value | |
| 503 elif self.resolver.processing_version != (1, 2) and ':' in value_s: | |
| 504 digits = [float(part) for part in value_s.split(':')] | |
| 505 digits.reverse() | |
| 506 base = 1 | |
| 507 value = 0.0 | |
| 508 for digit in digits: | |
| 509 value += digit * base | |
| 510 base *= 60 | |
| 511 return sign * value | |
| 512 else: | |
| 513 if self.resolver.processing_version != (1, 2) and 'e' in value_s: | |
| 514 # value_s is lower case independent of input | |
| 515 mantissa, exponent = value_s.split('e') | |
| 516 if '.' not in mantissa: | |
| 517 warnings.warn(MantissaNoDotYAML1_1Warning(node, value_so)) | |
| 518 return sign * float(value_s) | |
| 519 | |
| 520 if PY3: | |
| 521 | |
| 522 def construct_yaml_binary(self, node): | |
| 523 # type: (Any) -> Any | |
| 524 try: | |
| 525 value = self.construct_scalar(node).encode('ascii') | |
| 526 except UnicodeEncodeError as exc: | |
| 527 raise ConstructorError( | |
| 528 None, | |
| 529 None, | |
| 530 'failed to convert base64 data into ascii: %s' % exc, | |
| 531 node.start_mark, | |
| 532 ) | |
| 533 try: | |
| 534 if hasattr(base64, 'decodebytes'): | |
| 535 return base64.decodebytes(value) | |
| 536 else: | |
| 537 return base64.decodestring(value) | |
| 538 except binascii.Error as exc: | |
| 539 raise ConstructorError( | |
| 540 None, None, 'failed to decode base64 data: %s' % exc, node.start_mark | |
| 541 ) | |
| 542 | |
| 543 else: | |
| 544 | |
| 545 def construct_yaml_binary(self, node): | |
| 546 # type: (Any) -> Any | |
| 547 value = self.construct_scalar(node) | |
| 548 try: | |
| 549 return to_str(value).decode('base64') | |
| 550 except (binascii.Error, UnicodeEncodeError) as exc: | |
| 551 raise ConstructorError( | |
| 552 None, None, 'failed to decode base64 data: %s' % exc, node.start_mark | |
| 553 ) | |
| 554 | |
| 555 timestamp_regexp = RegExp( | |
| 556 u"""^(?P<year>[0-9][0-9][0-9][0-9]) | |
| 557 -(?P<month>[0-9][0-9]?) | |
| 558 -(?P<day>[0-9][0-9]?) | |
| 559 (?:((?P<t>[Tt])|[ \\t]+) # explictly not retaining extra spaces | |
| 560 (?P<hour>[0-9][0-9]?) | |
| 561 :(?P<minute>[0-9][0-9]) | |
| 562 :(?P<second>[0-9][0-9]) | |
| 563 (?:\\.(?P<fraction>[0-9]*))? | |
| 564 (?:[ \\t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?) | |
| 565 (?::(?P<tz_minute>[0-9][0-9]))?))?)?$""", | |
| 566 re.X, | |
| 567 ) | |
| 568 | |
| 569 def construct_yaml_timestamp(self, node, values=None): | |
| 570 # type: (Any, Any) -> Any | |
| 571 if values is None: | |
| 572 try: | |
| 573 match = self.timestamp_regexp.match(node.value) | |
| 574 except TypeError: | |
| 575 match = None | |
| 576 if match is None: | |
| 577 raise ConstructorError( | |
| 578 None, | |
| 579 None, | |
| 580 'failed to construct timestamp from "{}"'.format(node.value), | |
| 581 node.start_mark, | |
| 582 ) | |
| 583 values = match.groupdict() | |
| 584 year = int(values['year']) | |
| 585 month = int(values['month']) | |
| 586 day = int(values['day']) | |
| 587 if not values['hour']: | |
| 588 return datetime.date(year, month, day) | |
| 589 hour = int(values['hour']) | |
| 590 minute = int(values['minute']) | |
| 591 second = int(values['second']) | |
| 592 fraction = 0 | |
| 593 if values['fraction']: | |
| 594 fraction_s = values['fraction'][:6] | |
| 595 while len(fraction_s) < 6: | |
| 596 fraction_s += '0' | |
| 597 fraction = int(fraction_s) | |
| 598 if len(values['fraction']) > 6 and int(values['fraction'][6]) > 4: | |
| 599 fraction += 1 | |
| 600 delta = None | |
| 601 if values['tz_sign']: | |
| 602 tz_hour = int(values['tz_hour']) | |
| 603 minutes = values['tz_minute'] | |
| 604 tz_minute = int(minutes) if minutes else 0 | |
| 605 delta = datetime.timedelta(hours=tz_hour, minutes=tz_minute) | |
| 606 if values['tz_sign'] == '-': | |
| 607 delta = -delta | |
| 608 # should do something else instead (or hook this up to the preceding if statement | |
| 609 # in reverse | |
| 610 # if delta is None: | |
| 611 # return datetime.datetime(year, month, day, hour, minute, second, fraction) | |
| 612 # return datetime.datetime(year, month, day, hour, minute, second, fraction, | |
| 613 # datetime.timezone.utc) | |
| 614 # the above is not good enough though, should provide tzinfo. In Python3 that is easily | |
| 615 # doable drop that kind of support for Python2 as it has not native tzinfo | |
| 616 data = datetime.datetime(year, month, day, hour, minute, second, fraction) | |
| 617 if delta: | |
| 618 data -= delta | |
| 619 return data | |
| 620 | |
| 621 def construct_yaml_omap(self, node): | |
| 622 # type: (Any) -> Any | |
| 623 # Note: we do now check for duplicate keys | |
| 624 omap = ordereddict() | |
| 625 yield omap | |
| 626 if not isinstance(node, SequenceNode): | |
| 627 raise ConstructorError( | |
| 628 'while constructing an ordered map', | |
| 629 node.start_mark, | |
| 630 'expected a sequence, but found %s' % node.id, | |
| 631 node.start_mark, | |
| 632 ) | |
| 633 for subnode in node.value: | |
| 634 if not isinstance(subnode, MappingNode): | |
| 635 raise ConstructorError( | |
| 636 'while constructing an ordered map', | |
| 637 node.start_mark, | |
| 638 'expected a mapping of length 1, but found %s' % subnode.id, | |
| 639 subnode.start_mark, | |
| 640 ) | |
| 641 if len(subnode.value) != 1: | |
| 642 raise ConstructorError( | |
| 643 'while constructing an ordered map', | |
| 644 node.start_mark, | |
| 645 'expected a single mapping item, but found %d items' % len(subnode.value), | |
| 646 subnode.start_mark, | |
| 647 ) | |
| 648 key_node, value_node = subnode.value[0] | |
| 649 key = self.construct_object(key_node) | |
| 650 assert key not in omap | |
| 651 value = self.construct_object(value_node) | |
| 652 omap[key] = value | |
| 653 | |
| 654 def construct_yaml_pairs(self, node): | |
| 655 # type: (Any) -> Any | |
| 656 # Note: the same code as `construct_yaml_omap`. | |
| 657 pairs = [] # type: List[Any] | |
| 658 yield pairs | |
| 659 if not isinstance(node, SequenceNode): | |
| 660 raise ConstructorError( | |
| 661 'while constructing pairs', | |
| 662 node.start_mark, | |
| 663 'expected a sequence, but found %s' % node.id, | |
| 664 node.start_mark, | |
| 665 ) | |
| 666 for subnode in node.value: | |
| 667 if not isinstance(subnode, MappingNode): | |
| 668 raise ConstructorError( | |
| 669 'while constructing pairs', | |
| 670 node.start_mark, | |
| 671 'expected a mapping of length 1, but found %s' % subnode.id, | |
| 672 subnode.start_mark, | |
| 673 ) | |
| 674 if len(subnode.value) != 1: | |
| 675 raise ConstructorError( | |
| 676 'while constructing pairs', | |
| 677 node.start_mark, | |
| 678 'expected a single mapping item, but found %d items' % len(subnode.value), | |
| 679 subnode.start_mark, | |
| 680 ) | |
| 681 key_node, value_node = subnode.value[0] | |
| 682 key = self.construct_object(key_node) | |
| 683 value = self.construct_object(value_node) | |
| 684 pairs.append((key, value)) | |
| 685 | |
| 686 def construct_yaml_set(self, node): | |
| 687 # type: (Any) -> Any | |
| 688 data = set() # type: Set[Any] | |
| 689 yield data | |
| 690 value = self.construct_mapping(node) | |
| 691 data.update(value) | |
| 692 | |
| 693 def construct_yaml_str(self, node): | |
| 694 # type: (Any) -> Any | |
| 695 value = self.construct_scalar(node) | |
| 696 if PY3: | |
| 697 return value | |
| 698 try: | |
| 699 return value.encode('ascii') | |
| 700 except UnicodeEncodeError: | |
| 701 return value | |
| 702 | |
| 703 def construct_yaml_seq(self, node): | |
| 704 # type: (Any) -> Any | |
| 705 data = self.yaml_base_list_type() # type: List[Any] | |
| 706 yield data | |
| 707 data.extend(self.construct_sequence(node)) | |
| 708 | |
| 709 def construct_yaml_map(self, node): | |
| 710 # type: (Any) -> Any | |
| 711 data = self.yaml_base_dict_type() # type: Dict[Any, Any] | |
| 712 yield data | |
| 713 value = self.construct_mapping(node) | |
| 714 data.update(value) | |
| 715 | |
| 716 def construct_yaml_object(self, node, cls): | |
| 717 # type: (Any, Any) -> Any | |
| 718 data = cls.__new__(cls) | |
| 719 yield data | |
| 720 if hasattr(data, '__setstate__'): | |
| 721 state = self.construct_mapping(node, deep=True) | |
| 722 data.__setstate__(state) | |
| 723 else: | |
| 724 state = self.construct_mapping(node) | |
| 725 data.__dict__.update(state) | |
| 726 | |
| 727 def construct_undefined(self, node): | |
| 728 # type: (Any) -> None | |
| 729 raise ConstructorError( | |
| 730 None, | |
| 731 None, | |
| 732 'could not determine a constructor for the tag %r' % utf8(node.tag), | |
| 733 node.start_mark, | |
| 734 ) | |
| 735 | |
| 736 | |
| 737 SafeConstructor.add_constructor(u'tag:yaml.org,2002:null', SafeConstructor.construct_yaml_null) | |
| 738 | |
| 739 SafeConstructor.add_constructor(u'tag:yaml.org,2002:bool', SafeConstructor.construct_yaml_bool) | |
| 740 | |
| 741 SafeConstructor.add_constructor(u'tag:yaml.org,2002:int', SafeConstructor.construct_yaml_int) | |
| 742 | |
| 743 SafeConstructor.add_constructor( | |
| 744 u'tag:yaml.org,2002:float', SafeConstructor.construct_yaml_float | |
| 745 ) | |
| 746 | |
| 747 SafeConstructor.add_constructor( | |
| 748 u'tag:yaml.org,2002:binary', SafeConstructor.construct_yaml_binary | |
| 749 ) | |
| 750 | |
| 751 SafeConstructor.add_constructor( | |
| 752 u'tag:yaml.org,2002:timestamp', SafeConstructor.construct_yaml_timestamp | |
| 753 ) | |
| 754 | |
| 755 SafeConstructor.add_constructor(u'tag:yaml.org,2002:omap', SafeConstructor.construct_yaml_omap) | |
| 756 | |
| 757 SafeConstructor.add_constructor( | |
| 758 u'tag:yaml.org,2002:pairs', SafeConstructor.construct_yaml_pairs | |
| 759 ) | |
| 760 | |
| 761 SafeConstructor.add_constructor(u'tag:yaml.org,2002:set', SafeConstructor.construct_yaml_set) | |
| 762 | |
| 763 SafeConstructor.add_constructor(u'tag:yaml.org,2002:str', SafeConstructor.construct_yaml_str) | |
| 764 | |
| 765 SafeConstructor.add_constructor(u'tag:yaml.org,2002:seq', SafeConstructor.construct_yaml_seq) | |
| 766 | |
| 767 SafeConstructor.add_constructor(u'tag:yaml.org,2002:map', SafeConstructor.construct_yaml_map) | |
| 768 | |
| 769 SafeConstructor.add_constructor(None, SafeConstructor.construct_undefined) | |
| 770 | |
| 771 if PY2: | |
| 772 | |
| 773 class classobj: | |
| 774 pass | |
| 775 | |
| 776 | |
| 777 class Constructor(SafeConstructor): | |
| 778 def construct_python_str(self, node): | |
| 779 # type: (Any) -> Any | |
| 780 return utf8(self.construct_scalar(node)) | |
| 781 | |
| 782 def construct_python_unicode(self, node): | |
| 783 # type: (Any) -> Any | |
| 784 return self.construct_scalar(node) | |
| 785 | |
| 786 if PY3: | |
| 787 | |
| 788 def construct_python_bytes(self, node): | |
| 789 # type: (Any) -> Any | |
| 790 try: | |
| 791 value = self.construct_scalar(node).encode('ascii') | |
| 792 except UnicodeEncodeError as exc: | |
| 793 raise ConstructorError( | |
| 794 None, | |
| 795 None, | |
| 796 'failed to convert base64 data into ascii: %s' % exc, | |
| 797 node.start_mark, | |
| 798 ) | |
| 799 try: | |
| 800 if hasattr(base64, 'decodebytes'): | |
| 801 return base64.decodebytes(value) | |
| 802 else: | |
| 803 return base64.decodestring(value) | |
| 804 except binascii.Error as exc: | |
| 805 raise ConstructorError( | |
| 806 None, None, 'failed to decode base64 data: %s' % exc, node.start_mark | |
| 807 ) | |
| 808 | |
| 809 def construct_python_long(self, node): | |
| 810 # type: (Any) -> int | |
| 811 val = self.construct_yaml_int(node) | |
| 812 if PY3: | |
| 813 return val | |
| 814 return int(val) | |
| 815 | |
| 816 def construct_python_complex(self, node): | |
| 817 # type: (Any) -> Any | |
| 818 return complex(self.construct_scalar(node)) | |
| 819 | |
| 820 def construct_python_tuple(self, node): | |
| 821 # type: (Any) -> Any | |
| 822 return tuple(self.construct_sequence(node)) | |
| 823 | |
| 824 def find_python_module(self, name, mark): | |
| 825 # type: (Any, Any) -> Any | |
| 826 if not name: | |
| 827 raise ConstructorError( | |
| 828 'while constructing a Python module', | |
| 829 mark, | |
| 830 'expected non-empty name appended to the tag', | |
| 831 mark, | |
| 832 ) | |
| 833 try: | |
| 834 __import__(name) | |
| 835 except ImportError as exc: | |
| 836 raise ConstructorError( | |
| 837 'while constructing a Python module', | |
| 838 mark, | |
| 839 'cannot find module %r (%s)' % (utf8(name), exc), | |
| 840 mark, | |
| 841 ) | |
| 842 return sys.modules[name] | |
| 843 | |
| 844 def find_python_name(self, name, mark): | |
| 845 # type: (Any, Any) -> Any | |
| 846 if not name: | |
| 847 raise ConstructorError( | |
| 848 'while constructing a Python object', | |
| 849 mark, | |
| 850 'expected non-empty name appended to the tag', | |
| 851 mark, | |
| 852 ) | |
| 853 if u'.' in name: | |
| 854 lname = name.split('.') | |
| 855 lmodule_name = lname | |
| 856 lobject_name = [] # type: List[Any] | |
| 857 while len(lmodule_name) > 1: | |
| 858 lobject_name.insert(0, lmodule_name.pop()) | |
| 859 module_name = '.'.join(lmodule_name) | |
| 860 try: | |
| 861 __import__(module_name) | |
| 862 # object_name = '.'.join(object_name) | |
| 863 break | |
| 864 except ImportError: | |
| 865 continue | |
| 866 else: | |
| 867 module_name = builtins_module | |
| 868 lobject_name = [name] | |
| 869 try: | |
| 870 __import__(module_name) | |
| 871 except ImportError as exc: | |
| 872 raise ConstructorError( | |
| 873 'while constructing a Python object', | |
| 874 mark, | |
| 875 'cannot find module %r (%s)' % (utf8(module_name), exc), | |
| 876 mark, | |
| 877 ) | |
| 878 module = sys.modules[module_name] | |
| 879 object_name = '.'.join(lobject_name) | |
| 880 obj = module | |
| 881 while lobject_name: | |
| 882 if not hasattr(obj, lobject_name[0]): | |
| 883 | |
| 884 raise ConstructorError( | |
| 885 'while constructing a Python object', | |
| 886 mark, | |
| 887 'cannot find %r in the module %r' % (utf8(object_name), module.__name__), | |
| 888 mark, | |
| 889 ) | |
| 890 obj = getattr(obj, lobject_name.pop(0)) | |
| 891 return obj | |
| 892 | |
| 893 def construct_python_name(self, suffix, node): | |
| 894 # type: (Any, Any) -> Any | |
| 895 value = self.construct_scalar(node) | |
| 896 if value: | |
| 897 raise ConstructorError( | |
| 898 'while constructing a Python name', | |
| 899 node.start_mark, | |
| 900 'expected the empty value, but found %r' % utf8(value), | |
| 901 node.start_mark, | |
| 902 ) | |
| 903 return self.find_python_name(suffix, node.start_mark) | |
| 904 | |
| 905 def construct_python_module(self, suffix, node): | |
| 906 # type: (Any, Any) -> Any | |
| 907 value = self.construct_scalar(node) | |
| 908 if value: | |
| 909 raise ConstructorError( | |
| 910 'while constructing a Python module', | |
| 911 node.start_mark, | |
| 912 'expected the empty value, but found %r' % utf8(value), | |
| 913 node.start_mark, | |
| 914 ) | |
| 915 return self.find_python_module(suffix, node.start_mark) | |
| 916 | |
| 917 def make_python_instance(self, suffix, node, args=None, kwds=None, newobj=False): | |
| 918 # type: (Any, Any, Any, Any, bool) -> Any | |
| 919 if not args: | |
| 920 args = [] | |
| 921 if not kwds: | |
| 922 kwds = {} | |
| 923 cls = self.find_python_name(suffix, node.start_mark) | |
| 924 if PY3: | |
| 925 if newobj and isinstance(cls, type): | |
| 926 return cls.__new__(cls, *args, **kwds) | |
| 927 else: | |
| 928 return cls(*args, **kwds) | |
| 929 else: | |
| 930 if newobj and isinstance(cls, type(classobj)) and not args and not kwds: | |
| 931 instance = classobj() | |
| 932 instance.__class__ = cls | |
| 933 return instance | |
| 934 elif newobj and isinstance(cls, type): | |
| 935 return cls.__new__(cls, *args, **kwds) | |
| 936 else: | |
| 937 return cls(*args, **kwds) | |
| 938 | |
| 939 def set_python_instance_state(self, instance, state): | |
| 940 # type: (Any, Any) -> None | |
| 941 if hasattr(instance, '__setstate__'): | |
| 942 instance.__setstate__(state) | |
| 943 else: | |
| 944 slotstate = {} # type: Dict[Any, Any] | |
| 945 if isinstance(state, tuple) and len(state) == 2: | |
| 946 state, slotstate = state | |
| 947 if hasattr(instance, '__dict__'): | |
| 948 instance.__dict__.update(state) | |
| 949 elif state: | |
| 950 slotstate.update(state) | |
| 951 for key, value in slotstate.items(): | |
| 952 setattr(object, key, value) | |
| 953 | |
| 954 def construct_python_object(self, suffix, node): | |
| 955 # type: (Any, Any) -> Any | |
| 956 # Format: | |
| 957 # !!python/object:module.name { ... state ... } | |
| 958 instance = self.make_python_instance(suffix, node, newobj=True) | |
| 959 self.recursive_objects[node] = instance | |
| 960 yield instance | |
| 961 deep = hasattr(instance, '__setstate__') | |
| 962 state = self.construct_mapping(node, deep=deep) | |
| 963 self.set_python_instance_state(instance, state) | |
| 964 | |
| 965 def construct_python_object_apply(self, suffix, node, newobj=False): | |
| 966 # type: (Any, Any, bool) -> Any | |
| 967 # Format: | |
| 968 # !!python/object/apply # (or !!python/object/new) | |
| 969 # args: [ ... arguments ... ] | |
| 970 # kwds: { ... keywords ... } | |
| 971 # state: ... state ... | |
| 972 # listitems: [ ... listitems ... ] | |
| 973 # dictitems: { ... dictitems ... } | |
| 974 # or short format: | |
| 975 # !!python/object/apply [ ... arguments ... ] | |
| 976 # The difference between !!python/object/apply and !!python/object/new | |
| 977 # is how an object is created, check make_python_instance for details. | |
| 978 if isinstance(node, SequenceNode): | |
| 979 args = self.construct_sequence(node, deep=True) | |
| 980 kwds = {} # type: Dict[Any, Any] | |
| 981 state = {} # type: Dict[Any, Any] | |
| 982 listitems = [] # type: List[Any] | |
| 983 dictitems = {} # type: Dict[Any, Any] | |
| 984 else: | |
| 985 value = self.construct_mapping(node, deep=True) | |
| 986 args = value.get('args', []) | |
| 987 kwds = value.get('kwds', {}) | |
| 988 state = value.get('state', {}) | |
| 989 listitems = value.get('listitems', []) | |
| 990 dictitems = value.get('dictitems', {}) | |
| 991 instance = self.make_python_instance(suffix, node, args, kwds, newobj) | |
| 992 if bool(state): | |
| 993 self.set_python_instance_state(instance, state) | |
| 994 if bool(listitems): | |
| 995 instance.extend(listitems) | |
| 996 if bool(dictitems): | |
| 997 for key in dictitems: | |
| 998 instance[key] = dictitems[key] | |
| 999 return instance | |
| 1000 | |
| 1001 def construct_python_object_new(self, suffix, node): | |
| 1002 # type: (Any, Any) -> Any | |
| 1003 return self.construct_python_object_apply(suffix, node, newobj=True) | |
| 1004 | |
| 1005 | |
| 1006 Constructor.add_constructor(u'tag:yaml.org,2002:python/none', Constructor.construct_yaml_null) | |
| 1007 | |
| 1008 Constructor.add_constructor(u'tag:yaml.org,2002:python/bool', Constructor.construct_yaml_bool) | |
| 1009 | |
| 1010 Constructor.add_constructor(u'tag:yaml.org,2002:python/str', Constructor.construct_python_str) | |
| 1011 | |
| 1012 Constructor.add_constructor( | |
| 1013 u'tag:yaml.org,2002:python/unicode', Constructor.construct_python_unicode | |
| 1014 ) | |
| 1015 | |
| 1016 if PY3: | |
| 1017 Constructor.add_constructor( | |
| 1018 u'tag:yaml.org,2002:python/bytes', Constructor.construct_python_bytes | |
| 1019 ) | |
| 1020 | |
| 1021 Constructor.add_constructor(u'tag:yaml.org,2002:python/int', Constructor.construct_yaml_int) | |
| 1022 | |
| 1023 Constructor.add_constructor( | |
| 1024 u'tag:yaml.org,2002:python/long', Constructor.construct_python_long | |
| 1025 ) | |
| 1026 | |
| 1027 Constructor.add_constructor( | |
| 1028 u'tag:yaml.org,2002:python/float', Constructor.construct_yaml_float | |
| 1029 ) | |
| 1030 | |
| 1031 Constructor.add_constructor( | |
| 1032 u'tag:yaml.org,2002:python/complex', Constructor.construct_python_complex | |
| 1033 ) | |
| 1034 | |
| 1035 Constructor.add_constructor(u'tag:yaml.org,2002:python/list', Constructor.construct_yaml_seq) | |
| 1036 | |
| 1037 Constructor.add_constructor( | |
| 1038 u'tag:yaml.org,2002:python/tuple', Constructor.construct_python_tuple | |
| 1039 ) | |
| 1040 | |
| 1041 Constructor.add_constructor(u'tag:yaml.org,2002:python/dict', Constructor.construct_yaml_map) | |
| 1042 | |
| 1043 Constructor.add_multi_constructor( | |
| 1044 u'tag:yaml.org,2002:python/name:', Constructor.construct_python_name | |
| 1045 ) | |
| 1046 | |
| 1047 Constructor.add_multi_constructor( | |
| 1048 u'tag:yaml.org,2002:python/module:', Constructor.construct_python_module | |
| 1049 ) | |
| 1050 | |
| 1051 Constructor.add_multi_constructor( | |
| 1052 u'tag:yaml.org,2002:python/object:', Constructor.construct_python_object | |
| 1053 ) | |
| 1054 | |
| 1055 Constructor.add_multi_constructor( | |
| 1056 u'tag:yaml.org,2002:python/object/apply:', Constructor.construct_python_object_apply | |
| 1057 ) | |
| 1058 | |
| 1059 Constructor.add_multi_constructor( | |
| 1060 u'tag:yaml.org,2002:python/object/new:', Constructor.construct_python_object_new | |
| 1061 ) | |
| 1062 | |
| 1063 | |
| 1064 class RoundTripConstructor(SafeConstructor): | |
| 1065 """need to store the comments on the node itself, | |
| 1066 as well as on the items | |
| 1067 """ | |
| 1068 | |
| 1069 def construct_scalar(self, node): | |
| 1070 # type: (Any) -> Any | |
| 1071 if not isinstance(node, ScalarNode): | |
| 1072 raise ConstructorError( | |
| 1073 None, None, 'expected a scalar node, but found %s' % node.id, node.start_mark | |
| 1074 ) | |
| 1075 | |
| 1076 if node.style == '|' and isinstance(node.value, text_type): | |
| 1077 lss = LiteralScalarString(node.value, anchor=node.anchor) | |
| 1078 if node.comment and node.comment[1]: | |
| 1079 lss.comment = node.comment[1][0] # type: ignore | |
| 1080 return lss | |
| 1081 if node.style == '>' and isinstance(node.value, text_type): | |
| 1082 fold_positions = [] # type: List[int] | |
| 1083 idx = -1 | |
| 1084 while True: | |
| 1085 idx = node.value.find('\a', idx + 1) | |
| 1086 if idx < 0: | |
| 1087 break | |
| 1088 fold_positions.append(idx - len(fold_positions)) | |
| 1089 fss = FoldedScalarString(node.value.replace('\a', ''), anchor=node.anchor) | |
| 1090 if node.comment and node.comment[1]: | |
| 1091 fss.comment = node.comment[1][0] # type: ignore | |
| 1092 if fold_positions: | |
| 1093 fss.fold_pos = fold_positions # type: ignore | |
| 1094 return fss | |
| 1095 elif bool(self._preserve_quotes) and isinstance(node.value, text_type): | |
| 1096 if node.style == "'": | |
| 1097 return SingleQuotedScalarString(node.value, anchor=node.anchor) | |
| 1098 if node.style == '"': | |
| 1099 return DoubleQuotedScalarString(node.value, anchor=node.anchor) | |
| 1100 if node.anchor: | |
| 1101 return PlainScalarString(node.value, anchor=node.anchor) | |
| 1102 return node.value | |
| 1103 | |
| 1104 def construct_yaml_int(self, node): | |
| 1105 # type: (Any) -> Any | |
| 1106 width = None # type: Any | |
| 1107 value_su = to_str(self.construct_scalar(node)) | |
| 1108 try: | |
| 1109 sx = value_su.rstrip('_') | |
| 1110 underscore = [len(sx) - sx.rindex('_') - 1, False, False] # type: Any | |
| 1111 except ValueError: | |
| 1112 underscore = None | |
| 1113 except IndexError: | |
| 1114 underscore = None | |
| 1115 value_s = value_su.replace('_', "") | |
| 1116 sign = +1 | |
| 1117 if value_s[0] == '-': | |
| 1118 sign = -1 | |
| 1119 if value_s[0] in '+-': | |
| 1120 value_s = value_s[1:] | |
| 1121 if value_s == '0': | |
| 1122 return 0 | |
| 1123 elif value_s.startswith('0b'): | |
| 1124 if self.resolver.processing_version > (1, 1) and value_s[2] == '0': | |
| 1125 width = len(value_s[2:]) | |
| 1126 if underscore is not None: | |
| 1127 underscore[1] = value_su[2] == '_' | |
| 1128 underscore[2] = len(value_su[2:]) > 1 and value_su[-1] == '_' | |
| 1129 return BinaryInt( | |
| 1130 sign * int(value_s[2:], 2), | |
| 1131 width=width, | |
| 1132 underscore=underscore, | |
| 1133 anchor=node.anchor, | |
| 1134 ) | |
| 1135 elif value_s.startswith('0x'): | |
| 1136 # default to lower-case if no a-fA-F in string | |
| 1137 if self.resolver.processing_version > (1, 1) and value_s[2] == '0': | |
| 1138 width = len(value_s[2:]) | |
| 1139 hex_fun = HexInt # type: Any | |
| 1140 for ch in value_s[2:]: | |
| 1141 if ch in 'ABCDEF': # first non-digit is capital | |
| 1142 hex_fun = HexCapsInt | |
| 1143 break | |
| 1144 if ch in 'abcdef': | |
| 1145 break | |
| 1146 if underscore is not None: | |
| 1147 underscore[1] = value_su[2] == '_' | |
| 1148 underscore[2] = len(value_su[2:]) > 1 and value_su[-1] == '_' | |
| 1149 return hex_fun( | |
| 1150 sign * int(value_s[2:], 16), | |
| 1151 width=width, | |
| 1152 underscore=underscore, | |
| 1153 anchor=node.anchor, | |
| 1154 ) | |
| 1155 elif value_s.startswith('0o'): | |
| 1156 if self.resolver.processing_version > (1, 1) and value_s[2] == '0': | |
| 1157 width = len(value_s[2:]) | |
| 1158 if underscore is not None: | |
| 1159 underscore[1] = value_su[2] == '_' | |
| 1160 underscore[2] = len(value_su[2:]) > 1 and value_su[-1] == '_' | |
| 1161 return OctalInt( | |
| 1162 sign * int(value_s[2:], 8), | |
| 1163 width=width, | |
| 1164 underscore=underscore, | |
| 1165 anchor=node.anchor, | |
| 1166 ) | |
| 1167 elif self.resolver.processing_version != (1, 2) and value_s[0] == '0': | |
| 1168 return sign * int(value_s, 8) | |
| 1169 elif self.resolver.processing_version != (1, 2) and ':' in value_s: | |
| 1170 digits = [int(part) for part in value_s.split(':')] | |
| 1171 digits.reverse() | |
| 1172 base = 1 | |
| 1173 value = 0 | |
| 1174 for digit in digits: | |
| 1175 value += digit * base | |
| 1176 base *= 60 | |
| 1177 return sign * value | |
| 1178 elif self.resolver.processing_version > (1, 1) and value_s[0] == '0': | |
| 1179 # not an octal, an integer with leading zero(s) | |
| 1180 if underscore is not None: | |
| 1181 # cannot have a leading underscore | |
| 1182 underscore[2] = len(value_su) > 1 and value_su[-1] == '_' | |
| 1183 return ScalarInt(sign * int(value_s), width=len(value_s), underscore=underscore) | |
| 1184 elif underscore: | |
| 1185 # cannot have a leading underscore | |
| 1186 underscore[2] = len(value_su) > 1 and value_su[-1] == '_' | |
| 1187 return ScalarInt( | |
| 1188 sign * int(value_s), width=None, underscore=underscore, anchor=node.anchor | |
| 1189 ) | |
| 1190 elif node.anchor: | |
| 1191 return ScalarInt(sign * int(value_s), width=None, anchor=node.anchor) | |
| 1192 else: | |
| 1193 return sign * int(value_s) | |
| 1194 | |
| 1195 def construct_yaml_float(self, node): | |
| 1196 # type: (Any) -> Any | |
| 1197 def leading_zeros(v): | |
| 1198 # type: (Any) -> int | |
| 1199 lead0 = 0 | |
| 1200 idx = 0 | |
| 1201 while idx < len(v) and v[idx] in '0.': | |
| 1202 if v[idx] == '0': | |
| 1203 lead0 += 1 | |
| 1204 idx += 1 | |
| 1205 return lead0 | |
| 1206 | |
| 1207 # underscore = None | |
| 1208 m_sign = False # type: Any | |
| 1209 value_so = to_str(self.construct_scalar(node)) | |
| 1210 value_s = value_so.replace('_', "").lower() | |
| 1211 sign = +1 | |
| 1212 if value_s[0] == '-': | |
| 1213 sign = -1 | |
| 1214 if value_s[0] in '+-': | |
| 1215 m_sign = value_s[0] | |
| 1216 value_s = value_s[1:] | |
| 1217 if value_s == '.inf': | |
| 1218 return sign * self.inf_value | |
| 1219 if value_s == '.nan': | |
| 1220 return self.nan_value | |
| 1221 if self.resolver.processing_version != (1, 2) and ':' in value_s: | |
| 1222 digits = [float(part) for part in value_s.split(':')] | |
| 1223 digits.reverse() | |
| 1224 base = 1 | |
| 1225 value = 0.0 | |
| 1226 for digit in digits: | |
| 1227 value += digit * base | |
| 1228 base *= 60 | |
| 1229 return sign * value | |
| 1230 if 'e' in value_s: | |
| 1231 try: | |
| 1232 mantissa, exponent = value_so.split('e') | |
| 1233 exp = 'e' | |
| 1234 except ValueError: | |
| 1235 mantissa, exponent = value_so.split('E') | |
| 1236 exp = 'E' | |
| 1237 if self.resolver.processing_version != (1, 2): | |
| 1238 # value_s is lower case independent of input | |
| 1239 if '.' not in mantissa: | |
| 1240 warnings.warn(MantissaNoDotYAML1_1Warning(node, value_so)) | |
| 1241 lead0 = leading_zeros(mantissa) | |
| 1242 width = len(mantissa) | |
| 1243 prec = mantissa.find('.') | |
| 1244 if m_sign: | |
| 1245 width -= 1 | |
| 1246 e_width = len(exponent) | |
| 1247 e_sign = exponent[0] in '+-' | |
| 1248 # nprint('sf', width, prec, m_sign, exp, e_width, e_sign) | |
| 1249 return ScalarFloat( | |
| 1250 sign * float(value_s), | |
| 1251 width=width, | |
| 1252 prec=prec, | |
| 1253 m_sign=m_sign, | |
| 1254 m_lead0=lead0, | |
| 1255 exp=exp, | |
| 1256 e_width=e_width, | |
| 1257 e_sign=e_sign, | |
| 1258 anchor=node.anchor, | |
| 1259 ) | |
| 1260 width = len(value_so) | |
| 1261 prec = value_so.index('.') # you can use index, this would not be float without dot | |
| 1262 lead0 = leading_zeros(value_so) | |
| 1263 return ScalarFloat( | |
| 1264 sign * float(value_s), | |
| 1265 width=width, | |
| 1266 prec=prec, | |
| 1267 m_sign=m_sign, | |
| 1268 m_lead0=lead0, | |
| 1269 anchor=node.anchor, | |
| 1270 ) | |
| 1271 | |
| 1272 def construct_yaml_str(self, node): | |
| 1273 # type: (Any) -> Any | |
| 1274 value = self.construct_scalar(node) | |
| 1275 if isinstance(value, ScalarString): | |
| 1276 return value | |
| 1277 if PY3: | |
| 1278 return value | |
| 1279 try: | |
| 1280 return value.encode('ascii') | |
| 1281 except AttributeError: | |
| 1282 # in case you replace the node dynamically e.g. with a dict | |
| 1283 return value | |
| 1284 except UnicodeEncodeError: | |
| 1285 return value | |
| 1286 | |
| 1287 def construct_rt_sequence(self, node, seqtyp, deep=False): | |
| 1288 # type: (Any, Any, bool) -> Any | |
| 1289 if not isinstance(node, SequenceNode): | |
| 1290 raise ConstructorError( | |
| 1291 None, None, 'expected a sequence node, but found %s' % node.id, node.start_mark | |
| 1292 ) | |
| 1293 ret_val = [] | |
| 1294 if node.comment: | |
| 1295 seqtyp._yaml_add_comment(node.comment[:2]) | |
| 1296 if len(node.comment) > 2: | |
| 1297 seqtyp.yaml_end_comment_extend(node.comment[2], clear=True) | |
| 1298 if node.anchor: | |
| 1299 from ruamel.yaml.serializer import templated_id | |
| 1300 | |
| 1301 if not templated_id(node.anchor): | |
| 1302 seqtyp.yaml_set_anchor(node.anchor) | |
| 1303 for idx, child in enumerate(node.value): | |
| 1304 ret_val.append(self.construct_object(child, deep=deep)) | |
| 1305 if child.comment: | |
| 1306 seqtyp._yaml_add_comment(child.comment, key=idx) | |
| 1307 seqtyp._yaml_set_idx_line_col( | |
| 1308 idx, [child.start_mark.line, child.start_mark.column] | |
| 1309 ) | |
| 1310 return ret_val | |
| 1311 | |
| 1312 def flatten_mapping(self, node): | |
| 1313 # type: (Any) -> Any | |
| 1314 """ | |
| 1315 This implements the merge key feature http://yaml.org/type/merge.html | |
| 1316 by inserting keys from the merge dict/list of dicts if not yet | |
| 1317 available in this node | |
| 1318 """ | |
| 1319 | |
| 1320 def constructed(value_node): | |
| 1321 # type: (Any) -> Any | |
| 1322 # If the contents of a merge are defined within the | |
| 1323 # merge marker, then they won't have been constructed | |
| 1324 # yet. But if they were already constructed, we need to use | |
| 1325 # the existing object. | |
| 1326 if value_node in self.constructed_objects: | |
| 1327 value = self.constructed_objects[value_node] | |
| 1328 else: | |
| 1329 value = self.construct_object(value_node, deep=False) | |
| 1330 return value | |
| 1331 | |
| 1332 # merge = [] | |
| 1333 merge_map_list = [] # type: List[Any] | |
| 1334 index = 0 | |
| 1335 while index < len(node.value): | |
| 1336 key_node, value_node = node.value[index] | |
| 1337 if key_node.tag == u'tag:yaml.org,2002:merge': | |
| 1338 if merge_map_list: # double << key | |
| 1339 if self.allow_duplicate_keys: | |
| 1340 del node.value[index] | |
| 1341 index += 1 | |
| 1342 continue | |
| 1343 args = [ | |
| 1344 'while constructing a mapping', | |
| 1345 node.start_mark, | |
| 1346 'found duplicate key "{}"'.format(key_node.value), | |
| 1347 key_node.start_mark, | |
| 1348 """ | |
| 1349 To suppress this check see: | |
| 1350 http://yaml.readthedocs.io/en/latest/api.html#duplicate-keys | |
| 1351 """, | |
| 1352 """\ | |
| 1353 Duplicate keys will become an error in future releases, and are errors | |
| 1354 by default when using the new API. | |
| 1355 """, | |
| 1356 ] | |
| 1357 if self.allow_duplicate_keys is None: | |
| 1358 warnings.warn(DuplicateKeyFutureWarning(*args)) | |
| 1359 else: | |
| 1360 raise DuplicateKeyError(*args) | |
| 1361 del node.value[index] | |
| 1362 if isinstance(value_node, MappingNode): | |
| 1363 merge_map_list.append((index, constructed(value_node))) | |
| 1364 # self.flatten_mapping(value_node) | |
| 1365 # merge.extend(value_node.value) | |
| 1366 elif isinstance(value_node, SequenceNode): | |
| 1367 # submerge = [] | |
| 1368 for subnode in value_node.value: | |
| 1369 if not isinstance(subnode, MappingNode): | |
| 1370 raise ConstructorError( | |
| 1371 'while constructing a mapping', | |
| 1372 node.start_mark, | |
| 1373 'expected a mapping for merging, but found %s' % subnode.id, | |
| 1374 subnode.start_mark, | |
| 1375 ) | |
| 1376 merge_map_list.append((index, constructed(subnode))) | |
| 1377 # self.flatten_mapping(subnode) | |
| 1378 # submerge.append(subnode.value) | |
| 1379 # submerge.reverse() | |
| 1380 # for value in submerge: | |
| 1381 # merge.extend(value) | |
| 1382 else: | |
| 1383 raise ConstructorError( | |
| 1384 'while constructing a mapping', | |
| 1385 node.start_mark, | |
| 1386 'expected a mapping or list of mappings for merging, ' | |
| 1387 'but found %s' % value_node.id, | |
| 1388 value_node.start_mark, | |
| 1389 ) | |
| 1390 elif key_node.tag == u'tag:yaml.org,2002:value': | |
| 1391 key_node.tag = u'tag:yaml.org,2002:str' | |
| 1392 index += 1 | |
| 1393 else: | |
| 1394 index += 1 | |
| 1395 return merge_map_list | |
| 1396 # if merge: | |
| 1397 # node.value = merge + node.value | |
| 1398 | |
| 1399 def _sentinel(self): | |
| 1400 # type: () -> None | |
| 1401 pass | |
| 1402 | |
| 1403 def construct_mapping(self, node, maptyp, deep=False): # type: ignore | |
| 1404 # type: (Any, Any, bool) -> Any | |
| 1405 if not isinstance(node, MappingNode): | |
| 1406 raise ConstructorError( | |
| 1407 None, None, 'expected a mapping node, but found %s' % node.id, node.start_mark | |
| 1408 ) | |
| 1409 merge_map = self.flatten_mapping(node) | |
| 1410 # mapping = {} | |
| 1411 if node.comment: | |
| 1412 maptyp._yaml_add_comment(node.comment[:2]) | |
| 1413 if len(node.comment) > 2: | |
| 1414 maptyp.yaml_end_comment_extend(node.comment[2], clear=True) | |
| 1415 if node.anchor: | |
| 1416 from ruamel.yaml.serializer import templated_id | |
| 1417 | |
| 1418 if not templated_id(node.anchor): | |
| 1419 maptyp.yaml_set_anchor(node.anchor) | |
| 1420 last_key, last_value = None, self._sentinel | |
| 1421 for key_node, value_node in node.value: | |
| 1422 # keys can be list -> deep | |
| 1423 key = self.construct_object(key_node, deep=True) | |
| 1424 # lists are not hashable, but tuples are | |
| 1425 if not isinstance(key, Hashable): | |
| 1426 if isinstance(key, MutableSequence): | |
| 1427 key_s = CommentedKeySeq(key) | |
| 1428 if key_node.flow_style is True: | |
| 1429 key_s.fa.set_flow_style() | |
| 1430 elif key_node.flow_style is False: | |
| 1431 key_s.fa.set_block_style() | |
| 1432 key = key_s | |
| 1433 elif isinstance(key, MutableMapping): | |
| 1434 key_m = CommentedKeyMap(key) | |
| 1435 if key_node.flow_style is True: | |
| 1436 key_m.fa.set_flow_style() | |
| 1437 elif key_node.flow_style is False: | |
| 1438 key_m.fa.set_block_style() | |
| 1439 key = key_m | |
| 1440 if PY2: | |
| 1441 try: | |
| 1442 hash(key) | |
| 1443 except TypeError as exc: | |
| 1444 raise ConstructorError( | |
| 1445 'while constructing a mapping', | |
| 1446 node.start_mark, | |
| 1447 'found unacceptable key (%s)' % exc, | |
| 1448 key_node.start_mark, | |
| 1449 ) | |
| 1450 else: | |
| 1451 if not isinstance(key, Hashable): | |
| 1452 raise ConstructorError( | |
| 1453 'while constructing a mapping', | |
| 1454 node.start_mark, | |
| 1455 'found unhashable key', | |
| 1456 key_node.start_mark, | |
| 1457 ) | |
| 1458 value = self.construct_object(value_node, deep=deep) | |
| 1459 if self.check_mapping_key(node, key_node, maptyp, key, value): | |
| 1460 | |
| 1461 if key_node.comment and len(key_node.comment) > 4 and key_node.comment[4]: | |
| 1462 if last_value is None: | |
| 1463 key_node.comment[0] = key_node.comment.pop(4) | |
| 1464 maptyp._yaml_add_comment(key_node.comment, value=last_key) | |
| 1465 else: | |
| 1466 key_node.comment[2] = key_node.comment.pop(4) | |
| 1467 maptyp._yaml_add_comment(key_node.comment, key=key) | |
| 1468 key_node.comment = None | |
| 1469 if key_node.comment: | |
| 1470 maptyp._yaml_add_comment(key_node.comment, key=key) | |
| 1471 if value_node.comment: | |
| 1472 maptyp._yaml_add_comment(value_node.comment, value=key) | |
| 1473 maptyp._yaml_set_kv_line_col( | |
| 1474 key, | |
| 1475 [ | |
| 1476 key_node.start_mark.line, | |
| 1477 key_node.start_mark.column, | |
| 1478 value_node.start_mark.line, | |
| 1479 value_node.start_mark.column, | |
| 1480 ], | |
| 1481 ) | |
| 1482 maptyp[key] = value | |
| 1483 last_key, last_value = key, value # could use indexing | |
| 1484 # do this last, or <<: before a key will prevent insertion in instances | |
| 1485 # of collections.OrderedDict (as they have no __contains__ | |
| 1486 if merge_map: | |
| 1487 maptyp.add_yaml_merge(merge_map) | |
| 1488 | |
| 1489 def construct_setting(self, node, typ, deep=False): | |
| 1490 # type: (Any, Any, bool) -> Any | |
| 1491 if not isinstance(node, MappingNode): | |
| 1492 raise ConstructorError( | |
| 1493 None, None, 'expected a mapping node, but found %s' % node.id, node.start_mark | |
| 1494 ) | |
| 1495 if node.comment: | |
| 1496 typ._yaml_add_comment(node.comment[:2]) | |
| 1497 if len(node.comment) > 2: | |
| 1498 typ.yaml_end_comment_extend(node.comment[2], clear=True) | |
| 1499 if node.anchor: | |
| 1500 from ruamel.yaml.serializer import templated_id | |
| 1501 | |
| 1502 if not templated_id(node.anchor): | |
| 1503 typ.yaml_set_anchor(node.anchor) | |
| 1504 for key_node, value_node in node.value: | |
| 1505 # keys can be list -> deep | |
| 1506 key = self.construct_object(key_node, deep=True) | |
| 1507 # lists are not hashable, but tuples are | |
| 1508 if not isinstance(key, Hashable): | |
| 1509 if isinstance(key, list): | |
| 1510 key = tuple(key) | |
| 1511 if PY2: | |
| 1512 try: | |
| 1513 hash(key) | |
| 1514 except TypeError as exc: | |
| 1515 raise ConstructorError( | |
| 1516 'while constructing a mapping', | |
| 1517 node.start_mark, | |
| 1518 'found unacceptable key (%s)' % exc, | |
| 1519 key_node.start_mark, | |
| 1520 ) | |
| 1521 else: | |
| 1522 if not isinstance(key, Hashable): | |
| 1523 raise ConstructorError( | |
| 1524 'while constructing a mapping', | |
| 1525 node.start_mark, | |
| 1526 'found unhashable key', | |
| 1527 key_node.start_mark, | |
| 1528 ) | |
| 1529 # construct but should be null | |
| 1530 value = self.construct_object(value_node, deep=deep) # NOQA | |
| 1531 self.check_set_key(node, key_node, typ, key) | |
| 1532 if key_node.comment: | |
| 1533 typ._yaml_add_comment(key_node.comment, key=key) | |
| 1534 if value_node.comment: | |
| 1535 typ._yaml_add_comment(value_node.comment, value=key) | |
| 1536 typ.add(key) | |
| 1537 | |
| 1538 def construct_yaml_seq(self, node): | |
| 1539 # type: (Any) -> Any | |
| 1540 data = CommentedSeq() | |
| 1541 data._yaml_set_line_col(node.start_mark.line, node.start_mark.column) | |
| 1542 if node.comment: | |
| 1543 data._yaml_add_comment(node.comment) | |
| 1544 yield data | |
| 1545 data.extend(self.construct_rt_sequence(node, data)) | |
| 1546 self.set_collection_style(data, node) | |
| 1547 | |
| 1548 def construct_yaml_map(self, node): | |
| 1549 # type: (Any) -> Any | |
| 1550 data = CommentedMap() | |
| 1551 data._yaml_set_line_col(node.start_mark.line, node.start_mark.column) | |
| 1552 yield data | |
| 1553 self.construct_mapping(node, data, deep=True) | |
| 1554 self.set_collection_style(data, node) | |
| 1555 | |
| 1556 def set_collection_style(self, data, node): | |
| 1557 # type: (Any, Any) -> None | |
| 1558 if len(data) == 0: | |
| 1559 return | |
| 1560 if node.flow_style is True: | |
| 1561 data.fa.set_flow_style() | |
| 1562 elif node.flow_style is False: | |
| 1563 data.fa.set_block_style() | |
| 1564 | |
| 1565 def construct_yaml_object(self, node, cls): | |
| 1566 # type: (Any, Any) -> Any | |
| 1567 data = cls.__new__(cls) | |
| 1568 yield data | |
| 1569 if hasattr(data, '__setstate__'): | |
| 1570 state = SafeConstructor.construct_mapping(self, node, deep=True) | |
| 1571 data.__setstate__(state) | |
| 1572 else: | |
| 1573 state = SafeConstructor.construct_mapping(self, node) | |
| 1574 data.__dict__.update(state) | |
| 1575 | |
| 1576 def construct_yaml_omap(self, node): | |
| 1577 # type: (Any) -> Any | |
| 1578 # Note: we do now check for duplicate keys | |
| 1579 omap = CommentedOrderedMap() | |
| 1580 omap._yaml_set_line_col(node.start_mark.line, node.start_mark.column) | |
| 1581 if node.flow_style is True: | |
| 1582 omap.fa.set_flow_style() | |
| 1583 elif node.flow_style is False: | |
| 1584 omap.fa.set_block_style() | |
| 1585 yield omap | |
| 1586 if node.comment: | |
| 1587 omap._yaml_add_comment(node.comment[:2]) | |
| 1588 if len(node.comment) > 2: | |
| 1589 omap.yaml_end_comment_extend(node.comment[2], clear=True) | |
| 1590 if not isinstance(node, SequenceNode): | |
| 1591 raise ConstructorError( | |
| 1592 'while constructing an ordered map', | |
| 1593 node.start_mark, | |
| 1594 'expected a sequence, but found %s' % node.id, | |
| 1595 node.start_mark, | |
| 1596 ) | |
| 1597 for subnode in node.value: | |
| 1598 if not isinstance(subnode, MappingNode): | |
| 1599 raise ConstructorError( | |
| 1600 'while constructing an ordered map', | |
| 1601 node.start_mark, | |
| 1602 'expected a mapping of length 1, but found %s' % subnode.id, | |
| 1603 subnode.start_mark, | |
| 1604 ) | |
| 1605 if len(subnode.value) != 1: | |
| 1606 raise ConstructorError( | |
| 1607 'while constructing an ordered map', | |
| 1608 node.start_mark, | |
| 1609 'expected a single mapping item, but found %d items' % len(subnode.value), | |
| 1610 subnode.start_mark, | |
| 1611 ) | |
| 1612 key_node, value_node = subnode.value[0] | |
| 1613 key = self.construct_object(key_node) | |
| 1614 assert key not in omap | |
| 1615 value = self.construct_object(value_node) | |
| 1616 if key_node.comment: | |
| 1617 omap._yaml_add_comment(key_node.comment, key=key) | |
| 1618 if subnode.comment: | |
| 1619 omap._yaml_add_comment(subnode.comment, key=key) | |
| 1620 if value_node.comment: | |
| 1621 omap._yaml_add_comment(value_node.comment, value=key) | |
| 1622 omap[key] = value | |
| 1623 | |
| 1624 def construct_yaml_set(self, node): | |
| 1625 # type: (Any) -> Any | |
| 1626 data = CommentedSet() | |
| 1627 data._yaml_set_line_col(node.start_mark.line, node.start_mark.column) | |
| 1628 yield data | |
| 1629 self.construct_setting(node, data) | |
| 1630 | |
| 1631 def construct_undefined(self, node): | |
| 1632 # type: (Any) -> Any | |
| 1633 try: | |
| 1634 if isinstance(node, MappingNode): | |
| 1635 data = CommentedMap() | |
| 1636 data._yaml_set_line_col(node.start_mark.line, node.start_mark.column) | |
| 1637 if node.flow_style is True: | |
| 1638 data.fa.set_flow_style() | |
| 1639 elif node.flow_style is False: | |
| 1640 data.fa.set_block_style() | |
| 1641 data.yaml_set_tag(node.tag) | |
| 1642 yield data | |
| 1643 if node.anchor: | |
| 1644 data.yaml_set_anchor(node.anchor) | |
| 1645 self.construct_mapping(node, data) | |
| 1646 return | |
| 1647 elif isinstance(node, ScalarNode): | |
| 1648 data2 = TaggedScalar() | |
| 1649 data2.value = self.construct_scalar(node) | |
| 1650 data2.style = node.style | |
| 1651 data2.yaml_set_tag(node.tag) | |
| 1652 yield data2 | |
| 1653 if node.anchor: | |
| 1654 data2.yaml_set_anchor(node.anchor, always_dump=True) | |
| 1655 return | |
| 1656 elif isinstance(node, SequenceNode): | |
| 1657 data3 = CommentedSeq() | |
| 1658 data3._yaml_set_line_col(node.start_mark.line, node.start_mark.column) | |
| 1659 if node.flow_style is True: | |
| 1660 data3.fa.set_flow_style() | |
| 1661 elif node.flow_style is False: | |
| 1662 data3.fa.set_block_style() | |
| 1663 data3.yaml_set_tag(node.tag) | |
| 1664 yield data3 | |
| 1665 if node.anchor: | |
| 1666 data3.yaml_set_anchor(node.anchor) | |
| 1667 data3.extend(self.construct_sequence(node)) | |
| 1668 return | |
| 1669 except: # NOQA | |
| 1670 pass | |
| 1671 raise ConstructorError( | |
| 1672 None, | |
| 1673 None, | |
| 1674 'could not determine a constructor for the tag %r' % utf8(node.tag), | |
| 1675 node.start_mark, | |
| 1676 ) | |
| 1677 | |
| 1678 def construct_yaml_timestamp(self, node, values=None): | |
| 1679 # type: (Any, Any) -> Any | |
| 1680 try: | |
| 1681 match = self.timestamp_regexp.match(node.value) | |
| 1682 except TypeError: | |
| 1683 match = None | |
| 1684 if match is None: | |
| 1685 raise ConstructorError( | |
| 1686 None, | |
| 1687 None, | |
| 1688 'failed to construct timestamp from "{}"'.format(node.value), | |
| 1689 node.start_mark, | |
| 1690 ) | |
| 1691 values = match.groupdict() | |
| 1692 if not values['hour']: | |
| 1693 return SafeConstructor.construct_yaml_timestamp(self, node, values) | |
| 1694 for part in ['t', 'tz_sign', 'tz_hour', 'tz_minute']: | |
| 1695 if values[part]: | |
| 1696 break | |
| 1697 else: | |
| 1698 return SafeConstructor.construct_yaml_timestamp(self, node, values) | |
| 1699 year = int(values['year']) | |
| 1700 month = int(values['month']) | |
| 1701 day = int(values['day']) | |
| 1702 hour = int(values['hour']) | |
| 1703 minute = int(values['minute']) | |
| 1704 second = int(values['second']) | |
| 1705 fraction = 0 | |
| 1706 if values['fraction']: | |
| 1707 fraction_s = values['fraction'][:6] | |
| 1708 while len(fraction_s) < 6: | |
| 1709 fraction_s += '0' | |
| 1710 fraction = int(fraction_s) | |
| 1711 if len(values['fraction']) > 6 and int(values['fraction'][6]) > 4: | |
| 1712 fraction += 1 | |
| 1713 delta = None | |
| 1714 if values['tz_sign']: | |
| 1715 tz_hour = int(values['tz_hour']) | |
| 1716 minutes = values['tz_minute'] | |
| 1717 tz_minute = int(minutes) if minutes else 0 | |
| 1718 delta = datetime.timedelta(hours=tz_hour, minutes=tz_minute) | |
| 1719 if values['tz_sign'] == '-': | |
| 1720 delta = -delta | |
| 1721 if delta: | |
| 1722 dt = datetime.datetime(year, month, day, hour, minute) | |
| 1723 dt -= delta | |
| 1724 data = TimeStamp(dt.year, dt.month, dt.day, dt.hour, dt.minute, second, fraction) | |
| 1725 data._yaml['delta'] = delta | |
| 1726 tz = values['tz_sign'] + values['tz_hour'] | |
| 1727 if values['tz_minute']: | |
| 1728 tz += ':' + values['tz_minute'] | |
| 1729 data._yaml['tz'] = tz | |
| 1730 else: | |
| 1731 data = TimeStamp(year, month, day, hour, minute, second, fraction) | |
| 1732 if values['tz']: # no delta | |
| 1733 data._yaml['tz'] = values['tz'] | |
| 1734 | |
| 1735 if values['t']: | |
| 1736 data._yaml['t'] = True | |
| 1737 return data | |
| 1738 | |
| 1739 def construct_yaml_bool(self, node): | |
| 1740 # type: (Any) -> Any | |
| 1741 b = SafeConstructor.construct_yaml_bool(self, node) | |
| 1742 if node.anchor: | |
| 1743 return ScalarBoolean(b, anchor=node.anchor) | |
| 1744 return b | |
| 1745 | |
| 1746 | |
| 1747 RoundTripConstructor.add_constructor( | |
| 1748 u'tag:yaml.org,2002:null', RoundTripConstructor.construct_yaml_null | |
| 1749 ) | |
| 1750 | |
| 1751 RoundTripConstructor.add_constructor( | |
| 1752 u'tag:yaml.org,2002:bool', RoundTripConstructor.construct_yaml_bool | |
| 1753 ) | |
| 1754 | |
| 1755 RoundTripConstructor.add_constructor( | |
| 1756 u'tag:yaml.org,2002:int', RoundTripConstructor.construct_yaml_int | |
| 1757 ) | |
| 1758 | |
| 1759 RoundTripConstructor.add_constructor( | |
| 1760 u'tag:yaml.org,2002:float', RoundTripConstructor.construct_yaml_float | |
| 1761 ) | |
| 1762 | |
| 1763 RoundTripConstructor.add_constructor( | |
| 1764 u'tag:yaml.org,2002:binary', RoundTripConstructor.construct_yaml_binary | |
| 1765 ) | |
| 1766 | |
| 1767 RoundTripConstructor.add_constructor( | |
| 1768 u'tag:yaml.org,2002:timestamp', RoundTripConstructor.construct_yaml_timestamp | |
| 1769 ) | |
| 1770 | |
| 1771 RoundTripConstructor.add_constructor( | |
| 1772 u'tag:yaml.org,2002:omap', RoundTripConstructor.construct_yaml_omap | |
| 1773 ) | |
| 1774 | |
| 1775 RoundTripConstructor.add_constructor( | |
| 1776 u'tag:yaml.org,2002:pairs', RoundTripConstructor.construct_yaml_pairs | |
| 1777 ) | |
| 1778 | |
| 1779 RoundTripConstructor.add_constructor( | |
| 1780 u'tag:yaml.org,2002:set', RoundTripConstructor.construct_yaml_set | |
| 1781 ) | |
| 1782 | |
| 1783 RoundTripConstructor.add_constructor( | |
| 1784 u'tag:yaml.org,2002:str', RoundTripConstructor.construct_yaml_str | |
| 1785 ) | |
| 1786 | |
| 1787 RoundTripConstructor.add_constructor( | |
| 1788 u'tag:yaml.org,2002:seq', RoundTripConstructor.construct_yaml_seq | |
| 1789 ) | |
| 1790 | |
| 1791 RoundTripConstructor.add_constructor( | |
| 1792 u'tag:yaml.org,2002:map', RoundTripConstructor.construct_yaml_map | |
| 1793 ) | |
| 1794 | |
| 1795 RoundTripConstructor.add_constructor(None, RoundTripConstructor.construct_undefined) |
