From 25b7008eb7721763fe0ea10cc23abeed2c1ef780 Mon Sep 17 00:00:00 2001 From: Anthon van der Neut Date: Thu, 27 Dec 2018 23:37:32 +0100 Subject: roundtrip anchors/aliases on str, int, float --- __init__.py | 4 +-- comments.py | 4 +-- composer.py | 1 + constructor.py | 43 +++++++++++++++++++++++++-------- emitter.py | 11 ++++++--- representer.py | 75 ++++++++++++++++++++++++++++++++++++++++++--------------- scalarfloat.py | 27 ++++++++++++++++++++- scalarint.py | 60 ++++++++++++++++++++++++++++++++++----------- scalarstring.py | 51 +++++++++++++++++++++++++-------------- 9 files changed, 206 insertions(+), 70 deletions(-) diff --git a/__init__.py b/__init__.py index 4300f70..c0c019a 100644 --- a/__init__.py +++ b/__init__.py @@ -7,8 +7,8 @@ if False: # MYPY _package_data = dict( full_package_name='ruamel.yaml', - version_info=(0, 15, 81), - __version__='0.15.81', + version_info=(0, 15, 82, 'dev'), + __version__='0.15.82.dev', author='Anthon van der Neut', author_email='a.van.der.neut@ruamel.eu', description='ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order', # NOQA diff --git a/comments.py b/comments.py index 7048772..5068d84 100644 --- a/comments.py +++ b/comments.py @@ -375,7 +375,7 @@ class CommentedBase(object): raise NotImplementedError -class CommentedSeq(MutableSliceableSequence, list, CommentedBase): +class CommentedSeq(MutableSliceableSequence, list, CommentedBase): # type: ignore __slots__ = (Comment.attrib, '_lst') def __init__(self, *args, **kw): @@ -508,7 +508,7 @@ class CommentedSeq(MutableSliceableSequence, list, CommentedBase): return list.__repr__(self) -class CommentedKeySeq(tuple, CommentedBase): +class CommentedKeySeq(tuple, CommentedBase): # type: ignore """This primarily exists to be able to roundtrip keys that are sequences""" def _yaml_add_comment(self, comment, key=NoComment): diff --git a/composer.py b/composer.py index 745c17a..d8d3d11 100644 --- a/composer.py +++ b/composer.py @@ -152,6 +152,7 @@ class Composer(object): event.end_mark, style=event.style, comment=event.comment, + anchor=anchor, ) if anchor is not None: self.anchors[anchor] = node diff --git a/constructor.py b/constructor.py index 2d3250a..6aef100 100644 --- a/constructor.py +++ b/constructor.py @@ -24,7 +24,7 @@ from ruamel.yaml.comments import (CommentedMap, CommentedOrderedMap, CommentedSe CommentedKeyMap) from ruamel.yaml.scalarstring import (SingleQuotedScalarString, DoubleQuotedScalarString, LiteralScalarString, FoldedScalarString, - ScalarString,) + PlainScalarString, ScalarString,) from ruamel.yaml.scalarint import ScalarInt, BinaryInt, OctalInt, HexInt, HexCapsInt from ruamel.yaml.scalarfloat import ScalarFloat from ruamel.yaml.timestamp import TimeStamp @@ -1057,7 +1057,7 @@ class RoundTripConstructor(SafeConstructor): ) if node.style == '|' and isinstance(node.value, text_type): - lss = LiteralScalarString(node.value) + lss = LiteralScalarString(node.value, anchor=node.anchor) if node.comment and node.comment[1]: lss.comment = node.comment[1][0] # type: ignore return lss @@ -1069,7 +1069,7 @@ class RoundTripConstructor(SafeConstructor): if idx < 0: break fold_positions.append(idx - len(fold_positions)) - fss = FoldedScalarString(node.value.replace('\a', '')) + fss = FoldedScalarString(node.value.replace('\a', ''), anchor=node.anchor) if node.comment and node.comment[1]: fss.comment = node.comment[1][0] # type: ignore if fold_positions: @@ -1077,9 +1077,11 @@ class RoundTripConstructor(SafeConstructor): return fss elif bool(self._preserve_quotes) and isinstance(node.value, text_type): if node.style == "'": - return SingleQuotedScalarString(node.value) + return SingleQuotedScalarString(node.value, anchor=node.anchor) if node.style == '"': - return DoubleQuotedScalarString(node.value) + return DoubleQuotedScalarString(node.value, anchor=node.anchor) + if node.anchor: + return PlainScalarString(node.value, anchor=node.anchor) return node.value def construct_yaml_int(self, node): @@ -1108,7 +1110,10 @@ class RoundTripConstructor(SafeConstructor): underscore[1] = value_su[2] == '_' underscore[2] = len(value_su[2:]) > 1 and value_su[-1] == '_' return BinaryInt( # type: ignore - sign * int(value_s[2:], 2), width=width, underscore=underscore + sign * int(value_s[2:], 2), + width=width, + underscore=underscore, + anchor=node.anchor, ) elif value_s.startswith('0x'): # default to lower-case if no a-fA-F in string @@ -1124,7 +1129,12 @@ class RoundTripConstructor(SafeConstructor): if underscore is not None: underscore[1] = value_su[2] == '_' underscore[2] = len(value_su[2:]) > 1 and value_su[-1] == '_' - return hex_fun(sign * int(value_s[2:], 16), width=width, underscore=underscore) + return hex_fun( + sign * int(value_s[2:], 16), + width=width, + underscore=underscore, + anchor=node.anchor, + ) elif value_s.startswith('0o'): if self.resolver.processing_version > (1, 1) and value_s[2] == '0': width = len(value_s[2:]) @@ -1132,7 +1142,10 @@ class RoundTripConstructor(SafeConstructor): underscore[1] = value_su[2] == '_' underscore[2] = len(value_su[2:]) > 1 and value_su[-1] == '_' return OctalInt( # type: ignore - sign * int(value_s[2:], 8), width=width, underscore=underscore + sign * int(value_s[2:], 8), + width=width, + underscore=underscore, + anchor=node.anchor, ) elif self.resolver.processing_version != (1, 2) and value_s[0] == '0': return sign * int(value_s, 8) @@ -1157,7 +1170,11 @@ class RoundTripConstructor(SafeConstructor): # cannot have a leading underscore underscore[2] = len(value_su) > 1 and value_su[-1] == '_' return ScalarInt( # type: ignore - sign * int(value_s), width=None, underscore=underscore + sign * int(value_s), width=None, underscore=underscore, anchor=node.anchor + ) + elif node.anchor: + return ScalarInt( # type: ignore + sign * int(value_s), width=None, anchor=node.anchor ) else: return sign * int(value_s) @@ -1225,12 +1242,18 @@ class RoundTripConstructor(SafeConstructor): exp=exp, e_width=e_width, e_sign=e_sign, + anchor=node.anchor, ) width = len(value_so) prec = value_so.index('.') # you can use index, this would not be float without dot lead0 = leading_zeros(value_so) return ScalarFloat( # type: ignore - sign * float(value_s), width=width, prec=prec, m_sign=m_sign, m_lead0=lead0 + sign * float(value_s), + width=width, + prec=prec, + m_sign=m_sign, + m_lead0=lead0, + anchor=node.anchor, ) def construct_yaml_str(self, node): diff --git a/emitter.py b/emitter.py index 61ca269..7829219 100644 --- a/emitter.py +++ b/emitter.py @@ -402,12 +402,14 @@ class Emitter(object): if isinstance(self.event, AliasEvent): self.expect_alias() elif isinstance(self.event, (ScalarEvent, CollectionStartEvent)): - self.process_anchor(u'&') + if self.process_anchor(u'&') and isinstance(self.event, ScalarEvent): + self.no_newline = True self.process_tag() if isinstance(self.event, ScalarEvent): + # nprint('@', self.indention, self.no_newline, self.column) self.expect_scalar() elif isinstance(self.event, SequenceStartEvent): - # nprintf('@', self.indention, self.no_newline, self.column) + # nprint('@', self.indention, self.no_newline, self.column) i2, n2 = self.indention, self.no_newline # NOQA if self.event.comment: if self.event.flow_style is False and self.event.comment: @@ -757,15 +759,16 @@ class Emitter(object): # Anchor, Tag, and Scalar processors. def process_anchor(self, indicator): - # type: (Any) -> None + # type: (Any) -> bool if self.event.anchor is None: self.prepared_anchor = None - return + return False if self.prepared_anchor is None: self.prepared_anchor = self.prepare_anchor(self.event.anchor) if self.prepared_anchor: self.write_indicator(indicator + self.prepared_anchor, True) self.prepared_anchor = None + return True def process_tag(self): # type: () -> None diff --git a/representer.py b/representer.py index d1fd739..923b2a2 100644 --- a/representer.py +++ b/representer.py @@ -12,6 +12,7 @@ from ruamel.yaml.scalarstring import ( FoldedScalarString, SingleQuotedScalarString, DoubleQuotedScalarString, + PlainScalarString, ) from ruamel.yaml.scalarint import ScalarInt, BinaryInt, OctalInt, HexInt, HexCapsInt from ruamel.yaml.scalarfloat import ScalarFloat @@ -147,8 +148,8 @@ class BaseRepresenter(object): cls.yaml_multi_representers = cls.yaml_multi_representers.copy() cls.yaml_multi_representers[data_type] = representer - def represent_scalar(self, tag, value, style=None): - # type: (Any, Any, Any) -> Any + def represent_scalar(self, tag, value, style=None, anchor=None): + # type: (Any, Any, Any, Any) -> Any if style is None: style = self.default_style comment = None @@ -156,7 +157,7 @@ class BaseRepresenter(object): comment = getattr(value, 'comment', None) if comment: comment = [None, [comment]] - node = ScalarNode(tag, value, style=style, comment=comment) + node = ScalarNode(tag, value, style=style, comment=comment, anchor=anchor) if self.alias_key is not None: self.represented_objects[self.alias_key] = node return node @@ -669,6 +670,15 @@ class RoundTripRepresenter(SafeRepresenter): dumper=dumper, ) + def ignore_aliases(self, data): + # type: (Any) -> bool + try: + if data.anchor is not None and data.anchor.value is not None: + return False + except AttributeError: + pass + return SafeRepresenter.ignore_aliases(self, data) + def represent_none(self, data): # type: (Any) -> Any if len(self.represented_objects) == 0 and not self.serializer.use_explicit_start: @@ -680,10 +690,11 @@ class RoundTripRepresenter(SafeRepresenter): # type: (Any) -> Any tag = None style = '|' + anchor = data.yaml_anchor(any=True) if PY2 and not isinstance(data, unicode): data = unicode(data, 'ascii') tag = u'tag:yaml.org,2002:str' - return self.represent_scalar(tag, data, style=style) + return self.represent_scalar(tag, data, style=style, anchor=anchor) represent_preserved_scalarstring = represent_literal_scalarstring @@ -691,6 +702,7 @@ class RoundTripRepresenter(SafeRepresenter): # type: (Any) -> Any tag = None style = '>' + anchor = data.yaml_anchor(any=True) for fold_pos in reversed(getattr(data, 'fold_pos', [])): if ( data[fold_pos] == ' ' @@ -701,30 +713,42 @@ class RoundTripRepresenter(SafeRepresenter): if PY2 and not isinstance(data, unicode): data = unicode(data, 'ascii') tag = u'tag:yaml.org,2002:str' - return self.represent_scalar(tag, data, style=style) + return self.represent_scalar(tag, data, style=style, anchor=anchor) def represent_single_quoted_scalarstring(self, data): # type: (Any) -> Any tag = None style = "'" + anchor = data.yaml_anchor(any=True) if PY2 and not isinstance(data, unicode): data = unicode(data, 'ascii') tag = u'tag:yaml.org,2002:str' - return self.represent_scalar(tag, data, style=style) + return self.represent_scalar(tag, data, style=style, anchor=anchor) def represent_double_quoted_scalarstring(self, data): # type: (Any) -> Any tag = None style = '"' + anchor = data.yaml_anchor(any=True) if PY2 and not isinstance(data, unicode): data = unicode(data, 'ascii') tag = u'tag:yaml.org,2002:str' - return self.represent_scalar(tag, data, style=style) + return self.represent_scalar(tag, data, style=style, anchor=anchor) - def insert_underscore(self, prefix, s, underscore): - # type: (Any, Any, Any) -> Any + def represent_plain_scalarstring(self, data): + # type: (Any) -> Any + tag = None + style = '' + anchor = data.yaml_anchor(any=True) + if PY2 and not isinstance(data, unicode): + data = unicode(data, 'ascii') + tag = u'tag:yaml.org,2002:str' + return self.represent_scalar(tag, data, style=style, anchor=anchor) + + def insert_underscore(self, prefix, s, underscore, anchor=None): + # type: (Any, Any, Any, Any) -> Any if underscore is None: - return self.represent_scalar(u'tag:yaml.org,2002:int', prefix + s) + return self.represent_scalar(u'tag:yaml.org,2002:int', prefix + s, anchor=anchor) if underscore[0]: sl = list(s) pos = len(s) - underscore[0] @@ -736,7 +760,7 @@ class RoundTripRepresenter(SafeRepresenter): s = '_' + s if underscore[2]: s += '_' - return self.represent_scalar(u'tag:yaml.org,2002:int', prefix + s) + return self.represent_scalar(u'tag:yaml.org,2002:int', prefix + s, anchor=anchor) def represent_scalar_int(self, data): # type: (Any) -> Any @@ -744,7 +768,8 @@ class RoundTripRepresenter(SafeRepresenter): s = '{:0{}d}'.format(data, data._width) else: s = format(data, 'd') - return self.insert_underscore("", s, data._underscore) + anchor = data.yaml_anchor(any=True) + return self.insert_underscore("", s, data._underscore, anchor=anchor) def represent_binary_int(self, data): # type: (Any) -> Any @@ -753,7 +778,8 @@ class RoundTripRepresenter(SafeRepresenter): s = '{:0{}b}'.format(data, data._width) else: s = format(data, 'b') - return self.insert_underscore('0b', s, data._underscore) + anchor = data.yaml_anchor(any=True) + return self.insert_underscore('0b', s, data._underscore, anchor=anchor) def represent_octal_int(self, data): # type: (Any) -> Any @@ -762,7 +788,8 @@ class RoundTripRepresenter(SafeRepresenter): s = '{:0{}o}'.format(data, data._width) else: s = format(data, 'o') - return self.insert_underscore('0o', s, data._underscore) + anchor = data.yaml_anchor(any=True) + return self.insert_underscore('0o', s, data._underscore, anchor=anchor) def represent_hex_int(self, data): # type: (Any) -> Any @@ -771,7 +798,8 @@ class RoundTripRepresenter(SafeRepresenter): s = '{:0{}x}'.format(data, data._width) else: s = format(data, 'x') - return self.insert_underscore('0x', s, data._underscore) + anchor = data.yaml_anchor(any=True) + return self.insert_underscore('0x', s, data._underscore, anchor=anchor) def represent_hex_caps_int(self, data): # type: (Any) -> Any @@ -780,12 +808,14 @@ class RoundTripRepresenter(SafeRepresenter): s = '{:0{}X}'.format(data, data._width) else: s = format(data, 'X') - return self.insert_underscore('0x', s, data._underscore) + anchor = data.yaml_anchor(any=True) + return self.insert_underscore('0x', s, data._underscore, anchor=anchor) def represent_scalar_float(self, data): # type: (Any) -> Any """ this is way more complicated """ value = None + anchor = data.yaml_anchor(any=True) if data != data or (data == 0.0 and data == 1.0): value = u'.nan' elif data == self.inf_value: @@ -793,7 +823,7 @@ class RoundTripRepresenter(SafeRepresenter): elif data == -self.inf_value: value = u'-.inf' if value: - return self.represent_scalar(u'tag:yaml.org,2002:float', value) + return self.represent_scalar(u'tag:yaml.org,2002:float', value, anchor=anchor) if data._exp is None and data._prec > 0 and data._prec == data._width - 1: # no exponent, but trailing dot value = u'{}{:d}.'.format(data._m_sign if data._m_sign else "", abs(int(data))) @@ -812,7 +842,10 @@ class RoundTripRepresenter(SafeRepresenter): else: # exponent m, es = u'{:{}.{}e}'.format( - data, data._width, data._width - data._prec + (1 if data._m_sign else 0) + # data, data._width, data._width - data._prec + (1 if data._m_sign else 0) + data, + data._width, + data._width + (1 if data._m_sign else 0), ).split('e') w = data._width if data._prec > 0 else (data._width + 1) if data < 0: @@ -855,7 +888,7 @@ class RoundTripRepresenter(SafeRepresenter): if value is None: value = to_unicode(repr(data)).lower() - return self.represent_scalar(u'tag:yaml.org,2002:float', value) + return self.represent_scalar(u'tag:yaml.org,2002:float', value, anchor=anchor) def represent_sequence(self, tag, sequence, flow_style=None): # type: (Any, Any, Any) -> Any @@ -1188,6 +1221,10 @@ RoundTripRepresenter.add_representer( DoubleQuotedScalarString, RoundTripRepresenter.represent_double_quoted_scalarstring ) +RoundTripRepresenter.add_representer( + PlainScalarString, RoundTripRepresenter.represent_plain_scalarstring +) + RoundTripRepresenter.add_representer(ScalarInt, RoundTripRepresenter.represent_scalar_int) RoundTripRepresenter.add_representer(BinaryInt, RoundTripRepresenter.represent_binary_int) diff --git a/scalarfloat.py b/scalarfloat.py index 65a1a28..0404df3 100644 --- a/scalarfloat.py +++ b/scalarfloat.py @@ -4,6 +4,7 @@ from __future__ import print_function, absolute_import, division, unicode_litera import sys from .compat import no_limit_int # NOQA +from ruamel.yaml.anchor import Anchor if False: # MYPY from typing import Text, Any, Dict, List # NOQA @@ -22,6 +23,7 @@ class ScalarFloat(float): e_width = kw.pop('e_width', None) # type: ignore e_sign = kw.pop('e_sign', None) # type: ignore underscore = kw.pop('underscore', None) # type: ignore + anchor = kw.pop('anchor', None) # type: ignore v = float.__new__(cls, *args, **kw) # type: ignore v._width = width v._prec = prec @@ -31,6 +33,8 @@ class ScalarFloat(float): v._e_width = e_width v._e_sign = e_sign v._underscore = underscore + if anchor is not None: + v.yaml_set_anchor(anchor, always_dump=True) return v def __iadd__(self, a): # type: ignore @@ -74,15 +78,36 @@ class ScalarFloat(float): x._underscore = self._underscore[:] if self._underscore is not None else None # NOQA return x + @property + def anchor(self): + # type: () -> Any + if not hasattr(self, Anchor.attrib): + setattr(self, Anchor.attrib, Anchor()) + return getattr(self, Anchor.attrib) + + def yaml_anchor(self, any=False): + # type: (bool) -> Any + if not hasattr(self, Anchor.attrib): + return None + if any or self.anchor.always_dump: + return self.anchor + return None + + def yaml_set_anchor(self, value, always_dump=False): + # type: (Any, bool) -> None + self.anchor.value = value + self.anchor.always_dump = always_dump + def dump(self, out=sys.stdout): # type: (Any) -> Any out.write( - 'ScalarFloat({}| w:{}, p:{}, s:{}, lz:{}|{}, w:{}, s:{})\n'.format( + 'ScalarFloat({}| w:{}, p:{}, s:{}, lz:{}, _:{}|{}, w:{}, s:{})\n'.format( self, self._width, # type: ignore self._prec, # type: ignore self._m_sign, # type: ignore self._m_lead0, # type: ignore + self._underscore, # type: ignore self._exp, # type: ignore self._e_width, # type: ignore self._e_sign, # type: ignore diff --git a/scalarint.py b/scalarint.py index 2bd605d..6842c05 100644 --- a/scalarint.py +++ b/scalarint.py @@ -2,22 +2,26 @@ from __future__ import print_function, absolute_import, division, unicode_literals +from .compat import no_limit_int # NOQA +from ruamel.yaml.anchor import Anchor + if False: # MYPY from typing import Text, Any, Dict, List # NOQA __all__ = ['ScalarInt', 'BinaryInt', 'OctalInt', 'HexInt', 'HexCapsInt'] -from .compat import no_limit_int # NOQA - class ScalarInt(no_limit_int): def __new__(cls, *args, **kw): # type: (Any, Any, Any) -> Any width = kw.pop('width', None) # type: ignore underscore = kw.pop('underscore', None) # type: ignore + anchor = kw.pop('anchor', None) # type: ignore v = no_limit_int.__new__(cls, *args, **kw) # type: ignore v._width = width v._underscore = underscore + if anchor is not None: + v.yaml_set_anchor(anchor, always_dump=True) return v def __iadd__(self, a): # type: ignore @@ -65,17 +69,37 @@ class ScalarInt(no_limit_int): ) # NOQA return x + @property + def anchor(self): + # type: () -> Any + if not hasattr(self, Anchor.attrib): + setattr(self, Anchor.attrib, Anchor()) + return getattr(self, Anchor.attrib) + + def yaml_anchor(self, any=False): + # type: (bool) -> Any + if not hasattr(self, Anchor.attrib): + return None + if any or self.anchor.always_dump: + return self.anchor + return None + + def yaml_set_anchor(self, value, always_dump=False): + # type: (Any, bool) -> None + self.anchor.value = value + self.anchor.always_dump = always_dump + class BinaryInt(ScalarInt): - def __new__(cls, value, width=None, underscore=None): - # type: (Any, Any, Any) -> Any - return ScalarInt.__new__(cls, value, width=width, underscore=underscore) + def __new__(cls, value, width=None, underscore=None, anchor=None): + # type: (Any, Any, Any, Any) -> Any + return ScalarInt.__new__(cls, value, width=width, underscore=underscore, anchor=anchor) class OctalInt(ScalarInt): - def __new__(cls, value, width=None, underscore=None): - # type: (Any, Any, Any) -> Any - return ScalarInt.__new__(cls, value, width=width, underscore=underscore) + def __new__(cls, value, width=None, underscore=None, anchor=None): + # type: (Any, Any, Any, Any) -> Any + return ScalarInt.__new__(cls, value, width=width, underscore=underscore, anchor=anchor) # mixed casing of A-F is not supported, when loading the first non digit @@ -85,14 +109,22 @@ class OctalInt(ScalarInt): class HexInt(ScalarInt): """uses lower case (a-f)""" - def __new__(cls, value, width=None, underscore=None): - # type: (Any, Any, Any) -> Any - return ScalarInt.__new__(cls, value, width=width, underscore=underscore) + def __new__(cls, value, width=None, underscore=None, anchor=None): + # type: (Any, Any, Any, Any) -> Any + return ScalarInt.__new__(cls, value, width=width, underscore=underscore, anchor=anchor) class HexCapsInt(ScalarInt): """uses upper case (A-F)""" - def __new__(cls, value, width=None, underscore=None): - # type: (Any, Any, Any) -> Any - return ScalarInt.__new__(cls, value, width=width, underscore=underscore) + def __new__(cls, value, width=None, underscore=None, anchor=None): + # type: (Any, Any, Any, Any) -> Any + return ScalarInt.__new__(cls, value, width=width, underscore=underscore, anchor=anchor) + + +class DecimalInt(ScalarInt): + """needed if anchor""" + + def __new__(cls, value, width=None, underscore=None, anchor=None): + # type: (Any, Any, Any, Any) -> Any + return ScalarInt.__new__(cls, value, width=width, underscore=underscore, anchor=anchor) diff --git a/scalarstring.py b/scalarstring.py index 0566164..bf3cbab 100644 --- a/scalarstring.py +++ b/scalarstring.py @@ -14,6 +14,7 @@ __all__ = [ 'FoldedScalarString', 'SingleQuotedScalarString', 'DoubleQuotedScalarString', + 'PlainScalarString', # PreservedScalarString is the old name, as it was the first to be preserved on rt, # use LiteralScalarString instead 'PreservedScalarString', @@ -25,7 +26,11 @@ class ScalarString(text_type): def __new__(cls, *args, **kw): # type: (Any, Any) -> Any - return text_type.__new__(cls, *args, **kw) # type: ignore + anchor = kw.pop('anchor', None) # type: ignore + ret_val = text_type.__new__(cls, *args, **kw) # type: ignore + if anchor is not None: + ret_val.yaml_set_anchor(anchor, always_dump=True) + return ret_val def replace(self, old, new, maxreplace=-1): # type: (Any, Any, int) -> Any @@ -38,13 +43,13 @@ class ScalarString(text_type): setattr(self, Anchor.attrib, Anchor()) return getattr(self, Anchor.attrib) - def yaml_anchor(self): - # type: () -> Any + def yaml_anchor(self, any=False): + # type: (bool) -> Any if not hasattr(self, Anchor.attrib): return None - if not self.anchor.always_dump: - return None - return self.anchor + if any or self.anchor.always_dump: + return self.anchor + return None def yaml_set_anchor(self, value, always_dump=False): # type: (Any, bool) -> None @@ -57,9 +62,9 @@ class LiteralScalarString(ScalarString): style = '|' - def __new__(cls, value): - # type: (Text) -> Any - return ScalarString.__new__(cls, value) + def __new__(cls, value, anchor=None): + # type: (Text, Any) -> Any + return ScalarString.__new__(cls, value, anchor=anchor) PreservedScalarString = LiteralScalarString @@ -70,9 +75,9 @@ class FoldedScalarString(ScalarString): style = '>' - def __new__(cls, value): - # type: (Text) -> Any - return ScalarString.__new__(cls, value) + def __new__(cls, value, anchor=None): + # type: (Text, Any) -> Any + return ScalarString.__new__(cls, value, anchor=anchor) class SingleQuotedScalarString(ScalarString): @@ -80,9 +85,9 @@ class SingleQuotedScalarString(ScalarString): style = "'" - def __new__(cls, value): - # type: (Text) -> Any - return ScalarString.__new__(cls, value) + def __new__(cls, value, anchor=None): + # type: (Text, Any) -> Any + return ScalarString.__new__(cls, value, anchor=anchor) class DoubleQuotedScalarString(ScalarString): @@ -90,9 +95,19 @@ class DoubleQuotedScalarString(ScalarString): style = '"' - def __new__(cls, value): - # type: (Text) -> Any - return ScalarString.__new__(cls, value) + def __new__(cls, value, anchor=None): + # type: (Text, Any) -> Any + return ScalarString.__new__(cls, value, anchor=anchor) + + +class PlainScalarString(ScalarString): + __slots__ = () + + style = '' + + def __new__(cls, value, anchor=None): + # type: (Text, Any) -> Any + return ScalarString.__new__(cls, value, anchor=anchor) def preserve_literal(s): -- cgit v1.2.1