summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES7
-rw-r--r--README.rst19
-rw-r--r--__init__.py4
-rw-r--r--_doc/_static/pypi.svg2
-rw-r--r--comments.py6
-rw-r--r--constructor.py22
-rw-r--r--emitter.py9
-rw-r--r--representer.py23
-rw-r--r--scalarbool.py51
9 files changed, 119 insertions, 24 deletions
diff --git a/CHANGES b/CHANGES
index b10d621..84248bb 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,10 @@
+[0, 15, 82]: 2018-12-28
+ - anchors and aliases on scalar int, float, string and bool are now preserved. Anchors
+ do not need a referring alias for these (reported by
+ `Alex Harvey <https://bitbucket.org/alexharv074/>`__)
+ - anchors no longer lost on tagged objects when roundtripping (reported by `Zaloo
+ <https://bitbucket.org/zaloo/>`__)
+
[0, 15, 81]: 2018-12-06
- fix issue saving methods of metaclass derived classes (reported and fix provided
by `Douglas Raillard <https://bitbucket.org/DouglasRaillard/>`__)
diff --git a/README.rst b/README.rst
index d59281f..e651606 100644
--- a/README.rst
+++ b/README.rst
@@ -4,8 +4,8 @@ ruamel.yaml
``ruamel.yaml`` is a YAML 1.2 loader/dumper package for Python.
-:version: 0.15.81
-:updated: 2018-12-06
+:version: 0.15.82
+:updated: 2018-12-28
:documentation: http://yaml.readthedocs.io
:repository: https://bitbucket.org/ruamel/
:pypi: https://pypi.org/project/ruamel.yaml/
@@ -54,13 +54,20 @@ ChangeLog
.. should insert NEXT: at the beginning of line for next key (with empty line)
+0.15.82 (2018-12-28):
+ - anchors and aliases on scalar int, float, string and bool are now preserved. Anchors
+ do not need a referring alias for these (reported by
+ `Alex Harvey <https://bitbucket.org/alexharv074/>`__)
+ - anchors no longer lost on tagged objects when roundtripping (reported by `Zaloo
+ <https://bitbucket.org/zaloo/>`__)
+
0.15.81 (2018-12-06):
- - fix issue dumping methods of metaclass derived classes (reported and fix provided
- by `Douglas Raillard <https://bitbucket.org/DouglasRaillard/>`__)
+ - fix issue dumping methods of metaclass derived classes (reported and fix provided
+ by `Douglas Raillard <https://bitbucket.org/DouglasRaillard/>`__)
0.15.80 (2018-11-26):
- - fix issue emitting BEL character when round-tripping invalid folded input
- (reported by Isaac on `StackOverflow <https://stackoverflow.com/a/53471217/1307905>`__)
+ - fix issue emitting BEL character when round-tripping invalid folded input
+ (reported by Isaac on `StackOverflow <https://stackoverflow.com/a/53471217/1307905>`__)
0.15.79 (2018-11-21):
- fix issue with anchors nested deeper than alias (reported by gaFF on
diff --git a/__init__.py b/__init__.py
index c0c019a..1ef43d8 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, 82, 'dev'),
- __version__='0.15.82.dev',
+ version_info=(0, 15, 82),
+ __version__='0.15.82',
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/_doc/_static/pypi.svg b/_doc/_static/pypi.svg
index 62a44e9..a98af9d 100644
--- a/_doc/_static/pypi.svg
+++ b/_doc/_static/pypi.svg
@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="86" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="86" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h33v20H0z"/><path fill="#007ec6" d="M33 0h53v20H33z"/><path fill="url(#b)" d="M0 0h86v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"> <text x="175" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="230">pypi</text><text x="175" y="140" transform="scale(.1)" textLength="230">pypi</text><text x="585" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="430">0.15.81</text><text x="585" y="140" transform="scale(.1)" textLength="430">0.15.81</text></g> </svg>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="86" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="86" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h33v20H0z"/><path fill="#007ec6" d="M33 0h53v20H33z"/><path fill="url(#b)" d="M0 0h86v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"> <text x="175" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="230">pypi</text><text x="175" y="140" transform="scale(.1)" textLength="230">pypi</text><text x="585" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="430">0.15.82</text><text x="585" y="140" transform="scale(.1)" textLength="430">0.15.82</text></g> </svg>
diff --git a/comments.py b/comments.py
index b76f909..1460a56 100644
--- a/comments.py
+++ b/comments.py
@@ -17,9 +17,9 @@ from ruamel.yaml.scalarstring import ScalarString
from ruamel.yaml.anchor import Anchor
if PY2:
- from collections import MutableSet, Sized, Set, MutableMapping, Mapping
+ from collections import MutableSet, Sized, Set, Mapping
else:
- from collections.abc import MutableSet, Sized, Set, MutableMapping, Mapping
+ from collections.abc import MutableSet, Sized, Set, Mapping
if False: # MYPY
from typing import Any, Dict, Optional, List, Union, Optional, Iterator # NOQA
@@ -1052,7 +1052,7 @@ class CommentedOrderedMap(CommentedMap):
__slots__ = (Comment.attrib,)
-class CommentedSet(MutableSet, CommentedBase): # type: ignore # NOQA
+class CommentedSet(MutableSet, CommentedBase): # type: ignore # NOQA
__slots__ = Comment.attrib, 'odict'
def __init__(self, values=None):
diff --git a/constructor.py b/constructor.py
index 61ac4e9..65d6829 100644
--- a/constructor.py
+++ b/constructor.py
@@ -27,6 +27,7 @@ from ruamel.yaml.scalarstring import (SingleQuotedScalarString, DoubleQuotedScal
PlainScalarString, ScalarString,)
from ruamel.yaml.scalarint import ScalarInt, BinaryInt, OctalInt, HexInt, HexCapsInt
from ruamel.yaml.scalarfloat import ScalarFloat
+from ruamel.yaml.scalarbool import ScalarBoolean
from ruamel.yaml.timestamp import TimeStamp
from ruamel.yaml.util import RegExp
@@ -1163,9 +1164,7 @@ class RoundTripConstructor(SafeConstructor):
if underscore is not None:
# cannot have a leading underscore
underscore[2] = len(value_su) > 1 and value_su[-1] == '_'
- return ScalarInt(
- sign * int(value_s), width=len(value_s), underscore=underscore
- )
+ return ScalarInt(sign * int(value_s), width=len(value_s), underscore=underscore)
elif underscore:
# cannot have a leading underscore
underscore[2] = len(value_su) > 1 and value_su[-1] == '_'
@@ -1173,9 +1172,7 @@ class RoundTripConstructor(SafeConstructor):
sign * int(value_s), width=None, underscore=underscore, anchor=node.anchor
)
elif node.anchor:
- return ScalarInt(
- sign * int(value_s), width=None, anchor=node.anchor
- )
+ return ScalarInt(sign * int(value_s), width=None, anchor=node.anchor)
else:
return sign * int(value_s)
@@ -1623,6 +1620,8 @@ class RoundTripConstructor(SafeConstructor):
data.fa.set_block_style()
data.yaml_set_tag(node.tag)
yield data
+ if node.anchor:
+ data.yaml_set_anchor(node.anchor)
self.construct_mapping(node, data)
return
elif isinstance(node, ScalarNode):
@@ -1631,6 +1630,8 @@ class RoundTripConstructor(SafeConstructor):
data2.style = node.style
data2.yaml_set_tag(node.tag)
yield data2
+ if node.anchor:
+ data2.yaml_set_anchor(node.anchor, always_dump=True)
return
elif isinstance(node, SequenceNode):
data3 = CommentedSeq()
@@ -1641,6 +1642,8 @@ class RoundTripConstructor(SafeConstructor):
data3.fa.set_block_style()
data3.yaml_set_tag(node.tag)
yield data3
+ if node.anchor:
+ data3.yaml_set_anchor(node.anchor)
data3.extend(self.construct_sequence(node))
return
except: # NOQA
@@ -1713,6 +1716,13 @@ class RoundTripConstructor(SafeConstructor):
data._yaml['t'] = True
return data
+ def construct_yaml_bool(self, node):
+ # type: (Any) -> Any
+ b = SafeConstructor.construct_yaml_bool(self, node)
+ if node.anchor:
+ return ScalarBoolean(b, anchor=node.anchor)
+ return b
+
RoundTripConstructor.add_constructor(
u'tag:yaml.org,2002:null', RoundTripConstructor.construct_yaml_null
diff --git a/emitter.py b/emitter.py
index 7829219..d4c51f9 100644
--- a/emitter.py
+++ b/emitter.py
@@ -402,8 +402,12 @@ class Emitter(object):
if isinstance(self.event, AliasEvent):
self.expect_alias()
elif isinstance(self.event, (ScalarEvent, CollectionStartEvent)):
- if self.process_anchor(u'&') and isinstance(self.event, ScalarEvent):
- self.no_newline = True
+ if (
+ self.process_anchor(u'&')
+ and isinstance(self.event, ScalarEvent)
+ and self.sequence_context
+ ):
+ self.sequence_context = False
self.process_tag()
if isinstance(self.event, ScalarEvent):
# nprint('@', self.indention, self.no_newline, self.column)
@@ -848,6 +852,7 @@ class Emitter(object):
# if self.analysis.multiline and split \
# and (not self.style or self.style in '\'\"'):
# self.write_indent()
+ # nprint('xx', self.sequence_context, self.flow_level)
if self.sequence_context and not self.flow_level:
self.write_indent()
if self.style == '"':
diff --git a/representer.py b/representer.py
index 923b2a2..ced41a0 100644
--- a/representer.py
+++ b/representer.py
@@ -16,6 +16,7 @@ from ruamel.yaml.scalarstring import (
)
from ruamel.yaml.scalarint import ScalarInt, BinaryInt, OctalInt, HexInt, HexCapsInt
from ruamel.yaml.scalarfloat import ScalarFloat
+from ruamel.yaml.scalarbool import ScalarBoolean
from ruamel.yaml.timestamp import TimeStamp
import datetime
@@ -289,8 +290,8 @@ class SafeRepresenter(BaseRepresenter):
# type: (Any) -> Any
return self.represent_scalar(u'tag:yaml.org,2002:str', data)
- def represent_bool(self, data):
- # type: (Any) -> Any
+ def represent_bool(self, data, anchor=None):
+ # type: (Any, Optional[Any]) -> Any
try:
value = self.dumper.boolean_representation[bool(data)]
except AttributeError:
@@ -298,7 +299,7 @@ class SafeRepresenter(BaseRepresenter):
value = u'true'
else:
value = u'false'
- return self.represent_scalar(u'tag:yaml.org,2002:bool', value)
+ return self.represent_scalar(u'tag:yaml.org,2002:bool', value, anchor=anchor)
def represent_int(self, data):
# type: (Any) -> Any
@@ -1200,7 +1201,19 @@ class RoundTripRepresenter(SafeRepresenter):
tag = data.tag.value
except AttributeError:
tag = None
- return self.represent_scalar(tag, data.value, style=data.style)
+ try:
+ anchor = data.yaml_anchor()
+ except AttributeError:
+ anchor = None
+ return self.represent_scalar(tag, data.value, style=data.style, anchor=anchor)
+
+ def represent_scalar_bool(self, data):
+ # type: (Any) -> Any
+ try:
+ anchor = data.yaml_anchor()
+ except AttributeError:
+ anchor = None
+ return SafeRepresenter.represent_bool(self, data, anchor=anchor)
RoundTripRepresenter.add_representer(type(None), RoundTripRepresenter.represent_none)
@@ -1237,6 +1250,8 @@ RoundTripRepresenter.add_representer(HexCapsInt, RoundTripRepresenter.represent_
RoundTripRepresenter.add_representer(ScalarFloat, RoundTripRepresenter.represent_scalar_float)
+RoundTripRepresenter.add_representer(ScalarBoolean, RoundTripRepresenter.represent_scalar_bool)
+
RoundTripRepresenter.add_representer(CommentedSeq, RoundTripRepresenter.represent_list)
RoundTripRepresenter.add_representer(CommentedMap, RoundTripRepresenter.represent_dict)
diff --git a/scalarbool.py b/scalarbool.py
new file mode 100644
index 0000000..fc8f8c2
--- /dev/null
+++ b/scalarbool.py
@@ -0,0 +1,51 @@
+# coding: utf-8
+
+from __future__ import print_function, absolute_import, division, unicode_literals
+
+"""
+You cannot subclass bool, and this is necessary for round-tripping anchored
+bool values (and also if you want to preserve the original way of writing)
+
+bool.__bases__ is type 'int', so that is what is used as the basis for ScalarBoolean as well.
+
+You can use these in an if statement, but not when testing equivalence
+"""
+
+from ruamel.yaml.anchor import Anchor
+
+if False: # MYPY
+ from typing import Text, Any, Dict, List # NOQA
+
+__all__ = ['ScalarBoolean']
+
+# no need for no_limit_int -> int
+
+
+class ScalarBoolean(int):
+ def __new__(cls, *args, **kw):
+ # type: (Any, Any, Any) -> Any
+ anchor = kw.pop('anchor', None) # type: ignore
+ b = int.__new__(cls, *args, **kw) # type: ignore
+ if anchor is not None:
+ b.yaml_set_anchor(anchor, always_dump=True)
+ return b
+
+ @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