scalarstring.py 4.0 KB

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