summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthon van der Neut <anthon@mnt.org>2023-05-09 19:57:35 +0200
committerAnthon van der Neut <anthon@mnt.org>2023-05-09 19:57:35 +0200
commitaccf77e5f97bd55fe62c67b3cc9bfdaad15dd6f3 (patch)
treec67a1b907c7b97d55dab46268b8b27438cb18bbe
parent31986190f69f68b454260f8c9a04d8697a476d15 (diff)
downloadruamel.yaml-accf77e5f97bd55fe62c67b3cc9bfdaad15dd6f3.tar.gz
fix issue: 4590.17.25
-rw-r--r--CHANGES4
-rw-r--r--README.rst8
-rw-r--r--__init__.py6
-rw-r--r--_doc/_static/pypi.svg2
-rw-r--r--_test/test_issues.py48
-rw-r--r--emitter.py60
6 files changed, 95 insertions, 33 deletions
diff --git a/CHANGES b/CHANGES
index 68f0036..6398bcc 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,7 @@
+[0, 17, 25]: 2023-05-09
+ - fix for regression while dumping wrapped strings with too many backslashes removed
+ (issue 459, reported by `Lele Gaifax <https://sourceforge.net/u/lele/profile/>`__)
+
[0, 17, 24]: 2023-05-06
- rewrite of ``CommentedMap.insert()``. If you have a merge key in
the YAML document for the mapping you insert to, the position value should
diff --git a/README.rst b/README.rst
index 092b63c..81631c7 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.17.24
-:updated: 2023-05-06
+:version: 0.17.25
+:updated: 2023-05-09
:documentation: http://yaml.readthedocs.io
:repository: https://sourceforge.net/projects/ruamel-yaml/
:pypi: https://pypi.org/project/ruamel.yaml/
@@ -61,6 +61,10 @@ ChangeLog
.. should insert NEXT: at the beginning of line for next key (with empty line)
+0.17.25 (2023-05-09):
+ - fix for regression while dumping wrapped strings with too many backslashes removed
+ (issue 459, reported by `Lele Gaifax <https://sourceforge.net/u/lele/profile/>`__)
+
0.17.24 (2023-05-06):
- rewrite of ``CommentedMap.insert()``. If you have a merge key in
the YAML document for the mapping you insert to, the position value should
diff --git a/__init__.py b/__init__.py
index d548852..c676d16 100644
--- a/__init__.py
+++ b/__init__.py
@@ -5,9 +5,9 @@ if False: # MYPY
_package_data = dict(
full_package_name='ruamel.yaml',
- version_info=(0, 17, 24),
- __version__='0.17.24',
- version_timestamp='2023-05-06 12:28:17',
+ version_info=(0, 17, 25),
+ __version__='0.17.25',
+ version_timestamp='2023-05-09 19:56:50',
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 1784380..b5c8870 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.17.24</text><text x="585" y="140" transform="scale(.1)" textLength="430">0.17.24</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.17.25</text><text x="585" y="140" transform="scale(.1)" textLength="430">0.17.25</text></g> </svg>
diff --git a/_test/test_issues.py b/_test/test_issues.py
index eadf94d..f0a7ede 100644
--- a/_test/test_issues.py
+++ b/_test/test_issues.py
@@ -957,7 +957,7 @@ class TestIssues:
def test_issue_447(self) -> None:
from ruamel.yaml import YAML
- YAML().load("{\n\t\"FOO\": \"BAR\"\n}")
+ YAML().load('{\n\t"FOO": "BAR"\n}')
def test_issue_449(self) -> None:
inp = """\
@@ -1039,11 +1039,55 @@ class TestIssues:
yaml = YAML()
out_stream = StringIO()
- in_string = "a" * 128
+ in_string = 'a' * 128
yaml.dump(in_string, out_stream)
result = out_stream.getvalue()
assert in_string == result.splitlines()[0]
+ def test_issue_459(self) -> None:
+ from io import StringIO
+ from ruamel.yaml import YAML
+
+ MYOBJ = {
+ 'data': dedent(
+ """\
+ example: "first"
+ data:
+ - flag: true
+ integer: 1
+ float: 1.0
+ string: "this is a string"
+ list:
+ - first
+ - second
+ - third
+ circle:
+ x: 10cm
+ y: 10cm
+ radius: 2.24cm
+
+ - flag: false
+ integer: 2
+ float: 2.0
+ string: "this is another string"
+ list:
+ - first
+ - second
+ - third
+ circle:
+ x: 20cm
+ y: 20cm
+ radius: 2.24cm
+ """
+ )
+ }
+ yaml = YAML()
+ yaml.width = 60
+ out_stream = StringIO()
+ yaml.dump([MYOBJ], out_stream)
+ data = yaml.load(out_stream.getvalue())
+ assert data[0]['data'] == MYOBJ['data']
+
# @pytest.mark.xfail(strict=True, reason='bla bla', raises=AssertionError)
# def test_issue_ xxx(self) -> None:
diff --git a/emitter.py b/emitter.py
index d927cc0..d882fdc 100644
--- a/emitter.py
+++ b/emitter.py
@@ -1350,7 +1350,7 @@ class Emitter:
self.write_line_break()
if self.requested_indent != 0:
self.write_indent()
- self.write_indicator(u'"', True)
+ self.write_indicator('"', True)
start = end = 0
while end <= len(text):
ch = None
@@ -1358,15 +1358,15 @@ class Emitter:
ch = text[end]
if (
ch is None
- or ch in u'"\\\x85\u2028\u2029\uFEFF'
+ or ch in '"\\\x85\u2028\u2029\uFEFF'
or not (
- u'\x20' <= ch <= u'\x7E'
+ '\x20' <= ch <= '\x7E'
or (
self.allow_unicode
and (
- (u'\xA0' <= ch <= u'\uD7FF')
- or (u'\uE000' <= ch <= u'\uFFFD')
- or (u'\U00010000' <= ch <= u'\U0010FFFF')
+ ('\xA0' <= ch <= '\uD7FF')
+ or ('\uE000' <= ch <= '\uFFFD')
+ or ('\U00010000' <= ch <= '\U0010FFFF')
)
)
)
@@ -1380,13 +1380,13 @@ class Emitter:
start = end
if ch is not None:
if ch in self.ESCAPE_REPLACEMENTS:
- data = u'\\' + self.ESCAPE_REPLACEMENTS[ch]
- elif ch <= u'\xFF':
- data = u'\\x%02X' % ord(ch)
- elif ch <= u'\uFFFF':
- data = u'\\u%04X' % ord(ch)
+ data = '\\' + self.ESCAPE_REPLACEMENTS[ch]
+ elif ch <= '\xFF':
+ data = '\\x%02X' % ord(ch)
+ elif ch <= '\uFFFF':
+ data = '\\u%04X' % ord(ch)
else:
- data = u'\\U%08X' % ord(ch)
+ data = '\\U%08X' % ord(ch)
self.column += len(data)
if bool(self.encoding):
data = data.encode(self.encoding)
@@ -1394,18 +1394,26 @@ class Emitter:
start = end + 1
if (
0 < end < len(text) - 1
- and (ch == u' ' or start >= end)
+ and (ch == ' ' or start >= end)
and self.column + (end - start) > self.best_width
and split
):
# SO https://stackoverflow.com/a/75634614/1307905
# data = text[start:end] + u'\\' # <<< replaced with following six lines
- need_backquote = (
- text[end] == u' '
- and (len(text) > end)
- and text[end + 1] == u' '
- )
- data = text[start:end] + (u'\\' if need_backquote else u'')
+ need_backquote = True
+ if len(text) > end:
+ space_pos = text.index(' ', end)
+ try:
+ if (
+ '"' not in text[end:space_pos]
+ and "'" not in text[end:space_pos]
+ and text[space_pos + 1] != ' '
+ and text[end - 1 : end + 1] != ' '
+ ):
+ need_backquote = False
+ except IndexError:
+ pass
+ data = text[start:end] + ('\\' if need_backquote else '')
if start < end:
start = end
self.column += len(data)
@@ -1415,18 +1423,18 @@ class Emitter:
self.write_indent()
self.whitespace = False
self.indention = False
- if text[start] == u' ':
+ if text[start] == ' ':
if not need_backquote:
# remove leading space it will load from the newline
start += 1
# data = u'\\' # <<< replaced with following line
- data = u'\\' if need_backquote else u''
+ data = '\\' if need_backquote else ''
self.column += len(data)
if bool(self.encoding):
data = data.encode(self.encoding)
self.stream.write(data)
end += 1
- self.write_indicator(u'"', False)
+ self.write_indicator('"', False)
def determine_block_hints(self, text: Any) -> Any:
indent = 0
@@ -1634,9 +1642,11 @@ class Emitter:
else:
if ch is None or ch in ' \n\x85\u2028\u2029':
data = text[start:end]
- if (len(data) > self.best_width
- and self.indent is not None
- and self.column > self.indent):
+ if (
+ len(data) > self.best_width
+ and self.indent is not None
+ and self.column > self.indent
+ ):
# words longer than line length get a line of their own
self.write_indent()
self.column += len(data)