You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

143 line
4.1 KiB

  1. from __future__ import annotations
  2. from ruamel.yaml.anchor import Anchor
  3. if False: # MYPY
  4. from typing import Text, Any, Dict, List # NOQA
  5. from ruamel.yaml.compat import SupportsIndex
  6. __all__ = [
  7. 'ScalarString',
  8. 'LiteralScalarString',
  9. 'FoldedScalarString',
  10. 'SingleQuotedScalarString',
  11. 'DoubleQuotedScalarString',
  12. 'PlainScalarString',
  13. # PreservedScalarString is the old name, as it was the first to be preserved on rt,
  14. # use LiteralScalarString instead
  15. 'PreservedScalarString',
  16. ]
  17. class ScalarString(str):
  18. __slots__ = Anchor.attrib
  19. def __new__(cls, *args: Any, **kw: Any) -> Any:
  20. anchor = kw.pop('anchor', None)
  21. ret_val = str.__new__(cls, *args, **kw)
  22. if anchor is not None:
  23. ret_val.yaml_set_anchor(anchor, always_dump=True)
  24. return ret_val
  25. def replace(self, old: Any, new: Any, maxreplace: SupportsIndex = -1) -> Any:
  26. return type(self)((str.replace(self, old, new, maxreplace)))
  27. @property
  28. def anchor(self) -> Any:
  29. if not hasattr(self, Anchor.attrib):
  30. setattr(self, Anchor.attrib, Anchor())
  31. return getattr(self, Anchor.attrib)
  32. def yaml_anchor(self, any: bool = False) -> Any:
  33. if not hasattr(self, Anchor.attrib):
  34. return None
  35. if any or self.anchor.always_dump:
  36. return self.anchor
  37. return None
  38. def yaml_set_anchor(self, value: Any, always_dump: bool = False) -> None:
  39. self.anchor.value = value
  40. self.anchor.always_dump = always_dump
  41. class LiteralScalarString(ScalarString):
  42. __slots__ = 'comment' # the comment after the | on the first line
  43. style = '|'
  44. def __new__(cls, value: Text, anchor: Any = None) -> Any:
  45. return ScalarString.__new__(cls, value, anchor=anchor)
  46. PreservedScalarString = LiteralScalarString
  47. class FoldedScalarString(ScalarString):
  48. __slots__ = ('fold_pos', 'comment') # the comment after the > on the first line
  49. style = '>'
  50. def __new__(cls, value: Text, anchor: Any = None) -> Any:
  51. return ScalarString.__new__(cls, value, anchor=anchor)
  52. class SingleQuotedScalarString(ScalarString):
  53. __slots__ = ()
  54. style = "'"
  55. def __new__(cls, value: Text, anchor: Any = None) -> Any:
  56. return ScalarString.__new__(cls, value, anchor=anchor)
  57. class DoubleQuotedScalarString(ScalarString):
  58. __slots__ = ()
  59. style = '"'
  60. def __new__(cls, value: Text, anchor: Any = None) -> Any:
  61. return ScalarString.__new__(cls, value, anchor=anchor)
  62. class PlainScalarString(ScalarString):
  63. __slots__ = ()
  64. style = ''
  65. def __new__(cls, value: Text, anchor: Any = None) -> Any:
  66. return ScalarString.__new__(cls, value, anchor=anchor)
  67. def preserve_literal(s: Text) -> Text:
  68. return LiteralScalarString(s.replace('\r\n', '\n').replace('\r', '\n'))
  69. def walk_tree(base: Any, map: Any = None) -> None:
  70. """
  71. the routine here walks over a simple yaml tree (recursing in
  72. dict values and list items) and converts strings that
  73. have multiple lines to literal scalars
  74. You can also provide an explicit (ordered) mapping for multiple transforms
  75. (first of which is executed):
  76. map = ruamel.yaml.compat.ordereddict
  77. map['\n'] = preserve_literal
  78. map[':'] = SingleQuotedScalarString
  79. walk_tree(data, map=map)
  80. """
  81. from collections.abc import MutableMapping, MutableSequence
  82. if map is None:
  83. map = {'\n': preserve_literal}
  84. if isinstance(base, MutableMapping):
  85. for k in base:
  86. v: Text = base[k]
  87. if isinstance(v, str):
  88. for ch in map:
  89. if ch in v:
  90. base[k] = map[ch](v)
  91. break
  92. else:
  93. walk_tree(v, map=map)
  94. elif isinstance(base, MutableSequence):
  95. for idx, elem in enumerate(base):
  96. if isinstance(elem, str):
  97. for ch in map:
  98. if ch in elem:
  99. base[idx] = map[ch](elem)
  100. break
  101. else:
  102. walk_tree(elem, map=map)