constructor.py 69 KB

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