diff options
author | Anthon van der Neut <anthon@mnt.org> | 2023-05-05 20:08:37 +0200 |
---|---|---|
committer | Anthon van der Neut <anthon@mnt.org> | 2023-05-05 20:08:37 +0200 |
commit | a6a96c99a78cdc34e291af8d7d2d17fd1bf42a42 (patch) | |
tree | 99c4e94587427d628bb5679a8ee85b8c2487bf01 | |
parent | 199f4f52fa9c1700de3b4d3709de81c34b7402a4 (diff) | |
download | ruamel.yaml-a6a96c99a78cdc34e291af8d7d2d17fd1bf42a42.tar.gz |
fixes issue: 458,454, stackoverflow reports
38 files changed, 406 insertions, 203 deletions
@@ -1,3 +1,16 @@ +[0, 17, 23]: 2023-05-05 + - fix 458, error on plain scalars starting with word longer than width. + (reported by `Kyle Larose <https://sourceforge.net/u/klarose/profile/>`__) + - fix for ``.update()`` no longer correctly handling keyword arguments + (reported by John Lin on <StackOverflow + `<https://stackoverflow.com/q/76089100/1307905>`__) + - fix issue 454: high Unicode (emojis) in quoted strings always + escaped (reported by `Michal Čihař <https://sourceforge.net/u/nijel/profile/>`__ + based on a question on StackOverflow). + - fix issue with emitter conservatively inserting extra backslashes in wrapped + quoted strings (reported by thebenman on `StackOverflow + <https://stackoverflow.com/q/75631454/1307905>`__) + [0, 17, 22]: 2023-05-02 - fix issue 449 where the second exclamation marks got URL encoded (reported @@ -4,8 +4,8 @@ ruamel.yaml ``ruamel.yaml`` is a YAML 1.2 loader/dumper package for Python. -:version: 0.17.22 -:updated: 2023-05-02 +:version: 0.17.23 +:updated: 2023-05-05 :documentation: http://yaml.readthedocs.io :repository: https://sourceforge.net/projects/ruamel-yaml/ :pypi: https://pypi.org/project/ruamel.yaml/ @@ -61,6 +61,19 @@ ChangeLog .. should insert NEXT: at the beginning of line for next key (with empty line) +0.17.23 (2023-05-05): + - fix 458, error on plain scalars starting with word longer than width. + (reported by `Kyle Larose <https://sourceforge.net/u/klarose/profile/>`__) + - fix for ``.update()`` no longer correctly handling keyword arguments + (reported by John Lin on <StackOverflow + `<https://stackoverflow.com/q/76089100/1307905>`__) + - fix issue 454: high Unicode (emojis) in quoted strings always + escaped (reported by `Michal Čihař <https://sourceforge.net/u/nijel/profile/>`__ + based on a question on StackOverflow). + - fix issue with emitter conservatively inserting extra backslashes in wrapped + quoted strings (reported by thebenman on `StackOverflow + <https://stackoverflow.com/q/75631454/1307905>`__) + 0.17.22 (2023-05-02): - fix issue 449 where the second exclamation marks got URL encoded (reported diff --git a/__init__.py b/__init__.py index 3a7b355..61552f0 100644 --- a/__init__.py +++ b/__init__.py @@ -5,16 +5,16 @@ if False: # MYPY _package_data = dict( full_package_name='ruamel.yaml', - version_info=(0, 17, 22), - __version__='0.17.22', - version_timestamp='2023-05-02 08:06:59', + version_info=(0, 17, 23), + __version__='0.17.23', + version_timestamp='2023-05-05 20:08:10', 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 entry_points=None, since=2014, extras_require={ - ':platform_python_implementation=="CPython" and python_version<"3.11"': ['ruamel.yaml.clib>=0.2.6'], # NOQA + ':platform_python_implementation=="CPython" and python_version<"3.12"': ['ruamel.yaml.clib>=0.2.7'], # NOQA 'jinja2': ['ruamel.yaml.jinja2>=0.2'], 'docs': ['ryd'], }, diff --git a/_doc/_static/pypi.svg b/_doc/_static/pypi.svg index 9197e4e..32bd51f 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.22</text><text x="585" y="140" transform="scale(.1)" textLength="430">0.17.22</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.23</text><text x="585" y="140" transform="scale(.1)" textLength="430">0.17.23</text></g> </svg> diff --git a/_test/test_a_dedent.py b/_test/test_a_dedent.py index e13a54b..569171c 100644 --- a/_test/test_a_dedent.py +++ b/_test/test_a_dedent.py @@ -1,6 +1,6 @@ # coding: utf-8 -from roundtrip import dedent +from roundtrip import dedent # type: ignore class TestDedent: diff --git a/_test/test_add_xxx.py b/_test/test_add_xxx.py index 5f12ece..32859c2 100644 --- a/_test/test_add_xxx.py +++ b/_test/test_add_xxx.py @@ -3,7 +3,7 @@ import re import pytest # type: ignore # NOQA -from roundtrip import dedent, round_trip_dump # NOQA +from roundtrip import dedent, round_trip_dump # type: ignore # NOQA from typing import Any diff --git a/_test/test_anchor.py b/_test/test_anchor.py index da0f1ef..bab41fd 100644 --- a/_test/test_anchor.py +++ b/_test/test_anchor.py @@ -7,7 +7,7 @@ testing of anchors and the aliases referring to them import pytest # type: ignore # NOQA import platform -from roundtrip import round_trip, dedent, round_trip_load, round_trip_dump, YAML # NOQA +from roundtrip import round_trip, dedent, round_trip_load, round_trip_dump, YAML # type: ignore # NOQA from typing import Any @@ -332,7 +332,7 @@ class TestMergeKeysValues: # in the following d always has "expanded" the merges def test_merge_for(self) -> None: - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML d = YAML(typ='safe', pure=True).load(self.yaml_str) data = round_trip_load(self.yaml_str) @@ -343,7 +343,7 @@ class TestMergeKeysValues: assert count == len(d[2]) def test_merge_keys(self) -> None: - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML d = YAML(typ='safe', pure=True).load(self.yaml_str) data = round_trip_load(self.yaml_str) @@ -354,7 +354,7 @@ class TestMergeKeysValues: assert count == len(d[2]) def test_merge_values(self) -> None: - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML d = YAML(typ='safe', pure=True).load(self.yaml_str) data = round_trip_load(self.yaml_str) @@ -365,7 +365,7 @@ class TestMergeKeysValues: assert count == len(d[2]) def test_merge_items(self) -> None: - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML d = YAML(typ='safe', pure=True).load(self.yaml_str) data = round_trip_load(self.yaml_str) @@ -376,7 +376,7 @@ class TestMergeKeysValues: assert count == len(d[2]) def test_len_items_delete(self) -> None: - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML d = YAML(typ='safe', pure=True).load(self.yaml_str) data = round_trip_load(self.yaml_str) @@ -396,7 +396,7 @@ class TestMergeKeysValues: assert len(x) == ref def test_issue_196_cast_of_dict(self, capsys: Any) -> None: - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML yaml = YAML() mapping = yaml.load("""\ @@ -434,14 +434,14 @@ class TestMergeKeysValues: assert 'a' in dict(mapping.items()) def test_values_of_merged(self) -> None: - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML yaml = YAML() data = yaml.load(dedent(self.yaml_str)) assert list(data[2].values()) == [1, 6, 'x2', 'x3', 'y4'] def test_issue_213_copy_of_merge(self) -> None: - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML yaml = YAML() d = yaml.load("""\ @@ -463,7 +463,7 @@ class TestMergeKeysValues: class TestDuplicateKeyThroughAnchor: def test_duplicate_key_00(self) -> None: from ruamel.yaml import version_info - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML from ruamel.yaml.constructor import DuplicateKeyFutureWarning, DuplicateKeyError s = dedent("""\ diff --git a/_test/test_class_register.py b/_test/test_class_register.py index fdd0275..39be660 100644 --- a/_test/test_class_register.py +++ b/_test/test_class_register.py @@ -7,7 +7,7 @@ testing of YAML.register_class and @yaml_object from typing import Any from ruamel.yaml.comments import TaggedScalar, CommentedMap # NOQA -from roundtrip import YAML +from roundtrip import YAML # type: ignore class User0: diff --git a/_test/test_collections.py b/_test/test_collections.py index d6e88ef..cee1ab3 100644 --- a/_test/test_collections.py +++ b/_test/test_collections.py @@ -10,7 +10,7 @@ This is now so integrated in Python that it can be mapped to !!omap import pytest # type: ignore # NOQA -from roundtrip import round_trip, dedent, round_trip_load, round_trip_dump # NOQA +from roundtrip import round_trip, dedent, round_trip_load, round_trip_dump # type: ignore # NOQA class TestOrderedDict: diff --git a/_test/test_comment_manipulation.py b/_test/test_comment_manipulation.py index 979b386..9101853 100644 --- a/_test/test_comment_manipulation.py +++ b/_test/test_comment_manipulation.py @@ -2,7 +2,7 @@ import pytest # type: ignore # NOQA -from roundtrip import round_trip, dedent, round_trip_load, round_trip_dump # NOQA +from roundtrip import round_trip, dedent, round_trip_load, round_trip_dump # type: ignore # NOQA from typing import Any @@ -17,7 +17,7 @@ def compare(data: Any, s: str, **kw: Any) -> None: def compare_eol(data: Any, s: str) -> None: assert 'EOL' in s ds = dedent(s).replace('EOL', '').replace('\n', '|\n') - assert round_trip_dump(data).replace('\n', '|\n') == ds # type: ignore + assert round_trip_dump(data).replace('\n', '|\n') == ds class TestCommentsManipulation: diff --git a/_test/test_comments.py b/_test/test_comments.py index 6c3d8c3..2c39c4f 100644 --- a/_test/test_comments.py +++ b/_test/test_comments.py @@ -13,7 +13,7 @@ roundtrip changes import pytest # type: ignore # NOQA import sys -from roundtrip import round_trip, dedent, round_trip_load, round_trip_dump +from roundtrip import round_trip, dedent, round_trip_load, round_trip_dump # type: ignore class TestComments: diff --git a/_test/test_copy.py b/_test/test_copy.py index cf402a4..ef37d6d 100644 --- a/_test/test_copy.py +++ b/_test/test_copy.py @@ -8,7 +8,7 @@ import copy import pytest # type: ignore # NOQA -from roundtrip import dedent, round_trip_load, round_trip_dump +from roundtrip import dedent, round_trip_load, round_trip_dump # type: ignore class TestDeepCopy: diff --git a/_test/test_datetime.py b/_test/test_datetime.py index bc86e74..388b96b 100644 --- a/_test/test_datetime.py +++ b/_test/test_datetime.py @@ -22,7 +22,7 @@ Please note that a fraction can only be included if not equal to 0 import copy import pytest # type: ignore # NOQA -from roundtrip import round_trip, dedent, round_trip_load, round_trip_dump # NOQA +from roundtrip import round_trip, dedent, round_trip_load, round_trip_dump # type: ignore # NOQA class TestDateTime: diff --git a/_test/test_documents.py b/_test/test_documents.py index 7c6e2e6..43bd8f4 100644 --- a/_test/test_documents.py +++ b/_test/test_documents.py @@ -2,7 +2,7 @@ import pytest # type: ignore # NOQA -from roundtrip import round_trip, round_trip_load_all, round_trip_dump_all +from roundtrip import round_trip, round_trip_load_all, round_trip_dump_all # type: ignore class TestDocument: diff --git a/_test/test_fail.py b/_test/test_fail.py index 7fbbd07..516856a 100644 --- a/_test/test_fail.py +++ b/_test/test_fail.py @@ -8,7 +8,7 @@ import pytest # type: ignore -from roundtrip import round_trip, dedent, round_trip_load, round_trip_dump +from roundtrip import round_trip, dedent, round_trip_load, round_trip_dump # type: ignore class TestCommentFailures: diff --git a/_test/test_float.py b/_test/test_float.py index 582ccf0..51745f8 100644 --- a/_test/test_float.py +++ b/_test/test_float.py @@ -2,7 +2,7 @@ import pytest # type: ignore # NOQA -from roundtrip import round_trip, dedent, round_trip_load, round_trip_dump # NOQA +from roundtrip import round_trip, dedent, round_trip_load, round_trip_dump # type: ignore # NOQA # http://yaml.org/type/int.html is where underscores in integers are defined diff --git a/_test/test_flowsequencekey.py b/_test/test_flowsequencekey.py index be70699..29f157a 100644 --- a/_test/test_flowsequencekey.py +++ b/_test/test_flowsequencekey.py @@ -7,7 +7,7 @@ test flow style sequences as keys roundtrip # import pytest -from roundtrip import round_trip # , dedent, round_trip_load, round_trip_dump +from roundtrip import round_trip # type: ignore class TestFlowStyleSequenceKey: diff --git a/_test/test_indentation.py b/_test/test_indentation.py index 1f16cb2..995c3b3 100644 --- a/_test/test_indentation.py +++ b/_test/test_indentation.py @@ -3,13 +3,13 @@ from typing import Any import pytest # type: ignore # NOQA -from roundtrip import round_trip, round_trip_load, round_trip_dump, dedent, YAML +from roundtrip import round_trip, round_trip_load, round_trip_dump, dedent, YAML # type: ignore # NOQA def rt(s: str) -> str: res = round_trip_dump(round_trip_load(s)) assert res is not None - return res.strip() + '\n' + return res.strip() + '\n' # type: ignore class TestIndent: diff --git a/_test/test_int.py b/_test/test_int.py index 92fb92a..d50d53a 100644 --- a/_test/test_int.py +++ b/_test/test_int.py @@ -2,7 +2,7 @@ import pytest # type: ignore # NOQA -from roundtrip import dedent, round_trip_load, round_trip_dump +from roundtrip import dedent, round_trip_load, round_trip_dump # type: ignore # http://yaml.org/type/int.html is where underscores in integers are defined diff --git a/_test/test_issues.py b/_test/test_issues.py index 47e8e87..ce78cce 100644 --- a/_test/test_issues.py +++ b/_test/test_issues.py @@ -5,7 +5,8 @@ from typing import Any import pytest # type: ignore # NOQA -from roundtrip import ( +# cannot do "from .roundtrip" because of pytest, so mypy cannot find this +from roundtrip import ( # type: ignore round_trip, na_round_trip, round_trip_load, @@ -18,7 +19,8 @@ from roundtrip import ( class TestIssues: def test_issue_61(self) -> None: - s = dedent(""" + s = dedent( + """ def1: &ANCHOR1 key1: value1 def: &ANCHOR @@ -26,70 +28,73 @@ class TestIssues: key: value comb: <<: *ANCHOR - """) + """ + ) data = round_trip_load(s) assert str(data['comb']) == str(data['def']) assert str(data['comb']) == "{'key': 'value', 'key1': 'value1'}" -# def test_issue_82(self, tmpdir): -# program_src = r''' -# from ruamel import yaml -# import re -# -# class SINumber(yaml.YAMLObject): -# PREFIXES = {'k': 1e3, 'M': 1e6, 'G': 1e9} -# yaml_loader = yaml.Loader -# yaml_dumper = yaml.Dumper -# yaml_tag = '!si' -# yaml_implicit_pattern = re.compile( -# r'^(?P<value>[0-9]+(?:\.[0-9]+)?)(?P<prefix>[kMG])$') -# -# @classmethod -# def from_yaml(cls, loader, node): -# return cls(node.value) -# -# @classmethod -# def to_yaml(cls, dumper, data): -# return dumper.represent_scalar(cls.yaml_tag, str(data)) -# -# def __init__(self, *args): -# m = self.yaml_implicit_pattern.match(args[0]) -# self.value = float(m.groupdict()['value']) -# self.prefix = m.groupdict()['prefix'] -# -# def __str__(self) -> None: -# return str(self.value)+self.prefix -# -# def __int__(self) -> None: -# return int(self.value*self.PREFIXES[self.prefix]) -# -# # This fails: -# yaml.add_implicit_resolver(SINumber.yaml_tag, SINumber.yaml_implicit_pattern) -# -# ret = yaml.load(""" -# [1,2,3, !si 10k, 100G] -# """, Loader=yaml.Loader) -# for idx, l in enumerate([1, 2, 3, 10000, 100000000000]): -# assert int(ret[idx]) == l -# ''' -# assert save_and_run(dedent(program_src), tmpdir) == 0 + # def test_issue_82(self, tmpdir): + # program_src = r''' + # from ruamel import yaml + # import re + # + # class SINumber(yaml.YAMLObject): + # PREFIXES = {'k': 1e3, 'M': 1e6, 'G': 1e9} + # yaml_loader = yaml.Loader + # yaml_dumper = yaml.Dumper + # yaml_tag = '!si' + # yaml_implicit_pattern = re.compile( + # r'^(?P<value>[0-9]+(?:\.[0-9]+)?)(?P<prefix>[kMG])$') + # + # @classmethod + # def from_yaml(cls, loader, node): + # return cls(node.value) + # + # @classmethod + # def to_yaml(cls, dumper, data): + # return dumper.represent_scalar(cls.yaml_tag, str(data)) + # + # def __init__(self, *args): + # m = self.yaml_implicit_pattern.match(args[0]) + # self.value = float(m.groupdict()['value']) + # self.prefix = m.groupdict()['prefix'] + # + # def __str__(self) -> None: + # return str(self.value)+self.prefix + # + # def __int__(self) -> None: + # return int(self.value*self.PREFIXES[self.prefix]) + # + # # This fails: + # yaml.add_implicit_resolver(SINumber.yaml_tag, SINumber.yaml_implicit_pattern) + # + # ret = yaml.load(""" + # [1,2,3, !si 10k, 100G] + # """, Loader=yaml.Loader) + # for idx, l in enumerate([1, 2, 3, 10000, 100000000000]): + # assert int(ret[idx]) == l + # ''' + # assert save_and_run(dedent(program_src), tmpdir) == 0 def test_issue_82rt(self, tmpdir: Any) -> None: yaml_str = '[1, 2, 3, !si 10k, 100G]\n' x = round_trip(yaml_str, preserve_quotes=True) # NOQA def test_issue_102(self) -> None: - yaml_str = dedent(""" + yaml_str = dedent( + """ var1: #empty var2: something #notempty var3: {} #empty object var4: {a: 1} #filled object var5: [] #empty array - """) + """ + ) x = round_trip(yaml_str, preserve_quotes=True) # NOQA def test_issue_150(self) -> None: - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML inp = """\ base: &base_key @@ -107,54 +112,65 @@ class TestIssues: def test_issue_160(self) -> None: from ruamel.yaml.compat import StringIO - s = dedent("""\ + + s = dedent( + """\ root: # a comment - {some_key: "value"} foo: 32 bar: 32 - """) + """ + ) a = round_trip_load(s) del a['root'][0]['some_key'] buf = StringIO() round_trip_dump(a, buf, block_seq_indent=4) - exp = dedent("""\ + exp = dedent( + """\ root: # a comment - {} foo: 32 bar: 32 - """) + """ + ) assert buf.getvalue() == exp def test_issue_161(self) -> None: - yaml_str = dedent("""\ + yaml_str = dedent( + """\ mapping-A: key-A:{} mapping-B: - """) + """ + ) for comment in ['', ' # no-newline', ' # some comment\n', '\n']: s = yaml_str.format(comment) res = round_trip(s) # NOQA def test_issue_161a(self) -> None: - yaml_str = dedent("""\ + yaml_str = dedent( + """\ mapping-A: key-A:{} mapping-B: - """) + """ + ) for comment in ['\n# between']: s = yaml_str.format(comment) res = round_trip(s) # NOQA def test_issue_163(self) -> None: - s = dedent("""\ + s = dedent( + """\ some-list: # List comment - {} - """) + """ + ) x = round_trip(s, preserve_quotes=True) # NOQA json_str = ( @@ -171,14 +187,15 @@ class TestIssues: def test_issue_176(self) -> None: # basic request by Stuart Berg - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML yaml = YAML() seq = yaml.load('[1,2,3]') seq[:] = [1, 2, 3, 4] def test_issue_176_preserve_comments_on_extended_slice_assignment(self) -> None: - yaml_str = dedent("""\ + yaml_str = dedent( + """\ - a - b # comment - c # commment c @@ -186,7 +203,8 @@ class TestIssues: - d - e # comment - """) + """ + ) seq = round_trip_load(yaml_str) seq[1::2] = ['B', 'D'] res = round_trip_dump(seq) @@ -243,28 +261,34 @@ class TestIssues: assert m == [] def test_issue_184(self) -> None: - yaml_str = dedent("""\ + yaml_str = dedent( + """\ test::test: # test foo: bar: baz - """) + """ + ) d = round_trip_load(yaml_str) d['bar'] = 'foo' d.yaml_add_eol_comment('test1', 'bar') assert round_trip_dump(d) == yaml_str + 'bar: foo # test1\n' def test_issue_219(self) -> None: - yaml_str = dedent("""\ + yaml_str = dedent( + """\ [StackName: AWS::StackName] - """) + """ + ) d = round_trip_load(yaml_str) # NOQA def test_issue_219a(self) -> None: - yaml_str = dedent("""\ + yaml_str = dedent( + """\ [StackName: AWS::StackName] - """) + """ + ) d = round_trip_load(yaml_str) # NOQA def test_issue_220(self, tmpdir: Any) -> None: @@ -289,103 +313,119 @@ class TestIssues: a + [4, 5] def test_issue_221_sort(self) -> None: - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML from ruamel.yaml.compat import StringIO yaml = YAML() - inp = dedent("""\ + inp = dedent( + """\ - d - a # 1 - c # 3 - e # 5 - b # 2 - """) + """ + ) a = yaml.load(dedent(inp)) a.sort() buf = StringIO() yaml.dump(a, buf) - exp = dedent("""\ + exp = dedent( + """\ - a # 1 - b # 2 - c # 3 - d - e # 5 - """) + """ + ) assert buf.getvalue() == exp def test_issue_221_sort_reverse(self) -> None: - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML from ruamel.yaml.compat import StringIO yaml = YAML() - inp = dedent("""\ + inp = dedent( + """\ - d - a # 1 - c # 3 - e # 5 - b # 2 - """) + """ + ) a = yaml.load(dedent(inp)) a.sort(reverse=True) buf = StringIO() yaml.dump(a, buf) - exp = dedent("""\ + exp = dedent( + """\ - e # 5 - d - c # 3 - b # 2 - a # 1 - """) + """ + ) assert buf.getvalue() == exp def test_issue_221_sort_key(self) -> None: - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML from ruamel.yaml.compat import StringIO yaml = YAML() - inp = dedent("""\ + inp = dedent( + """\ - four - One # 1 - Three # 3 - five # 5 - two # 2 - """) + """ + ) a = yaml.load(dedent(inp)) a.sort(key=str.lower) buf = StringIO() yaml.dump(a, buf) - exp = dedent("""\ + exp = dedent( + """\ - five # 5 - four - One # 1 - Three # 3 - two # 2 - """) + """ + ) assert buf.getvalue() == exp def test_issue_221_sort_key_reverse(self) -> None: - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML from ruamel.yaml.compat import StringIO yaml = YAML() - inp = dedent("""\ + inp = dedent( + """\ - four - One # 1 - Three # 3 - five # 5 - two # 2 - """) + """ + ) a = yaml.load(dedent(inp)) a.sort(key=str.lower, reverse=True) buf = StringIO() yaml.dump(a, buf) - exp = dedent("""\ + exp = dedent( + """\ - two # 2 - Three # 3 - One # 1 - four - five # 5 - """) + """ + ) assert buf.getvalue() == exp def test_issue_222(self) -> None: @@ -414,7 +454,7 @@ class TestIssues: yaml.load('{]') def test_issue_233(self) -> None: - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML import json yaml = YAML() @@ -422,7 +462,7 @@ class TestIssues: json_str = json.dumps(data) # NOQA def test_issue_233a(self) -> None: - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML import json yaml = YAML() @@ -430,16 +470,18 @@ class TestIssues: json_str = json.dumps(data) # NOQA def test_issue_234(self) -> None: - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML - inp = dedent("""\ + inp = dedent( + """\ - key: key1 ctx: [one, two] help: one cmd: > foo bar foo bar - """) + """ + ) yaml = YAML(typ='safe', pure=True) data = yaml.load(inp) fold = data[0]['cmd'] @@ -513,7 +555,8 @@ class TestIssues: assert d0['a'] == 'b' def test_issue_245(self) -> None: - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML + inp = """ d: yes """ @@ -532,19 +575,23 @@ class TestIssues: def test_issue_249(self) -> None: yaml = YAML() - inp = dedent("""\ + inp = dedent( + """\ # comment - - 1 - 2 - 3 - """) - exp = dedent("""\ + """ + ) + exp = dedent( + """\ # comment - - 1 - 2 - 3 - """) + """ + ) yaml.round_trip(inp, outp=exp) # NOQA def test_issue_250(self) -> None: @@ -560,18 +607,20 @@ class TestIssues: # @pytest.mark.xfail(strict=True, reason='bla bla', raises=AssertionError) def test_issue_279(self) -> None: - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML from ruamel.yaml.compat import StringIO yaml = YAML() yaml.indent(sequence=4, offset=2) - inp = dedent("""\ + inp = dedent( + """\ experiments: - datasets: # ATLAS EWK - {dataset: ATLASWZRAP36PB, frac: 1.0} - {dataset: ATLASZHIGHMASS49FB, frac: 1.0} - """) + """ + ) a = yaml.load(inp) buf = StringIO() yaml.dump(a, buf) @@ -579,10 +628,11 @@ class TestIssues: assert buf.getvalue() == inp def test_issue_280(self) -> None: - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML from ruamel.yaml.representer import RepresenterError from collections import namedtuple from sys import stdout + T = namedtuple('T', ('a', 'b')) t = T(1, 2) yaml = YAML() @@ -592,6 +642,7 @@ class TestIssues: def test_issue_282(self) -> None: # update from list of tuples caused AttributeError import ruamel.yaml + yaml_data = ruamel.yaml.comments.CommentedMap([('a', 'apple'), ('b', 'banana')]) yaml_data.update([('c', 'cantaloupe')]) yaml_data.update({'d': 'date', 'k': 'kiwi'}) @@ -600,12 +651,15 @@ class TestIssues: def test_issue_284(self) -> None: import ruamel.yaml - inp = dedent("""\ + + inp = dedent( + """\ plain key: in-line value : # Both empty "quoted key": - entry - """) + """ + ) yaml = ruamel.yaml.YAML(typ='rt') yaml.version = (1, 2) d = yaml.load(inp) @@ -617,17 +671,19 @@ class TestIssues: d = yaml.load(inp) def test_issue_285(self) -> None: - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML yaml = YAML() - inp = dedent("""\ + inp = dedent( + """\ %YAML 1.1 --- - y - n - Y - N - """) + """ + ) a = yaml.load(inp) assert a[0] assert a[2] @@ -635,15 +691,17 @@ class TestIssues: assert not a[3] def test_issue_286(self) -> None: - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML from ruamel.yaml.compat import StringIO yaml = YAML() - inp = dedent("""\ + inp = dedent( + """\ parent_key: - sub_key: sub_value - # xxx""") + # xxx""" + ) a = yaml.load(inp) a['new_key'] = 'new_value' buf = StringIO() @@ -653,9 +711,10 @@ class TestIssues: def test_issue_288(self) -> None: import sys from ruamel.yaml.compat import StringIO - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML - yamldoc = dedent("""\ + yamldoc = dedent( + """\ --- # Reusable values aliases: @@ -669,7 +728,8 @@ class TestIssues: - &thirdEntry Third entry # EOF Comment - """) + """ + ) yaml = YAML() yaml.indent(mapping=2, sequence=4, offset=2) @@ -684,9 +744,10 @@ class TestIssues: def test_issue_288a(self) -> None: import sys from ruamel.yaml.compat import StringIO - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML - yamldoc = dedent("""\ + yamldoc = dedent( + """\ --- # Reusable values aliases: @@ -700,7 +761,8 @@ class TestIssues: - &thirdEntry Third entry # EOF Comment - """) + """ + ) yaml = YAML() yaml.indent(mapping=2, sequence=4, offset=2) @@ -715,9 +777,10 @@ class TestIssues: def test_issue_290(self) -> None: import sys from ruamel.yaml.compat import StringIO - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML - yamldoc = dedent("""\ + yamldoc = dedent( + """\ --- aliases: # Folded-element comment @@ -736,7 +799,8 @@ class TestIssues: # Plain-element comment - &plainEntry Plain entry - """) + """ + ) yaml = YAML() yaml.indent(mapping=2, sequence=4, offset=2) @@ -751,9 +815,10 @@ class TestIssues: def test_issue_290a(self) -> None: import sys from ruamel.yaml.compat import StringIO - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML - yamldoc = dedent("""\ + yamldoc = dedent( + """\ --- aliases: # Folded-element comment @@ -772,7 +837,8 @@ class TestIssues: # Plain-element comment - &plainEntry Plain entry - """) + """ + ) yaml = YAML() yaml.indent(mapping=2, sequence=4, offset=2) @@ -791,7 +857,8 @@ class TestIssues: # some old merge_comment code import copy - inp = dedent(""" + inp = dedent( + """ A: b: # comment @@ -805,34 +872,40 @@ class TestIssues: - - l31 - l32 - l33: '5' - """) + """ + ) data = round_trip_load(inp) # NOQA dc = copy.deepcopy(data) assert round_trip_dump(dc) == inp def test_issue_300(self) -> None: - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML - inp = dedent(""" + inp = dedent( + """ %YAML 1.2 %TAG ! tag:example.com,2019/path#fragment --- null - """) + """ + ) YAML().load(inp) def test_issue_300a(self) -> None: import ruamel.yaml - inp = dedent(""" + inp = dedent( + """ %YAML 1.1 %TAG ! tag:example.com,2019/path#fragment --- null - """) + """ + ) yaml = YAML() - with pytest.raises(ruamel.yaml.scanner.ScannerError, - match='while scanning a directive'): + with pytest.raises( + ruamel.yaml.scanner.ScannerError, match='while scanning a directive' + ): yaml.load(inp) def test_issue_304(self) -> None: @@ -864,12 +937,83 @@ class TestIssues: """ d = na_round_trip(inp) # NOQA + def test_issue_445(self) -> None: + from ruamel.yaml import YAML + from ruamel.yaml.compat import StringIO + + yaml = YAML() + yaml.version = '1.1' + data = yaml.load('quote: I have seen things') + buf = StringIO() + yaml.dump(data, buf) + assert buf.getvalue() == '%YAML 1.1\n---\nquote: I have seen things\n' + yaml = YAML() + yaml.version = [1, 1] + data = yaml.load('quote: I have seen things') + buf = StringIO() + yaml.dump(data, buf) + assert buf.getvalue() == '%YAML 1.1\n---\nquote: I have seen things\n' + def test_issue_449(self) -> None: inp = """\ emoji_index: !!python/name:materialx.emoji.twemoji """ d = na_round_trip(inp) # NOQA + def test_issue_455(self) -> None: + from ruamel.yaml import YAML + + cm = YAML().map(a=97, b=98) + cm.update({'c': 42, 'd': 196}) + cm.update(c=99, d=100) + prev = None + for k, v in cm.items(): + if prev is not None: + assert prev + 1 == v + prev = v + assert ord(k) == v + assert len(cm) == 4 + + def test_issue_454(self) -> None: + inp = """ + test1: 🎉 + test2: "🎉" + test3: '🎉' + """ + d = round_trip(inp, preserve_quotes=True) # NOQA + + def test_so_75631454(self) -> None: + from ruamel.yaml import YAML + from ruamel.yaml.compat import StringIO + + inp = dedent( + """ + test: + long: "This is a sample text + across two lines." + """ + ) + yaml = YAML() + yaml.preserve_quotes = True + yaml.indent(mapping=4) + yaml.width = 27 + data = yaml.load(inp) + buf = StringIO() + yaml.dump(data, buf) + assert buf.getvalue() == inp + + def test_issue_458(self) -> None: + from io import StringIO + from ruamel.yaml import YAML + + yaml = YAML() + out_stream = StringIO() + in_string = "a" * 128 + yaml.dump(in_string, out_stream) + result = out_stream.getvalue() + assert in_string == result.splitlines()[0] + + # @pytest.mark.xfail(strict=True, reason='bla bla', raises=AssertionError) # def test_issue_ xxx(self) -> None: # inp = """ diff --git a/_test/test_line_col.py b/_test/test_line_col.py index 5ba125e..6b172b0 100644 --- a/_test/test_line_col.py +++ b/_test/test_line_col.py @@ -2,7 +2,7 @@ import pytest # type: ignore # NOQA -from roundtrip import round_trip, dedent, round_trip_load, round_trip_dump # NOQA +from roundtrip import round_trip, dedent, round_trip_load, round_trip_dump # type: ignore # NOQA from typing import Any diff --git a/_test/test_literal.py b/_test/test_literal.py index 0cf34bc..f5c42e4 100644 --- a/_test/test_literal.py +++ b/_test/test_literal.py @@ -2,7 +2,7 @@ import pytest # type: ignore # NOQA -from roundtrip import YAML # does an automatic dedent on load +from roundtrip import YAML # type: ignore # does an automatic dedent on load """ @@ -63,7 +63,7 @@ class TestNoIndent: def test_root_literal_scalar_no_indent_1_1_old_style(self) -> None: from textwrap import dedent - from ruamel.yaml import YAML # type: ignore + from ruamel.yaml import YAML yaml = YAML(typ='safe', pure=True) s = 'testing123' diff --git a/_test/test_none.py b/_test/test_none.py index e11de17..dfb6c4c 100644 --- a/_test/test_none.py +++ b/_test/test_none.py @@ -1,7 +1,7 @@ # coding: utf-8 import pytest # type: ignore # NOQA -from roundtrip import round_trip_load, round_trip_dump +from roundtrip import round_trip_load, round_trip_dump # type: ignore class TestNone: diff --git a/_test/test_program_config.py b/_test/test_program_config.py index 6c5cad8..cda40d3 100644 --- a/_test/test_program_config.py +++ b/_test/test_program_config.py @@ -3,7 +3,7 @@ import pytest # type: ignore # NOQA # import ruamel.yaml -from roundtrip import round_trip +from roundtrip import round_trip # type: ignore class TestProgramConfig: diff --git a/_test/test_spec_examples.py b/_test/test_spec_examples.py index 7faa4bf..96c4a4d 100644 --- a/_test/test_spec_examples.py +++ b/_test/test_spec_examples.py @@ -1,6 +1,6 @@ # coding: utf-8 -from roundtrip import YAML +from roundtrip import YAML # type: ignore import pytest # type: ignore # NOQA diff --git a/_test/test_string.py b/_test/test_string.py index 75890d2..910e38c 100644 --- a/_test/test_string.py +++ b/_test/test_string.py @@ -17,7 +17,7 @@ import pytest # type: ignore import platform # from ruamel.yaml.compat import ordereddict -from roundtrip import round_trip, dedent, round_trip_load, round_trip_dump # NOQA +from roundtrip import round_trip, dedent, round_trip_load, round_trip_dump # type: ignore # NOQA class TestLiteralScalarString: diff --git a/_test/test_tag.py b/_test/test_tag.py index 6447779..5f388e5 100644 --- a/_test/test_tag.py +++ b/_test/test_tag.py @@ -3,7 +3,7 @@ import pytest # type: ignore # NOQA from typing import Any -from roundtrip import round_trip, round_trip_load, YAML +from roundtrip import round_trip, round_trip_load, YAML # type: ignore def register_xxx(**kw: Any) -> None: diff --git a/_test/test_version.py b/_test/test_version.py index b60b1dd..a664e49 100644 --- a/_test/test_version.py +++ b/_test/test_version.py @@ -3,7 +3,7 @@ import pytest # type: ignore # NOQA from typing import Any, Optional -from roundtrip import dedent, round_trip, round_trip_load +from roundtrip import dedent, round_trip, round_trip_load # type: ignore def load(s: str, version: Optional[Any] = None) -> Any: diff --git a/_test/test_yamlfile.py b/_test/test_yamlfile.py index 6f7aca7..47ab407 100644 --- a/_test/test_yamlfile.py +++ b/_test/test_yamlfile.py @@ -9,7 +9,7 @@ import io import pytest # type: ignore # NOQA import platform -from roundtrip import round_trip, dedent, round_trip_load, round_trip_dump # NOQA +from roundtrip import round_trip, dedent, round_trip_load, round_trip_dump # type: ignore # NOQA class TestYAML: diff --git a/_test/test_yamlobject.py b/_test/test_yamlobject.py index 3f488d3..7f7b14d 100644 --- a/_test/test_yamlobject.py +++ b/_test/test_yamlobject.py @@ -4,7 +4,7 @@ import sys from typing import Any import pytest # type: ignore # NOQA -from roundtrip import save_and_run # NOQA +from roundtrip import save_and_run # type: ignore # NOQA def test_monster(tmpdir: Any) -> None: diff --git a/_test/test_z_check_debug_leftovers.py b/_test/test_z_check_debug_leftovers.py index 7096a73..cd636aa 100644 --- a/_test/test_z_check_debug_leftovers.py +++ b/_test/test_z_check_debug_leftovers.py @@ -4,7 +4,7 @@ import sys from typing import Any import pytest # type: ignore # NOQA -from roundtrip import round_trip_load, round_trip_dump, dedent +from roundtrip import round_trip_load, round_trip_dump, dedent # type: ignore class TestLeftOverDebug: diff --git a/_test/test_z_data.py b/_test/test_z_data.py index 8a8ba21..f2e72f1 100644 --- a/_test/test_z_data.py +++ b/_test/test_z_data.py @@ -161,7 +161,7 @@ class TestYAMLData: def run_python( self, python: Any, data: Any, tmpdir: Any, input: Optional[Any] = None ) -> None: - from roundtrip import save_and_run + from roundtrip import save_and_run # type: ignore if input is not None: (tmpdir / 'input.yaml').write_text(input.value, encoding='utf-8') diff --git a/comments.py b/comments.py index da2b191..c7a4575 100644 --- a/comments.py +++ b/comments.py @@ -790,7 +790,7 @@ class CommentedMap(ordereddict, CommentedBase): for x in vals[0]: self._ok.add(x[0]) if kw: - self._ok.add(*kw.keys()) + self._ok.update(*kw.keys()) # type: ignore def insert(self, pos: Any, key: Any, value: Any, comment: Optional[Any] = None) -> None: """insert key value into given position @@ -866,7 +866,7 @@ class CommentedMap(ordereddict, CommentedBase): return default def __repr__(self) -> Any: - res = "{" + res = '{' sep = '' for k, v in self.items(): res += f'{sep}{k!r}: {v!r}' @@ -1131,13 +1131,13 @@ def dump_comments(d: Any, name: str = "", sep: str = '.', out: Any = sys.stdout) if isinstance(d, dict) and hasattr(d, 'ca'): if name: out.write(f'{name} {type(d)}\n') - out.write(f'{d.ca!r}\n') # type: ignore + out.write(f'{d.ca!r}\n') for k in d: dump_comments(d[k], name=(name + sep + str(k)) if name else k, sep=sep, out=out) elif isinstance(d, list) and hasattr(d, 'ca'): if name: out.write(f'{name} {type(d)}\n') - out.write(f'{d.ca!r}\n') # type: ignore + out.write(f'{d.ca!r}\n') for idx, k in enumerate(d): dump_comments( k, name=(name + sep + str(idx)) if name else str(idx), sep=sep, out=out @@ -211,7 +211,7 @@ class Emitter: try: return self._stream except AttributeError: - raise YAMLStreamError('output stream needs to specified') + raise YAMLStreamError('output stream needs to be specified') @stream.setter def stream(self, val: Any) -> None: @@ -1350,7 +1350,7 @@ class Emitter: self.write_line_break() if self.requested_indent != 0: self.write_indent() - self.write_indicator('"', True) + self.write_indicator(u'"', True) start = end = 0 while end <= len(text): ch = None @@ -1358,12 +1358,16 @@ class Emitter: ch = text[end] if ( ch is None - or ch in '"\\\x85\u2028\u2029\uFEFF' + or ch in u'"\\\x85\u2028\u2029\uFEFF' or not ( - '\x20' <= ch <= '\x7E' + u'\x20' <= ch <= u'\x7E' or ( self.allow_unicode - and ('\xA0' <= ch <= '\uD7FF' or '\uE000' <= ch <= '\uFFFD') + and ( + (u'\xA0' <= ch <= u'\uD7FF') + or (u'\uE000' <= ch <= u'\uFFFD') + or (u'\U00010000' <= ch <= u'\U0010FFFF') + ) ) ) ): @@ -1376,13 +1380,13 @@ class Emitter: start = end if ch is not None: if ch in self.ESCAPE_REPLACEMENTS: - data = '\\' + self.ESCAPE_REPLACEMENTS[ch] - elif ch <= '\xFF': - data = f'\\x{ord(ch):02X}' - elif ch <= '\uFFFF': - data = f'\\u{ord(ch):04X}' + 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) else: - data = f'\\U{ord(ch):08X}' + data = u'\\U%08X' % ord(ch) self.column += len(data) if bool(self.encoding): data = data.encode(self.encoding) @@ -1390,11 +1394,18 @@ class Emitter: start = end + 1 if ( 0 < end < len(text) - 1 - and (ch == ' ' or start >= end) + and (ch == u' ' or start >= end) and self.column + (end - start) > self.best_width and split ): - data = text[start:end] + '\\' + # 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'') if start < end: start = end self.column += len(data) @@ -1404,14 +1415,18 @@ class Emitter: self.write_indent() self.whitespace = False self.indention = False - if text[start] == ' ': - data = '\\' + if text[start] == u' ': + 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'' self.column += len(data) if bool(self.encoding): data = data.encode(self.encoding) self.stream.write(data) end += 1 - self.write_indicator('"', False) + self.write_indicator(u'"', False) def determine_block_hints(self, text: Any) -> Any: indent = 0 @@ -1619,8 +1634,9 @@ 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.column > self.indent: # type: ignore + 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) @@ -31,7 +31,7 @@ class Event: # if you use repr(getattr(self, 'value')) then flake8 complains about # abuse of getattr with a constant. When you change to self.value # then mypy throws an error - arguments.append(repr(self.value)) # type: ignore + arguments.append(repr(self.value)) for key in ['anchor', 'tag', 'implicit', 'flow_style', 'style']: v = getattr(self, key, None) if v is not None: @@ -54,7 +54,7 @@ class YAML: def __init__( self: Any, *, - typ: Optional[Text] = None, + typ: Optional[Union[List[Text], Text]] = None, pure: Any = False, output: Any = None, plug_ins: Any = None, @@ -157,7 +157,7 @@ class YAML: self.top_level_colon_align = None self.prefix_colon = None - self.version: Optional[Any] = None + self._version: Optional[Any] = None self.preserve_quotes: Optional[bool] = None self.allow_duplicate_keys = False # duplicate keys in map, set self.encoding = 'utf-8' @@ -798,6 +798,24 @@ class YAML: self.sequence_dash_offset = offset @property + def version(self) -> Optional[Any]: + return self._version + + @version.setter + def version(self, val: Optional[VersionType]) -> None: + if val is None: + self._version = val + return + if isinstance(val, str): + sval = tuple(int(x) for x in val.split('.')) + else: + sval = tuple(int(x) for x in val) + assert len(sval) == 2, f'version can only have major.minor, got {val}' + assert sval[0] == 1, f'version major part can only be 1, got {val}' + assert sval[1] in [1, 2], f'version minor part can only be 2 or 1, got {val}' + self._version = sval + + @property def indent(self) -> Any: return self._indent @@ -93,7 +93,7 @@ class Reader: try: return self._stream except AttributeError: - raise YAMLStreamError('input stream needs to specified') + raise YAMLStreamError('input stream needs to be specified') @stream.setter def stream(self, val: Any) -> None: @@ -788,7 +788,6 @@ class TmpFiles: def __enter__(self): self.bdist_wheel() - return self.py_project() def bdist_wheel(self): |