From a29127076c536d0009b2556a4a2081e8cad83032 Mon Sep 17 00:00:00 2001 From: Anthon van der Neut Date: Sun, 13 Aug 2017 13:16:06 +0200 Subject: fix issue #62: not allowing : or ? in flow style plain scalar also fix list withing list comment dropping, as it happened to occur in the example --- CHANGES | 5 +++++ README.rst | 5 +++++ __init__.py | 4 ++-- _test/test_version.py | 45 ++++++++++++++++++++++++++++++++++++++++++++- comments.py | 5 +++-- emitter.py | 19 ++++++++++++++++--- representer.py | 2 +- 7 files changed, 76 insertions(+), 9 deletions(-) diff --git a/CHANGES b/CHANGES index 14be90a..e9f85a7 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,8 @@ +[0, 15, 27]: 2017-08-13 + - fix issue 62, YAML 1.2 allows ``?`` and ``:`` in plain scalars if non-ambigious + (reported by nowox) + - fix lists within lists which would make comments disappear + [0, 15, 26]: 2017-08-10 - fix for disappearing comment after empty flow sequence (reported by oit-tzhimmash) diff --git a/README.rst b/README.rst index 9b08480..1eed1e0 100644 --- a/README.rst +++ b/README.rst @@ -35,6 +35,11 @@ ChangeLog .. should insert NEXT: at the beginning of line for next key +0.15.27 (2017-08-13): + - fix issue 62, YAML 1.2 allows ``?`` and ``:`` in plain scalars if non-ambigious + (reported by nowox) + - fix lists within lists which would make comments disappear + 0.15.26 (2017-08-10): - fix for disappearing comment after empty flow sequence (reported by oit-tzhimmash) diff --git a/__init__.py b/__init__.py index fab4d83..ba870c9 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, 26), - __version__='0.15.26', + version_info=(0, 15, 27), + __version__='0.15.27', 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_version.py b/_test/test_version.py index a0bdb29..795c242 100644 --- a/_test/test_version.py +++ b/_test/test_version.py @@ -3,7 +3,7 @@ import pytest # NOQA import ruamel.yaml -from roundtrip import dedent +from roundtrip import dedent, round_trip def load(s, version=None): @@ -106,3 +106,46 @@ class TestVersions: assert l[7] is True assert l[8] is False assert l[9] is True + + +class TestIssue62: + # bitbucket issue 62, issue_62 + def test_00(self): + s = dedent("""\ + {}# Outside flow collection: + - ::vector + - ": - ()" + - Up, up, and away! + - -123 + - http://example.com/foo#bar + # Inside flow collection: + - [::vector, ": - ()", "Down, down and away!", -456, http://example.com/foo#bar] + """) + with pytest.raises(ruamel.yaml.parser.ParserError): + round_trip(s.format('%YAML 1.1\n---\n'), preserve_quotes=True) + round_trip(s.format(''), preserve_quotes=True) + + def test_00_single_comment(self): + s = dedent("""\ + {}# Outside flow collection: + - ::vector + - ": - ()" + - Up, up, and away! + - -123 + - http://example.com/foo#bar + - [::vector, ": - ()", "Down, down and away!", -456, http://example.com/foo#bar] + """) + with pytest.raises(ruamel.yaml.parser.ParserError): + round_trip(s.format('%YAML 1.1\n---\n'), preserve_quotes=True) + round_trip(s.format(''), preserve_quotes=True) + # round_trip(s.format('%YAML 1.2\n---\n'), preserve_quotes=True, version=(1, 2)) + + def test_01(self): + s = dedent("""\ + {}[random plain value that contains a ? character] + """) + with pytest.raises(ruamel.yaml.parser.ParserError): + round_trip(s.format('%YAML 1.1\n---\n'), preserve_quotes=True) + round_trip(s.format(''), preserve_quotes=True) + # note the flow seq on the --- line! + round_trip(s.format('%YAML 1.2\n--- '), preserve_quotes=True, version="1.2") diff --git a/comments.py b/comments.py index 6cde817..9c65cf2 100644 --- a/comments.py +++ b/comments.py @@ -942,6 +942,7 @@ class CommentedSet(MutableSet, CommentedMap): def dump_comments(d, name='', sep='.', out=sys.stdout): + # type: (Any, str, str, Any) -> None """ recurisively dump domments all but the toplevel preceded by the path in dotted form x.0.a @@ -949,13 +950,13 @@ def dump_comments(d, name='', sep='.', out=sys.stdout): if isinstance(d, dict): if name: print(name) - print(d.ca, file=out) + print(d.ca, file=out) # type: ignore for k in d: dump_comments(d[k], name=(name + sep + k) if name else k, sep=sep, out=out) elif isinstance(d, list): if name: print(name) - print(d.ca, file=out) + print(d.ca, file=out) # type: ignore for idx, k in enumerate(d): dump_comments(k, name=(name + sep + str(idx)) if name else str(idx), sep=sep, out=out) diff --git a/emitter.py b/emitter.py index 52a5c82..09d3419 100644 --- a/emitter.py +++ b/emitter.py @@ -152,6 +152,16 @@ class Emitter(object): raise YAMLStreamError('stream argument needs to have a write() method') self._stream = val + @property + def serializer(self): + # type: () -> Any + try: + if hasattr(self.dumper, 'typ'): + return self.dumper.serializer # type: ignore + return self.dumper._serializer # type: ignore + except AttributeError: + return self # cyaml + def dispose(self): # type: () -> None # Reset the state attributes (to clear self-references) @@ -850,8 +860,9 @@ class Emitter(object): if ch in u'#,[]{}&*!|>\'\"%@`': flow_indicators = True block_indicators = True - if ch in u'?:': - flow_indicators = True + if ch in u'?:': # ToDo + if self.serializer.use_version == (1, 1): + flow_indicators = True if followed_by_whitespace: block_indicators = True if ch == u'-' and followed_by_whitespace: @@ -859,7 +870,9 @@ class Emitter(object): block_indicators = True else: # Some indicators cannot appear within a scalar as well. - if ch in u',?[]{}': + if ch in u',[]{}': # http://yaml.org/spec/1.2/spec.html#id2788859 + flow_indicators = True + if ch == u'?' and self.serializer.use_version == (1, 1): flow_indicators = True if ch == u':': if followed_by_whitespace: diff --git a/representer.py b/representer.py index 7468060..5380813 100644 --- a/representer.py +++ b/representer.py @@ -309,7 +309,7 @@ class SafeRepresenter(BaseRepresenter): value = u'-.inf' else: value = to_unicode(repr(data)).lower() - if self.serializer.use_version == (1, 1): # type: ignore + if self.serializer.use_version == (1, 1): if u'.' not in value and u'e' in value: # Note that in some cases `repr(data)` represents a float number # without the decimal parts. For instance: -- cgit v1.2.1