diff options
author | Anthon van der Neut <anthon@mnt.org> | 2016-11-28 18:02:34 +0100 |
---|---|---|
committer | Anthon van der Neut <anthon@mnt.org> | 2016-11-28 18:02:34 +0100 |
commit | 786fc2f80aa5c2d626674c7c9125c4c3be874af6 (patch) | |
tree | eedc7a090bcecc52ce4925cc76af8f1090792c9f | |
parent | 0ab4dd3ca904554aecc272d707ce1946a56a50d4 (diff) | |
download | ruamel.yaml-786fc2f80aa5c2d626674c7c9125c4c3be874af6.tar.gz |
addresses #25 comment after empty (null) values0.13.2
can remove comment between key en value
-rw-r--r-- | README.rst | 3 | ||||
-rw-r--r-- | __init__.py | 2 | ||||
-rw-r--r-- | _test/test_comments.py | 32 | ||||
-rw-r--r-- | _test/test_numpy.py | 2 | ||||
-rw-r--r-- | comments.py | 4 | ||||
-rw-r--r-- | constructor.py | 14 | ||||
-rw-r--r-- | parser.py | 12 | ||||
-rw-r--r-- | tokens.py | 8 |
8 files changed, 69 insertions, 8 deletions
@@ -18,6 +18,9 @@ ChangeLog .. should insert NEXT: at the beginning of line for next key +0.13.2 (2016-11-28): + - fix for comments after empty (null) values (reported by dsw2127 and cokelaer) + 0.13.1 (2016-11-22): - optimisations on memory usage when loading YAML from large files (py3: -50%, py2: -85%) diff --git a/__init__.py b/__init__.py index 006f948..24189c4 100644 --- a/__init__.py +++ b/__init__.py @@ -9,7 +9,7 @@ from __future__ import absolute_import _package_data = dict( full_package_name="ruamel.yaml", - version_info=(0, 13, 1), + version_info=(0, 13, 2), 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/_test/test_comments.py b/_test/test_comments.py index f2aa1f0..019d8b7 100644 --- a/_test/test_comments.py +++ b/_test/test_comments.py @@ -659,3 +659,35 @@ class TestUnicodeComments: - :no: 05273867 # 〇 - :no: 05205786 # 〇𤦌 """) + + +class TestEmptyValueBeforeComments: + @pytest.mark.xfail(strict=True) + def test_issue_25a(self): + round_trip("""\ + - a: b + c: d + d: # foo + - e: f + """) + + def test_issue_25b(self): + round_trip("""\ + var1: #empty + var2: something #notempty + """) + + def test_issue_25c(self): + round_trip("""\ + params: + a: 1 # comment a + b: # comment b + c: 3 # comment c + """) + + def test_issue_25_00(self): + round_trip("""\ + params: + a: 1 # comment a + b: # comment b + """) diff --git a/_test/test_numpy.py b/_test/test_numpy.py index deec7a2..1a6eabb 100644 --- a/_test/test_numpy.py +++ b/_test/test_numpy.py @@ -10,7 +10,7 @@ except: import ruamel.yaml -def test_numpy(): +def Xtest_numpy(): if numpy is None: return data = numpy.arange(10) diff --git a/comments.py b/comments.py index 2fa66e6..dc56594 100644 --- a/comments.py +++ b/comments.py @@ -158,7 +158,9 @@ class CommentedBase(object): return getattr(self, Comment.attrib) def yaml_end_comment_extend(self, comment, clear=False): - if clear: + if comment is None: + return + if clear or self.ca.end is None: self.ca.end = [] self.ca.end.extend(comment) diff --git a/constructor.py b/constructor.py index 03c88ae..682e95a 100644 --- a/constructor.py +++ b/constructor.py @@ -934,6 +934,9 @@ class RoundTripConstructor(SafeConstructor): # if merge: # node.value = merge + node.value + def _sentinel(self): + pass + def construct_mapping(self, node, maptyp, deep=False): if not isinstance(node, MappingNode): raise ConstructorError( @@ -950,6 +953,7 @@ class RoundTripConstructor(SafeConstructor): from ruamel.yaml.serializer import templated_id if not templated_id(node.anchor): maptyp.yaml_set_anchor(node.anchor) + last_key, last_value = None, self._sentinel for key_node, value_node in node.value: # keys can be list -> deep key = self.construct_object(key_node, deep=True) @@ -976,6 +980,15 @@ class RoundTripConstructor(SafeConstructor): "while constructing a mapping", node.start_mark, "found unhashable key", key_node.start_mark) value = self.construct_object(value_node, deep=deep) + if key_node.comment and len(key_node.comment) > 4 and \ + key_node.comment[4]: + if last_value is None: + key_node.comment[0] = key_node.comment.pop(4) + maptyp._yaml_add_comment(key_node.comment, value=last_key) + else: + key_node.comment[2] = key_node.comment.pop(4) + maptyp._yaml_add_comment(key_node.comment, key=key) + key_node.comment = None if key_node.comment: maptyp._yaml_add_comment(key_node.comment, key=key) if value_node.comment: @@ -984,6 +997,7 @@ class RoundTripConstructor(SafeConstructor): key, [key_node.start_mark.line, key_node.start_mark.column, value_node.start_mark.line, value_node.start_mark.column]) maptyp[key] = value + last_key, last_value = key, value # could use indexing # do this last, or <<: before a key will prevent insertion in instances # of collections.OrderedDict (as they have no __contains__ if merge_map: @@ -515,13 +515,17 @@ class Parser(object): if self.check_token(ValueToken): token = self.get_token() # value token might have post comment move it to e.g. block - token.move_comment(self.peek_token()) + if self.check_token(ValueToken): + token.move_comment(self.peek_token()) + else: + token.move_comment(self.peek_token(), empty=True) if not self.check_token(KeyToken, ValueToken, BlockEndToken): self.states.append(self.parse_block_mapping_key) return self.parse_block_node_or_indentless_sequence() else: self.state = self.parse_block_mapping_key - return self.process_empty_scalar(token.end_mark) + return self.process_empty_scalar(token.end_mark, + comment=self.peek_token().comment) else: self.state = self.parse_block_mapping_key token = self.peek_token() @@ -660,8 +664,8 @@ class Parser(object): self.state = self.parse_flow_mapping_key return self.process_empty_scalar(self.peek_token().start_mark) - def process_empty_scalar(self, mark): - return ScalarEvent(None, None, (True, False), u'', mark, mark) + def process_empty_scalar(self, mark, comment=None): + return ScalarEvent(None, None, (True, False), u'', mark, mark, comment=comment) class RoundTripParser(Parser): @@ -35,10 +35,11 @@ class Token(object): def comment(self): return getattr(self, '_comment', None) - def move_comment(self, target): + def move_comment(self, target, empty=False): """move a comment from this token to target (normally next token) used to combine e.g. comments before a BlockEntryToken to the ScalarToken that follows it + empty is a special for empty values -> comment after key """ c = self.comment if c is None: @@ -46,9 +47,14 @@ class Token(object): # don't push beyond last element if isinstance(target, StreamEndToken): return + if isinstance(self, ValueToken) and isinstance(target, BlockEntryToken): + return delattr(self, '_comment') tc = target.comment if not tc: # target comment, just insert + # special for empty value in key: value issue 25 + if empty: + c = [c[0], c[1], None, None, c[0]] target._comment = c return self if c[0] and tc[0] or c[1] and tc[1]: |