diff --git a/.hgtags b/.hgtags index 321ee99..925fdba 100644 --- a/.hgtags +++ b/.hgtags @@ -217,3 +217,6 @@ d522a02977979e5feef1d0f1b94b6b7f823c0bdd 0.17.28 41fd3925691106c999959771e54bd69cce70d1c8 0.17.29 0ed43732b9e309d397e9c9cfa74f115f40f51a6b 0.17.30 b01b2f5c1ff21d561193de37b7e843baa2b91c91 0.17.31 +e2d9ee085ae698c4dca733b83a718b9e4a6ec8c0 0.17.32 +c4b4f7766d1845b67606fba5dd7d753e614417ea 0.17.33 +31cd820ffa1ae47947343603617be8294d8f1657 0.17.34 diff --git a/CHANGES b/CHANGES index ad89596..bfde04b 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,24 @@ +[0, 17, 35]: 2023-10-04 + - support for loading dataclasses with ``InitVar`` variables (some + special coding was necessary to get the, unexecpected, default value + in the corresponding instance attribute ( example of usage in + `this question `__ ) + +[0, 17, 34]: 2023-10-03 + - Python 3.12 also loads C version when using `typ='safe'` + - initial support for loading invoking `__post_init__()` on dataclasses that have that method + after loading a registered dataclass (`@yaml.register_class\n@dataclass\nclass ...`). + (Originally `asked `__ on Stackoverflow by + `nyanpasu64 `__ and as + `ticket `__ + by `Patrick Lehmann `__ + +[0, 17, 33]: 2023-09-28 + - added `flow_seq_start`, `flow_seq_end`, `flow_seq_separator`, `flow_map_start`, `flow_map_end`, + `flow_map_separator` **class** attributes to the `Emitter` class so flow style output + can more easily be influenced (based on `this answer `__ + on a StackOverflow question by `Huw Walters `__). + [0, 17, 32]: 2023-06-17 - fix issue with scanner getting stuck in infinite loop diff --git a/README.rst b/README.rst index f2fc104..9ad161b 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.32 -:updated: 2023-06-17 +:version: 0.17.35 +:updated: 2023-10-04 :documentation: http://yaml.readthedocs.io :repository: https://sourceforge.net/projects/ruamel-yaml/ :pypi: https://pypi.org/project/ruamel.yaml/ @@ -61,6 +61,27 @@ ChangeLog .. should insert NEXT: at the beginning of line for next key (with empty line) +0.17.35 (2023-10-04): + - support for loading dataclasses with ``InitVar`` variables (some + special coding was necessary to get the, unexecpected, default value + in the corresponding instance attribute ( example of usage in + `this question `__ ) + +0.17.34 (2023-10-03): + - Python 3.12 also loads C version when using ``typ='safe'`` + - initial support for loading invoking `__post_init__()` on dataclasses that have that method + after loading a registered dataclass (`@yaml.register_class\n@dataclass\nclass ...`). + (Originally `asked `__ on Stackoverflow by + `nyanpasu64 `__ and as + `ticket `__ + by `Patrick Lehmann `__ + +0.17.33 (2023-09-28): + - added `flow_seq_start`, `flow_seq_end`, `flow_seq_separator`, `flow_map_start`, `flow_map_end`, + `flow_map_separator` **class** attributes to the `Emitter` class so flow style output + can more easily be influenced (based on `this answer `__ + on a StackOverflow question by `Huw Walters `__). + 0.17.32 (2023-06-17): - fix issue with scanner getting stuck in infinite loop diff --git a/__init__.py b/__init__.py index a1043fd..b96961d 100644 --- a/__init__.py +++ b/__init__.py @@ -5,16 +5,16 @@ _package_data = dict( full_package_name='ruamel.yaml', - version_info=(0, 17, 32), - __version__='0.17.32', - version_timestamp='2023-06-17 07:55:58', + version_info=(0, 17, 35), + __version__='0.17.35', + version_timestamp='2023-10-04 11:45:09', 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.12"': ['ruamel.yaml.clib>=0.2.7'], # NOQA + ':platform_python_implementation=="CPython" and python_version<"3.13"': ['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 59e057b..6703d59 100644 --- a/_doc/_static/pypi.svg +++ b/_doc/_static/pypi.svg @@ -1 +1 @@ - pypipypi0.17.320.17.32 + pypipypi0.17.350.17.35 diff --git a/_doc/conf.py b/_doc/conf.py index 67fcc0e..1c4a02d 100644 --- a/_doc/conf.py +++ b/_doc/conf.py @@ -252,7 +252,7 @@ class ryd2rst: 'Python YAML package documentation', 'Anthon van der Neut', 'manual', - ) + ), ] # The name of an image file (relative to this directory) to place at the top of @@ -300,7 +300,7 @@ class ryd2rst: 'yaml', 'One line description of project.', 'Miscellaneous', - ) + ), ] # Documents to append as an appendix to all manuals. diff --git a/_test/roundtrip.py b/_test/roundtrip.py index fa8b08a..d36d704 100644 --- a/_test/roundtrip.py +++ b/_test/roundtrip.py @@ -27,7 +27,7 @@ def dedent(data: str) -> str: def round_trip_load( - inp: Any, preserve_quotes: Optional[bool] = None, version: Optional[Any] = None + inp: Any, preserve_quotes: Optional[bool] = None, version: Optional[Any] = None, ) -> Any: import ruamel.yaml # NOQA @@ -39,7 +39,7 @@ def round_trip_load( def round_trip_load_all( - inp: Any, preserve_quotes: Optional[bool] = None, version: Optional[Any] = None + inp: Any, preserve_quotes: Optional[bool] = None, version: Optional[Any] = None, ) -> Any: import ruamel.yaml # NOQA diff --git a/_test/test_a_dedent.py b/_test/test_a_dedent.py index 569171c..a4adf33 100644 --- a/_test/test_a_dedent.py +++ b/_test/test_a_dedent.py @@ -44,6 +44,6 @@ def test_multiple_dedent(self) -> None: x = dedent( dedent(""" 123 - """) + """), ) assert x == '123\n' diff --git a/_test/test_add_xxx.py b/_test/test_add_xxx.py index 32859c2..0ff8c26 100644 --- a/_test/test_add_xxx.py +++ b/_test/test_add_xxx.py @@ -122,7 +122,7 @@ def test_yaml_obj_with_loader_and_dumper() -> None: yaml = ruamel.yaml.YAML(typ='unsafe', pure=True) ruamel.yaml.add_representer(Obj1, YAMLObj1.to_yaml, Dumper=ruamel.yaml.Dumper) ruamel.yaml.add_multi_constructor( - YAMLObj1.yaml_tag, YAMLObj1.from_yaml, Loader=ruamel.yaml.Loader + YAMLObj1.yaml_tag, YAMLObj1.from_yaml, Loader=ruamel.yaml.Loader, ) x = yaml.load('!obj:x.2\na: 1') # x = ruamel.yaml.load('!obj:x.2\na: 1') diff --git a/_test/test_anchor.py b/_test/test_anchor.py index bab41fd..d4da89b 100644 --- a/_test/test_anchor.py +++ b/_test/test_anchor.py @@ -106,7 +106,7 @@ def test_anchor_id_retained(self) -> None: ) @pytest.mark.skipif( # type: ignore - platform.python_implementation() == 'Jython', reason='Jython throws RepresenterError' + platform.python_implementation() == 'Jython', reason='Jython throws RepresenterError', ) def test_alias_before_anchor(self) -> None: from ruamel.yaml.composer import ComposerError diff --git a/_test/test_api_change.py b/_test/test_api_change.py index 84e7828..85d3db8 100644 --- a/_test/test_api_change.py +++ b/_test/test_api_change.py @@ -164,7 +164,7 @@ def test_multi_document_load(self, tmpdir: Any) -> None: --- - b ... - """) + """), ) yaml = YAML() assert list(yaml.load_all(fn)) == [['a'], ['b']] @@ -185,7 +185,7 @@ def test_dupl_set_00(self) -> None: ? b ? c ? a - """) + """), ) diff --git a/_test/test_class_register.py b/_test/test_class_register.py index 39be660..18d2254 100644 --- a/_test/test_class_register.py +++ b/_test/test_class_register.py @@ -128,7 +128,7 @@ def __init__(self, name: str, age: int) -> None: @classmethod def to_yaml(cls, representer: Any, node: Any) -> Any: return representer.represent_scalar( - cls.yaml_tag, '{.name}-{.age}'.format(node, node) + cls.yaml_tag, '{.name}-{.age}'.format(node, node), ) @classmethod diff --git a/_test/test_comment_manipulation.py b/_test/test_comment_manipulation.py index 9101853..7ff26f7 100644 --- a/_test/test_comment_manipulation.py +++ b/_test/test_comment_manipulation.py @@ -446,7 +446,7 @@ def test_map_set_comment_before_and_after_non_first_key_00(self) -> None: test3: 3 """) data.yaml_set_comment_before_after_key( - 'test1', 'before test1 (top level)', after='before test2' + 'test1', 'before test1 (top level)', after='before test2', ) data['test1']['test2'].yaml_set_start_comment('after test2', indent=4) exp = """ @@ -474,7 +474,7 @@ def Xtest_map_set_comment_before_and_after_non_first_key_01(self) -> None: test3: 3 """) data.yaml_set_comment_before_after_key( - 'test1', 'before test1 (top level)', after='before test2\n\n' + 'test1', 'before test1 (top level)', after='before test2\n\n', ) data['test1']['test2'].yaml_set_start_comment('after test2', indent=4) # EOL is needed here as dedenting gets rid of spaces (as well as does Emacs @@ -506,7 +506,7 @@ def test_map_set_comment_before_and_after_non_first_key_01(self) -> None: test3: 3 """) data.yaml_set_comment_before_after_key( - 'test1', 'before test1 (top level)', after='before test2\n\n' + 'test1', 'before test1 (top level)', after='before test2\n\n', ) data['test1']['test2'].yaml_set_start_comment('after test2', indent=4) exp = """ @@ -535,7 +535,7 @@ def Xtest_map_set_comment_before_and_after_non_first_key_02(self) -> None: test3: 3 """) data.yaml_set_comment_before_after_key( - 'test1', 'xyz\n\nbefore test1 (top level)', after='\nbefore test2', after_indent=4 + 'test1', 'xyz\n\nbefore test1 (top level)', after='\nbefore test2', after_indent=4, ) data['test1']['test2'].yaml_set_start_comment('after test2', indent=4) # EOL is needed here as dedenting gets rid of spaces (as well as does Emacs @@ -567,7 +567,7 @@ def test_map_set_comment_before_and_after_non_first_key_02(self) -> None: test3: 3 """) data.yaml_set_comment_before_after_key( - 'test1', 'xyz\n\nbefore test1 (top level)', after='\nbefore test2', after_indent=4 + 'test1', 'xyz\n\nbefore test1 (top level)', after='\nbefore test2', after_indent=4, ) data['test1']['test2'].yaml_set_start_comment('after test2', indent=4) exp = """ diff --git a/_test/test_comments.py b/_test/test_comments.py index 2c39c4f..491f00e 100644 --- a/_test/test_comments.py +++ b/_test/test_comments.py @@ -274,7 +274,7 @@ def test_dump_utf8(self) -> None: data = round_trip_load(x) for utf in [True, False]: y = round_trip_dump( - data, default_flow_style=False, allow_unicode=utf + data, default_flow_style=False, allow_unicode=utf, ) assert y == x @@ -289,7 +289,7 @@ def test_dump_unicode_utf8(self) -> None: data = round_trip_load(x) for utf in [True, False]: y = round_trip_dump( - data, default_flow_style=False, allow_unicode=utf + data, default_flow_style=False, allow_unicode=utf, ) assert y == x diff --git a/_test/test_cyaml.py b/_test/test_cyaml.py index e1280f3..ce6a543 100644 --- a/_test/test_cyaml.py +++ b/_test/test_cyaml.py @@ -10,7 +10,7 @@ @pytest.mark.skipif( # type: ignore platform.python_implementation() in ['Jython', 'PyPy'], - reason='Jython throws RepresenterError' + reason='Jython throws RepresenterError', ) def test_load_cyaml() -> None: print("???????????????????????", platform.python_implementation()) @@ -42,7 +42,7 @@ def test_dump_cyaml() -> None: @pytest.mark.skipif( # type: ignore - platform.python_implementation() in ['Jython', 'PyPy'], reason='not avialable' + platform.python_implementation() in ['Jython', 'PyPy'], reason='not avialable', ) def test_load_cyaml_1_2() -> None: # issue 155 @@ -61,7 +61,7 @@ def test_load_cyaml_1_2() -> None: @pytest.mark.skipif( # type: ignore - platform.python_implementation() in ['Jython', 'PyPy'], reason='not available' + platform.python_implementation() in ['Jython', 'PyPy'], reason='not available', ) def test_dump_cyaml_1_2() -> None: # issue 155 diff --git a/_test/test_dataclass.py b/_test/test_dataclass.py new file mode 100644 index 0000000..ac5ec56 --- /dev/null +++ b/_test/test_dataclass.py @@ -0,0 +1,135 @@ + + +from dataclasses import dataclass, fields, InitVar # NOQA +from textwrap import dedent +from io import BytesIO +from typing import ClassVar, Union + + +class TestDataClasses: + def test_1(self) -> None: + from ruamel.yaml import YAML + + yaml = YAML() + + @yaml.register_class + @dataclass + class DC: + abc: int + klm: int + xyz: int = 0 + + def __post_init__(self) -> None: + self.xyz = self.abc + self.klm + + dc = DC(abc=5, klm=42) + assert dc.xyz == 47 + + yaml_str = dedent("""\ + !DC + abc: 13 + klm: 37 + """) + dc2 = yaml.load(yaml_str) + assert dc2.xyz == 50 + + def test_yamltag(self) -> None: + from ruamel.yaml import YAML + + yaml = YAML() + + @yaml.register_class + @dataclass + class DC: + yaml_tag: ClassVar = '!dc_example' + abc: int + klm: int + + dc = DC(abc=5, klm=42) + buf = BytesIO() + yaml.dump(dc, buf) + assert buf.getvalue() == dedent("""\ + !dc_example + abc: 5 + klm: 42 + """).encode('utf-8') + dc2 = yaml.load(buf.getvalue()) + assert len(fields(dc2)) == 2 # class var is not a field + assert dc2.abc == dc.abc + assert dc2.klm == dc.klm + + def test_initvar(self) -> None: + from ruamel.yaml import YAML + + yaml = YAML() + + @yaml.register_class + @dataclass + class DC: + abc: int + klm: int + xyz: InitVar[Union[str, None]] = None + + def __post_init__(self, xyz: Union[str, None]) -> None: + # assert xyz == self.xyz # self.xyz is always None + if xyz is not None: + self.klm += len(xyz) + + dc = DC(abc=5, klm=42, xyz='provided') + # this actually doesn't raise an attribute error, I would have expected it not to work + # at all, but it has the default value + assert dc.xyz is None # type: ignore + buf = BytesIO() + yaml.dump(dc, buf) + assert buf.getvalue() == dedent("""\ + !DC + abc: 5 + klm: 50 + """).encode('utf-8') + + yaml_str = dedent("""\ + !DC + abc: 18 + klm: 55 + xyz: some string + """) + dc2 = yaml.load(yaml_str) + assert dc2.xyz is None + assert dc2.klm == 55 + len('some string') + + def test_initvar_not_in_yaml(self) -> None: + from ruamel.yaml import YAML + + yaml = YAML() + + @yaml.register_class + @dataclass + class DC: + abc: int + klm: int + xyz: InitVar[Union[str, None]] = 'hello' + + def __post_init__(self, xyz: Union[str, None]) -> None: + # assert xyz == self.xyz # self.xyz is always None + if xyz is not None: + self.klm += len(xyz) + + dc = DC(abc=5, klm=42, xyz='provided') + assert dc.abc == 5 + assert dc.xyz == 'hello' # type: ignore + buf = BytesIO() + yaml.dump(dc, buf) + assert buf.getvalue() == dedent("""\ + !DC + abc: 5 + klm: 50 + """).encode('utf-8') + + yaml_str = dedent("""\ + !DC + abc: 18 + klm: 55 + """) + dc2 = yaml.load(yaml_str) + assert dc2.xyz == 'hello' + assert dc2.klm == 55 + len('hello') diff --git a/_test/test_indentation.py b/_test/test_indentation.py index 995c3b3..2b2f005 100644 --- a/_test/test_indentation.py +++ b/_test/test_indentation.py @@ -211,7 +211,7 @@ def test_00(self) -> None: package Pine (itself now available under the Apache License as Alpine). """ round_trip( - inp, indent=4, block_seq_indent=2, top_level_colon_align=True, prefix_colon=' ' + inp, indent=4, block_seq_indent=2, top_level_colon_align=True, prefix_colon=' ', ) diff --git a/_test/test_issues.py b/_test/test_issues.py index fd7160b..d6376c2 100644 --- a/_test/test_issues.py +++ b/_test/test_issues.py @@ -28,7 +28,7 @@ def test_issue_61(self) -> None: key: value comb: <<: *ANCHOR - """ + """, ) data = round_trip_load(s) assert str(data['comb']) == str(data['def']) @@ -89,7 +89,7 @@ def test_issue_102(self) -> None: var3: {} #empty object var4: {a: 1} #filled object var5: [] #empty array - """ + """, ) x = round_trip(yaml_str, preserve_quotes=True) # NOQA @@ -121,7 +121,7 @@ def test_issue_160(self) -> None: foo: 32 bar: 32 - """ + """, ) a = round_trip_load(s) del a['root'][0]['some_key'] @@ -135,7 +135,7 @@ def test_issue_160(self) -> None: foo: 32 bar: 32 - """ + """, ) assert buf.getvalue() == exp @@ -145,7 +145,7 @@ def test_issue_161(self) -> None: mapping-A: key-A:{} mapping-B: - """ + """, ) for comment in ['', ' # no-newline', ' # some comment\n', '\n']: s = yaml_str.format(comment) @@ -157,7 +157,7 @@ def test_issue_161a(self) -> None: mapping-A: key-A:{} mapping-B: - """ + """, ) for comment in ['\n# between']: s = yaml_str.format(comment) @@ -169,7 +169,7 @@ def test_issue_163(self) -> None: some-list: # List comment - {} - """ + """, ) x = round_trip(s, preserve_quotes=True) # NOQA @@ -203,7 +203,7 @@ def test_issue_176_preserve_comments_on_extended_slice_assignment(self) -> None: - d - e # comment - """ + """, ) seq = round_trip_load(yaml_str) seq[1::2] = ['B', 'D'] @@ -267,7 +267,7 @@ def test_issue_184(self) -> None: # test foo: bar: baz - """ + """, ) d = round_trip_load(yaml_str) d['bar'] = 'foo' @@ -278,7 +278,7 @@ def test_issue_219(self) -> None: yaml_str = dedent( """\ [StackName: AWS::StackName] - """ + """, ) d = round_trip_load(yaml_str) # NOQA @@ -287,7 +287,7 @@ def test_issue_219a(self) -> None: """\ [StackName: AWS::StackName] - """ + """, ) d = round_trip_load(yaml_str) # NOQA @@ -324,7 +324,7 @@ def test_issue_221_sort(self) -> None: - c # 3 - e # 5 - b # 2 - """ + """, ) a = yaml.load(dedent(inp)) a.sort() @@ -337,7 +337,7 @@ def test_issue_221_sort(self) -> None: - c # 3 - d - e # 5 - """ + """, ) assert buf.getvalue() == exp @@ -353,7 +353,7 @@ def test_issue_221_sort_reverse(self) -> None: - c # 3 - e # 5 - b # 2 - """ + """, ) a = yaml.load(dedent(inp)) a.sort(reverse=True) @@ -366,7 +366,7 @@ def test_issue_221_sort_reverse(self) -> None: - c # 3 - b # 2 - a # 1 - """ + """, ) assert buf.getvalue() == exp @@ -382,7 +382,7 @@ def test_issue_221_sort_key(self) -> None: - Three # 3 - five # 5 - two # 2 - """ + """, ) a = yaml.load(dedent(inp)) a.sort(key=str.lower) @@ -395,7 +395,7 @@ def test_issue_221_sort_key(self) -> None: - One # 1 - Three # 3 - two # 2 - """ + """, ) assert buf.getvalue() == exp @@ -411,7 +411,7 @@ def test_issue_221_sort_key_reverse(self) -> None: - Three # 3 - five # 5 - two # 2 - """ + """, ) a = yaml.load(dedent(inp)) a.sort(key=str.lower, reverse=True) @@ -424,7 +424,7 @@ def test_issue_221_sort_key_reverse(self) -> None: - One # 1 - four - five # 5 - """ + """, ) assert buf.getvalue() == exp @@ -480,7 +480,7 @@ def test_issue_234(self) -> None: cmd: > foo bar foo bar - """ + """, ) yaml = YAML(typ='safe', pure=True) data = yaml.load(inp) @@ -582,7 +582,7 @@ def test_issue_249(self) -> None: - 1 - 2 - 3 - """ + """, ) exp = dedent( """\ @@ -590,7 +590,7 @@ def test_issue_249(self) -> None: - - 1 - 2 - 3 - """ + """, ) yaml.round_trip(inp, outp=exp) # NOQA @@ -619,7 +619,7 @@ def test_issue_279(self) -> None: # ATLAS EWK - {dataset: ATLASWZRAP36PB, frac: 1.0} - {dataset: ATLASZHIGHMASS49FB, frac: 1.0} - """ + """, ) a = yaml.load(inp) buf = StringIO() @@ -658,7 +658,7 @@ def test_issue_284(self) -> None: : # Both empty "quoted key": - entry - """ + """, ) yaml = ruamel.yaml.YAML(typ='rt') yaml.version = (1, 2) @@ -682,7 +682,7 @@ def test_issue_285(self) -> None: - n - Y - N - """ + """, ) a = yaml.load(inp) assert a[0] @@ -700,7 +700,7 @@ def test_issue_286(self) -> None: parent_key: - sub_key: sub_value - # xxx""" + # xxx""", ) a = yaml.load(inp) a['new_key'] = 'new_value' @@ -728,7 +728,7 @@ def test_issue_288(self) -> None: - &thirdEntry Third entry # EOF Comment - """ + """, ) yaml = YAML() @@ -761,7 +761,7 @@ def test_issue_288a(self) -> None: - &thirdEntry Third entry # EOF Comment - """ + """, ) yaml = YAML() @@ -799,7 +799,7 @@ def test_issue_290(self) -> None: # Plain-element comment - &plainEntry Plain entry - """ + """, ) yaml = YAML() @@ -837,7 +837,7 @@ def test_issue_290a(self) -> None: # Plain-element comment - &plainEntry Plain entry - """ + """, ) yaml = YAML() @@ -872,7 +872,7 @@ def test_issue_295(self) -> None: - - l31 - l32 - l33: '5' - """ + """, ) data = round_trip_load(inp) # NOQA dc = copy.deepcopy(data) @@ -887,7 +887,7 @@ def test_issue_300(self) -> None: %TAG ! tag:example.com,2019/path#fragment --- null - """ + """, ) YAML().load(inp) @@ -900,11 +900,11 @@ def test_issue_300a(self) -> None: %TAG ! tag:example.com,2019/path#fragment --- null - """ + """, ) yaml = YAML() with pytest.raises( - ruamel.yaml.scanner.ScannerError, match='while scanning a directive' + ruamel.yaml.scanner.ScannerError, match='while scanning a directive', ): yaml.load(inp) @@ -994,7 +994,7 @@ def test_issue_453(self) -> None: usage: <<: [*anchor, *anchor2] usage-key: usage-value - """ + """, ) yaml = YAML() data = yaml.load(inp) @@ -1022,7 +1022,7 @@ def test_so_75631454(self) -> None: test: long: "This is a sample text across two lines." - """ + """, ) yaml = YAML() yaml.preserve_quotes = True @@ -1078,8 +1078,8 @@ def test_issue_459(self) -> None: x: 20cm y: 20cm radius: 2.24cm - """ - ) + """, + ), } yaml = YAML() yaml.width = 60 @@ -1098,7 +1098,7 @@ def test_issue_461(self) -> None: first name: Roy last name: Rogers city: somewhere - """ + """, ) yaml = YAML() data = yaml.load(inp) @@ -1116,7 +1116,7 @@ def test_issue_463(self) -> None: inp = dedent( """ first_name: Art - """ + """, ) data = yaml.load(inp) _ = data.merge @@ -1128,7 +1128,7 @@ def test_issue_463(self) -> None: """ some_key: test first_name: Art - """ + """, ) assert buf.getvalue() == exp diff --git a/_test/test_spec_examples.py b/_test/test_spec_examples.py index 96c4a4d..9e14a15 100644 --- a/_test/test_spec_examples.py +++ b/_test/test_spec_examples.py @@ -233,7 +233,7 @@ def test_example_2_16() -> None: @pytest.mark.xfail( # type: ignore - strict=True, reason='cannot YAML dump escape sequences (\n) as hex and normal' + strict=True, reason='cannot YAML dump escape sequences (\n) as hex and normal', ) def test_example_2_17() -> None: yaml = YAML() diff --git a/_test/test_string.py b/_test/test_string.py index 910e38c..cf826f7 100644 --- a/_test/test_string.py +++ b/_test/test_string.py @@ -32,7 +32,7 @@ def test_quoted_integer_string(self) -> None: """) @pytest.mark.skipif( # type: ignore - platform.python_implementation() == 'Jython', reason='Jython throws RepresenterError' + platform.python_implementation() == 'Jython', reason='Jython throws RepresenterError', ) def test_preserve_string(self) -> None: inp = """ @@ -43,7 +43,7 @@ def test_preserve_string(self) -> None: round_trip(inp, intermediate=dict(a='abc\ndef\n')) @pytest.mark.skipif( # type: ignore - platform.python_implementation() == 'Jython', reason='Jython throws RepresenterError' + platform.python_implementation() == 'Jython', reason='Jython throws RepresenterError', ) def test_preserve_string_strip(self) -> None: s = """ @@ -55,7 +55,7 @@ def test_preserve_string_strip(self) -> None: round_trip(s, intermediate=dict(a='abc\ndef')) @pytest.mark.skipif( # type: ignore - platform.python_implementation() == 'Jython', reason='Jython throws RepresenterError' + platform.python_implementation() == 'Jython', reason='Jython throws RepresenterError', ) def test_preserve_string_keep(self) -> None: # with pytest.raises(AssertionError) as excinfo: @@ -70,7 +70,7 @@ def test_preserve_string_keep(self) -> None: round_trip(inp, intermediate=dict(a='ghi\njkl\n\n\n', b='x')) @pytest.mark.skipif( # type: ignore - platform.python_implementation() == 'Jython', reason='Jython throws RepresenterError' + platform.python_implementation() == 'Jython', reason='Jython throws RepresenterError', ) def test_preserve_string_keep_at_end(self) -> None: # at EOF you have to specify the ... to get proper "closure" diff --git a/_test/test_tag.py b/_test/test_tag.py index 4f0587f..4cd96ac 100644 --- a/_test/test_tag.py +++ b/_test/test_tag.py @@ -32,7 +32,7 @@ def test_tag(self) -> None: name: Anthon location: Germany language: python - """ + """, ) def test_full_tag(self) -> None: @@ -42,7 +42,7 @@ def test_full_tag(self) -> None: name: Anthon location: Germany language: python - """ + """, ) def test_standard_tag(self) -> None: @@ -52,7 +52,7 @@ def test_standard_tag(self) -> None: name: Anthon location: Germany language: python - """ + """, ) def test_Y1(self) -> None: @@ -62,7 +62,7 @@ def test_Y1(self) -> None: name: Anthon location: Germany language: python - """ + """, ) def test_Y2(self) -> None: @@ -72,7 +72,7 @@ def test_Y2(self) -> None: name: Anthon location: Germany language: python - """ + """, ) # @pytest.mark.xfail(strict=True) # type: ignore @@ -88,7 +88,7 @@ def test_spec_6_26_tag_shorthands(self) -> None: - !local foo - !!str bar - !e!tag%21 baz - """ + """, ) yaml = YAML() data = yaml.load(inp) @@ -108,7 +108,7 @@ def test_unknow_handle(self) -> None: %TAG !x! tag:example.com,2000:app/ --- - !y!tag%21 baz - """ + """, ) @@ -121,7 +121,7 @@ def test_X1(self) -> None: name: Anthon location: Germany language: python - """ + """, ) @pytest.mark.xfail(strict=True) # type: ignore @@ -135,7 +135,7 @@ def test_X_pre_tag_comment(self) -> None: name: Anthon location: Germany language: python - """ + """, ) @pytest.mark.xfail(strict=True) # type: ignore @@ -148,7 +148,7 @@ def test_X_post_tag_comment(self) -> None: name: Anthon location: Germany language: python - """ + """, ) def test_scalar_00(self) -> None: @@ -160,7 +160,7 @@ def test_scalar_00(self) -> None: Value: !Ref: vpc # first tag Export: Name: !Sub "${AWS::StackName}-Vpc" # second tag - """ + """, ) @@ -169,7 +169,7 @@ def test_encoded_unicode_tag(self) -> None: round_trip_load( """ s: !!python/%75nicode 'abc' - """ + """, ) @@ -183,7 +183,7 @@ def test_scalar(self) -> None: - !SBool true - !SLit | glitter in the dark near the Tanhäuser gate - """ + """, ) # tagged scalers have string or string types as value assert data[0].count('d') == 1 @@ -196,7 +196,7 @@ def test_mapping(self) -> None: round_trip( """\ - !Mapping {a: 1, b: 2} - """ + """, ) def test_sequence(self) -> None: @@ -206,7 +206,7 @@ def test_sequence(self) -> None: yaml.round_trip( """ - !Sequence [a, {b: 1}, {c: {d: 3}}] - """ + """, ) def test_sequence2(self) -> None: @@ -215,5 +215,5 @@ def test_sequence2(self) -> None: yaml.round_trip( """ - !Sequence [a, b: 1, c: {d: 3}] - """ + """, ) diff --git a/_test/test_yamlfile.py b/_test/test_yamlfile.py index 47ab407..ffee9f2 100644 --- a/_test/test_yamlfile.py +++ b/_test/test_yamlfile.py @@ -89,7 +89,7 @@ def test_set_out(self) -> None: # preferable would be the shorter format without the ': null' import ruamel.yaml # NOQA - x = set(['a', 'b', 'c']) + x = set(['a', 'b', 'c']) # NOQA # cannot use round_trip_dump, it doesn't show null in block style buf = io.StringIO() yaml = ruamel.yaml.YAML(typ='unsafe', pure=True) @@ -131,7 +131,7 @@ def test_blank_line_between_seq_items(self) -> None: """) @pytest.mark.skipif( # type: ignore - platform.python_implementation() == 'Jython', reason='Jython throws RepresenterError' + platform.python_implementation() == 'Jython', reason='Jython throws RepresenterError', ) def test_blank_line_after_literal_chip(self) -> None: s = """ @@ -155,7 +155,7 @@ def test_blank_line_after_literal_chip(self) -> None: assert d['c'][1].split('line.')[1] == '\n' @pytest.mark.skipif( # type: ignore - platform.python_implementation() == 'Jython', reason='Jython throws RepresenterError' + platform.python_implementation() == 'Jython', reason='Jython throws RepresenterError', ) def test_blank_line_after_literal_keep(self) -> None: """ have to insert an eof marker in YAML to test this""" @@ -181,7 +181,7 @@ def test_blank_line_after_literal_keep(self) -> None: assert d['c'][1].split('line.')[1] == '\n\n\n' @pytest.mark.skipif( # type: ignore - platform.python_implementation() == 'Jython', reason='Jython throws RepresenterError' + platform.python_implementation() == 'Jython', reason='Jython throws RepresenterError', ) def test_blank_line_after_literal_strip(self) -> None: s = """ diff --git a/_test/test_z_data.py b/_test/test_z_data.py index b78f732..1f31f4f 100644 --- a/_test/test_z_data.py +++ b/_test/test_z_data.py @@ -118,7 +118,7 @@ def pytest_generate_tests(metafunc: Any) -> None: class TestYAMLData: def yaml( - self, yaml_version: Optional[Any] = None, typ: Any = 'rt', pure: Any = None + self, yaml_version: Optional[Any] = None, typ: Any = 'rt', pure: Any = None, ) -> Any: from ruamel.yaml import YAML @@ -149,7 +149,7 @@ def yaml_load(self, value: Any, yaml_version: Optional[Any] = None) -> Tuple[Any return yaml, data def round_trip( - self, input: Any, output: Optional[Any] = None, yaml_version: Optional[Any] = None + self, input: Any, output: Optional[Any] = None, yaml_version: Optional[Any] = None, ) -> None: from ruamel.yaml.compat import StringIO @@ -162,7 +162,7 @@ def round_trip( assert value == expected def gen_events( - self, input: Any, output: Any, yaml_version: Optional[Any] = None + self, input: Any, output: Any, yaml_version: Optional[Any] = None, ) -> None: from ruamel.yaml.compat import StringIO @@ -187,7 +187,7 @@ def gen_events( assert buf.getvalue() == output.value def load_compare_json( - self, input: Any, output: Any, yaml_version: Optional[Any] = None + self, input: Any, output: Any, yaml_version: Optional[Any] = None, ) -> None: import json from ruamel.yaml.compat import StringIO @@ -195,7 +195,7 @@ def load_compare_json( def serialize_obj(obj: Any) -> Any: if isinstance(obj, CommentedMap): - return {k: v for k, v in obj.items()} + return {k: v for k, v in obj.items()} # NOQA elif isinstance(obj, TaggedScalar): return str(obj.value) elif isinstance(obj, set): @@ -214,7 +214,7 @@ def serialize_obj(obj: Any) -> Any: assert buf.getvalue() == output.value def load_compare_emit( - self, input: Any, output: Any, yaml_version: Optional[Any] = None + self, input: Any, output: Any, yaml_version: Optional[Any] = None, ) -> None: from ruamel.yaml.compat import StringIO @@ -230,7 +230,7 @@ def load_compare_emit( assert buf.getvalue() == output.value def load_assert( - self, input: Any, confirm: Any, yaml_version: Optional[Any] = None + self, input: Any, confirm: Any, yaml_version: Optional[Any] = None, ) -> None: from collections.abc import Mapping @@ -251,7 +251,7 @@ def load_assert( exec(line) def run_python( - self, python: Any, data: Any, tmpdir: Any, input: Optional[Any] = None + self, python: Any, data: Any, tmpdir: Any, input: Optional[Any] = None, ) -> None: from roundtrip import save_and_run # type: ignore @@ -347,7 +347,7 @@ def test_yaml_data(self, yaml: Any, tmpdir: Any) -> None: elif typ == 'python_run': inp = None if output is None or data is None else data self.run_python( - python, output if output is not None else data, tmpdir, input=inp + python, output if output is not None else data, tmpdir, input=inp, ) elif typ == 'load_assert': self.load_assert(data, confirm, yaml_version=yaml_version) diff --git a/comments.py b/comments.py index 0360654..4aea3c7 100644 --- a/comments.py +++ b/comments.py @@ -367,7 +367,7 @@ def fa(self) -> Any: return getattr(self, Format.attrib) def yaml_add_eol_comment( - self, comment: Any, key: Optional[Any] = NotNone, column: Optional[Any] = None + self, comment: Any, key: Optional[Any] = NotNone, column: Optional[Any] = None, ) -> None: """ there is a problem as eol comments should start with ' #' @@ -563,7 +563,7 @@ def sort(self, key: Any = None, reverse: bool = False) -> None: list.__init__(self, [x[0] for x in tmp_lst]) else: tmp_lst = sorted( - zip(map(key, list.__iter__(self)), range(len(self))), reverse=reverse + zip(map(key, list.__iter__(self)), range(len(self))), reverse=reverse, ) list.__init__(self, [list.__getitem__(self, x[1]) for x in tmp_lst]) itm = self.ca.items @@ -701,7 +701,7 @@ def __init__(self, *args: Any, **kw: Any) -> None: ordereddict.__init__(self, *args, **kw) def _yaml_add_comment( - self, comment: Any, key: Optional[Any] = NotNone, value: Optional[Any] = NotNone + self, comment: Any, key: Optional[Any] = NotNone, value: Optional[Any] = NotNone, ) -> None: """values is set to key to indicate a value attachment of comment""" if key is not NotNone: @@ -1085,7 +1085,7 @@ def __init__(self, values: Any = None) -> None: self |= values def _yaml_add_comment( - self, comment: Any, key: Optional[Any] = NotNone, value: Optional[Any] = NotNone + self, comment: Any, key: Optional[Any] = NotNone, value: Optional[Any] = NotNone, ) -> None: """values is set to key to indicate a value attachment of comment""" if key is not NotNone: @@ -1159,5 +1159,5 @@ def dump_comments(d: Any, name: str = "", sep: str = '.', out: Any = sys.stdout) 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 + k, name=(name + sep + str(idx)) if name else str(idx), sep=sep, out=out, ) diff --git a/compat.py b/compat.py index c32d105..c427246 100644 --- a/compat.py +++ b/compat.py @@ -47,9 +47,6 @@ def insert(self, pos: int, key: Any, value: Any) -> None: self[old_key] = od[old_key] -PY2 = sys.version_info[0] == 2 -PY3 = sys.version_info[0] == 3 - StringIO = io.StringIO BytesIO = io.BytesIO @@ -209,11 +206,11 @@ def __setitem__(self, index: Any, value: Any) -> None: # need to test before changing, in case TypeError is caught if nr_assigned_items < len(value): raise TypeError( - f'too many elements in value {nr_assigned_items} < {len(value)}' + f'too many elements in value {nr_assigned_items} < {len(value)}', ) elif nr_assigned_items > len(value): raise TypeError( - f'not enough elements in value {nr_assigned_items} > {len(value)}' + f'not enough elements in value {nr_assigned_items} > {len(value)}', ) for idx, i in enumerate(range(*range_parms)): self[i] = value[idx] diff --git a/composer.py b/composer.py index e876bdc..3802d94 100644 --- a/composer.py +++ b/composer.py @@ -175,7 +175,7 @@ def compose_sequence_node(self, anchor: Any) -> Any: if node.comment is not None: x = node.flow_style nprint( - f'Warning: unexpected end_event commment in sequence node {x}' + f'Warning: unexpected end_event commment in sequence node {x}', ) node.comment = end_event.comment node.end_mark = end_event.end_mark diff --git a/configobjwalker.py b/configobjwalker.py index a6faa88..28318f1 100644 --- a/configobjwalker.py +++ b/configobjwalker.py @@ -10,6 +10,6 @@ def configobj_walker(cfg: Any) -> Any: warnings.warn( 'configobj_walker has moved to ruamel.yaml.util, please update your code', - stacklevel=2 + stacklevel=2, ) return new_configobj_walker(cfg) diff --git a/constructor.py b/constructor.py index 0054620..6f65b0b 100644 --- a/constructor.py +++ b/constructor.py @@ -26,7 +26,7 @@ ) from ruamel.yaml.scalarstring import (SingleQuotedScalarString, DoubleQuotedScalarString, LiteralScalarString, FoldedScalarString, - PlainScalarString, ScalarString,) + PlainScalarString, ScalarString) from ruamel.yaml.scalarint import ScalarInt, BinaryInt, OctalInt, HexInt, HexCapsInt from ruamel.yaml.scalarfloat import ScalarFloat from ruamel.yaml.scalarbool import ScalarBoolean @@ -248,7 +248,7 @@ def construct_mapping(self, node: Any, deep: bool = False) -> Any: return total_mapping def check_mapping_key( - self, node: Any, key_node: Any, mapping: Any, key: Any, value: Any + self, node: Any, key_node: Any, mapping: Any, key: Any, value: Any, ) -> bool: """return True if key is unique""" if key in mapping: @@ -322,6 +322,16 @@ def add_multi_constructor(cls, tag_prefix: Any, multi_constructor: Any) -> None: cls.yaml_multi_constructors = cls.yaml_multi_constructors.copy() cls.yaml_multi_constructors[tag_prefix] = multi_constructor + @classmethod + def add_default_constructor( + cls, tag: str, method: Any = None, tag_base: str = 'tag:yaml.org,2002:', + ) -> None: + if not tag.startswith('tag:'): + if method is None: + method = 'construct_yaml_' + tag + tag = tag_base + tag + cls.add_constructor(tag, getattr(cls, method)) + class SafeConstructor(BaseConstructor): def construct_scalar(self, node: Any) -> Any: @@ -631,37 +641,8 @@ def construct_undefined(self, node: Any) -> None: ) -SafeConstructor.add_constructor('tag:yaml.org,2002:null', SafeConstructor.construct_yaml_null) - -SafeConstructor.add_constructor('tag:yaml.org,2002:bool', SafeConstructor.construct_yaml_bool) - -SafeConstructor.add_constructor('tag:yaml.org,2002:int', SafeConstructor.construct_yaml_int) - -SafeConstructor.add_constructor( - 'tag:yaml.org,2002:float', SafeConstructor.construct_yaml_float -) - -SafeConstructor.add_constructor( - 'tag:yaml.org,2002:binary', SafeConstructor.construct_yaml_binary -) - -SafeConstructor.add_constructor( - 'tag:yaml.org,2002:timestamp', SafeConstructor.construct_yaml_timestamp -) - -SafeConstructor.add_constructor('tag:yaml.org,2002:omap', SafeConstructor.construct_yaml_omap) - -SafeConstructor.add_constructor( - 'tag:yaml.org,2002:pairs', SafeConstructor.construct_yaml_pairs -) - -SafeConstructor.add_constructor('tag:yaml.org,2002:set', SafeConstructor.construct_yaml_set) - -SafeConstructor.add_constructor('tag:yaml.org,2002:str', SafeConstructor.construct_yaml_str) - -SafeConstructor.add_constructor('tag:yaml.org,2002:seq', SafeConstructor.construct_yaml_seq) - -SafeConstructor.add_constructor('tag:yaml.org,2002:map', SafeConstructor.construct_yaml_map) +for tag in 'null bool int float binary timestamp omap pairs set str seq map'.split(): + SafeConstructor.add_default_constructor(tag) SafeConstructor.add_constructor(None, SafeConstructor.construct_undefined) @@ -790,7 +771,7 @@ def construct_python_module(self, suffix: Any, node: Any) -> Any: return self.find_python_module(suffix, node.start_mark) def make_python_instance( - self, suffix: Any, node: Any, args: Any = None, kwds: Any = None, newobj: bool = False + self, suffix: Any, node: Any, args: Any = None, kwds: Any = None, newobj: bool = False, ) -> Any: if not args: args = [] @@ -827,7 +808,7 @@ def construct_python_object(self, suffix: Any, node: Any) -> Any: self.set_python_instance_state(instance, state) def construct_python_object_apply( - self, suffix: Any, node: Any, newobj: bool = False + self, suffix: Any, node: Any, newobj: bool = False, ) -> Any: # Format: # !!python/object/apply # (or !!python/object/new) @@ -866,6 +847,16 @@ def construct_python_object_apply( def construct_python_object_new(self, suffix: Any, node: Any) -> Any: return self.construct_python_object_apply(suffix, node, newobj=True) + @classmethod + def add_default_constructor( + cls, tag: str, method: Any = None, tag_base: str = 'tag:yaml.org,2002:python/', + ) -> None: + if not tag.startswith('tag:'): + if method is None: + method = 'construct_yaml_' + tag + tag = tag_base + tag + cls.add_constructor(tag, getattr(cls, method)) + Constructor.add_constructor('tag:yaml.org,2002:python/none', Constructor.construct_yaml_null) @@ -874,11 +865,11 @@ def construct_python_object_new(self, suffix: Any, node: Any) -> Any: Constructor.add_constructor('tag:yaml.org,2002:python/str', Constructor.construct_python_str) Constructor.add_constructor( - 'tag:yaml.org,2002:python/unicode', Constructor.construct_python_unicode + 'tag:yaml.org,2002:python/unicode', Constructor.construct_python_unicode, ) Constructor.add_constructor( - 'tag:yaml.org,2002:python/bytes', Constructor.construct_python_bytes + 'tag:yaml.org,2002:python/bytes', Constructor.construct_python_bytes, ) Constructor.add_constructor('tag:yaml.org,2002:python/int', Constructor.construct_yaml_int) @@ -888,35 +879,37 @@ def construct_python_object_new(self, suffix: Any, node: Any) -> Any: Constructor.add_constructor('tag:yaml.org,2002:python/float', Constructor.construct_yaml_float) Constructor.add_constructor( - 'tag:yaml.org,2002:python/complex', Constructor.construct_python_complex + 'tag:yaml.org,2002:python/complex', Constructor.construct_python_complex, ) Constructor.add_constructor('tag:yaml.org,2002:python/list', Constructor.construct_yaml_seq) Constructor.add_constructor( - 'tag:yaml.org,2002:python/tuple', Constructor.construct_python_tuple + 'tag:yaml.org,2002:python/tuple', Constructor.construct_python_tuple, ) +# for tag in 'bool str unicode bytes int long float complex tuple'.split(): +# Constructor.add_default_constructor(tag) Constructor.add_constructor('tag:yaml.org,2002:python/dict', Constructor.construct_yaml_map) Constructor.add_multi_constructor( - 'tag:yaml.org,2002:python/name:', Constructor.construct_python_name + 'tag:yaml.org,2002:python/name:', Constructor.construct_python_name, ) Constructor.add_multi_constructor( - 'tag:yaml.org,2002:python/module:', Constructor.construct_python_module + 'tag:yaml.org,2002:python/module:', Constructor.construct_python_module, ) Constructor.add_multi_constructor( - 'tag:yaml.org,2002:python/object:', Constructor.construct_python_object + 'tag:yaml.org,2002:python/object:', Constructor.construct_python_object, ) Constructor.add_multi_constructor( - 'tag:yaml.org,2002:python/object/apply:', Constructor.construct_python_object_apply + 'tag:yaml.org,2002:python/object/apply:', Constructor.construct_python_object_apply, ) Constructor.add_multi_constructor( - 'tag:yaml.org,2002:python/object/new:', Constructor.construct_python_object_new + 'tag:yaml.org,2002:python/object/new:', Constructor.construct_python_object_new, ) @@ -1065,10 +1058,7 @@ def construct_yaml_int(self, node: Any) -> Any: ) elif self.resolver.processing_version != (1, 2) and value_s[0] == '0': return OctalInt( - sign * int(value_s, 8), - width=width, - underscore=underscore, - anchor=node.anchor, + sign * int(value_s, 8), width=width, underscore=underscore, anchor=node.anchor, ) elif self.resolver.processing_version != (1, 2) and ':' in value_s: digits = [int(part) for part in value_s.split(':')] @@ -1089,7 +1079,7 @@ def construct_yaml_int(self, node: Any) -> Any: # cannot have a leading underscore underscore[2] = len(value_su) > 1 and value_su[-1] == '_' return ScalarInt( - sign * int(value_s), width=None, underscore=underscore, anchor=node.anchor + 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) @@ -1213,7 +1203,7 @@ def construct_rt_sequence(self, node: Any, seqtyp: Any, deep: bool = False) -> A child.comment = None # if moved to sequence remove from child ret_val.append(self.construct_object(child, deep=deep)) seqtyp._yaml_set_idx_line_col( - idx, [child.start_mark.line, child.start_mark.column] + idx, [child.start_mark.line, child.start_mark.column], ) return ret_val @@ -1482,11 +1472,33 @@ def set_collection_style(self, data: Any, node: Any) -> None: data.fa.set_block_style() def construct_yaml_object(self, node: Any, cls: Any) -> Any: + from dataclasses import is_dataclass, InitVar, MISSING + data = cls.__new__(cls) yield data if hasattr(data, '__setstate__'): state = SafeConstructor.construct_mapping(self, node, deep=True) data.__setstate__(state) + elif is_dataclass(data): + mapping = SafeConstructor.construct_mapping(self, node) + init_var_defaults = {} + for field in data.__dataclass_fields__.values(): + # nprintf('field', field, field.default is MISSING, + # isinstance(field.type, InitVar)) + # in 3.7, InitVar is a singleton + if ( + isinstance(field.type, InitVar) or field.type is InitVar + ) and field.default is not MISSING: + init_var_defaults[field.name] = field.default + for attr, value in mapping.items(): + if attr not in init_var_defaults: + setattr(data, attr, value) + post_init = getattr(data, '__post_init__', None) + if post_init is not None: + kw = {} + for name, default in init_var_defaults.items(): + kw[name] = mapping.get(name, default) + post_init(**kw) else: state = SafeConstructor.construct_mapping(self, node) if hasattr(data, '__attrs_attrs__'): # issue 394 @@ -1573,7 +1585,7 @@ def construct_yaml_set(self, node: Any) -> Iterator[CommentedSet]: self.construct_setting(node, data) def construct_unknown( - self, node: Any + self, node: Any, ) -> Iterator[Union[CommentedMap, TaggedScalar, CommentedSeq]]: try: if isinstance(node, MappingNode): @@ -1630,7 +1642,7 @@ def construct_unknown( ) def construct_yaml_timestamp( - self, node: Any, values: Any = None + self, node: Any, values: Any = None, ) -> Union[datetime.date, datetime.datetime, TimeStamp]: try: match = self.timestamp_regexp.match(node.value) @@ -1666,7 +1678,7 @@ def construct_yaml_timestamp( # isinstance(datetime.datetime.now, datetime.date) is true) if isinstance(dd, datetime.datetime): data = TimeStamp( - dd.year, dd.month, dd.day, dd.hour, dd.minute, dd.second, dd.microsecond + dd.year, dd.month, dd.day, dd.hour, dd.minute, dd.second, dd.microsecond, ) else: # ToDo: make this into a DateStamp? @@ -1692,52 +1704,9 @@ def construct_yaml_sbool(self, node: Any) -> Union[bool, ScalarBoolean]: return b -RoundTripConstructor.add_constructor( - 'tag:yaml.org,2002:null', RoundTripConstructor.construct_yaml_null -) - -RoundTripConstructor.add_constructor( - 'tag:yaml.org,2002:bool', RoundTripConstructor.construct_yaml_sbool -) - -RoundTripConstructor.add_constructor( - 'tag:yaml.org,2002:int', RoundTripConstructor.construct_yaml_int -) - -RoundTripConstructor.add_constructor( - 'tag:yaml.org,2002:float', RoundTripConstructor.construct_yaml_float -) - -RoundTripConstructor.add_constructor( - 'tag:yaml.org,2002:binary', RoundTripConstructor.construct_yaml_binary -) - -RoundTripConstructor.add_constructor( - 'tag:yaml.org,2002:timestamp', RoundTripConstructor.construct_yaml_timestamp -) +RoundTripConstructor.add_default_constructor('bool', method='construct_yaml_sbool') -RoundTripConstructor.add_constructor( - 'tag:yaml.org,2002:omap', RoundTripConstructor.construct_yaml_omap -) - -RoundTripConstructor.add_constructor( - 'tag:yaml.org,2002:pairs', RoundTripConstructor.construct_yaml_pairs -) - -RoundTripConstructor.add_constructor( - 'tag:yaml.org,2002:set', RoundTripConstructor.construct_yaml_set -) - -RoundTripConstructor.add_constructor( - 'tag:yaml.org,2002:str', RoundTripConstructor.construct_yaml_str -) - -RoundTripConstructor.add_constructor( - 'tag:yaml.org,2002:seq', RoundTripConstructor.construct_yaml_seq -) - -RoundTripConstructor.add_constructor( - 'tag:yaml.org,2002:map', RoundTripConstructor.construct_yaml_map -) +for tag in 'null int float binary timestamp omap pairs set str seq map'.split(): + RoundTripConstructor.add_default_constructor(tag) RoundTripConstructor.add_constructor(None, RoundTripConstructor.construct_unknown) diff --git a/cyaml.py b/cyaml.py index 09d6480..3f15ffc 100644 --- a/cyaml.py +++ b/cyaml.py @@ -148,7 +148,7 @@ def __init__( ) self._emitter = self._serializer = self._representer = self SafeRepresenter.__init__( - self, default_style=default_style, default_flow_style=default_flow_style + self, default_style=default_style, default_flow_style=default_flow_style, ) Resolver.__init__(self) @@ -190,6 +190,6 @@ def __init__( ) self._emitter = self._serializer = self._representer = self Representer.__init__( - self, default_style=default_style, default_flow_style=default_flow_style + self, default_style=default_style, default_flow_style=default_flow_style, ) Resolver.__init__(self) diff --git a/emitter.py b/emitter.py index a068800..d3eb0bb 100644 --- a/emitter.py +++ b/emitter.py @@ -69,7 +69,7 @@ def last_seq(self) -> bool: return False def seq_flow_align( - self, seq_indent: int, column: int, pre_comment: Optional[bool] = False + self, seq_indent: int, column: int, pre_comment: Optional[bool] = False, ) -> int: # extra spaces because of dash # nprint('seq_flow_align', self.values, pre_comment) @@ -97,6 +97,12 @@ class Emitter: # fmt: on MAX_SIMPLE_KEY_LENGTH = 128 + flow_seq_start = '[' + flow_seq_end = ']' + flow_seq_separator = ',' + flow_map_start = '{' + flow_map_end = '}' + flow_map_separator = ',' def __init__( self, @@ -277,7 +283,7 @@ def need_events(self, count: int) -> bool: return len(self.events) < count + 1 def increase_indent( - self, flow: bool = False, sequence: Optional[bool] = None, indentless: bool = False + self, flow: bool = False, sequence: Optional[bool] = None, indentless: bool = False, ) -> None: self.indents.append(self.indent, sequence) if self.indent is None: # top level @@ -450,7 +456,7 @@ def expect_node( or self.check_empty_mapping() ): self.expect_flow_mapping( - single=self.event.nr_items == 1, force_flow_indent=force_flow_indent + single=self.event.nr_items == 1, force_flow_indent=force_flow_indent, ) else: self.expect_block_mapping() @@ -475,9 +481,9 @@ def expect_flow_sequence(self, force_flow_indent: Optional[bool] = False) -> Non if force_flow_indent: self.increase_indent(flow=True, sequence=True) ind = self.indents.seq_flow_align( - self.best_sequence_indent, self.column, force_flow_indent + self.best_sequence_indent, self.column, force_flow_indent, ) - self.write_indicator(' ' * ind + '[', True, whitespace=True) + self.write_indicator(' ' * ind + self.flow_seq_start, True, whitespace=True) if not force_flow_indent: self.increase_indent(flow=True, sequence=True) self.flow_context.append('[') @@ -488,7 +494,7 @@ def expect_first_flow_sequence_item(self) -> None: self.indent = self.indents.pop() popped = self.flow_context.pop() assert popped == '[' - self.write_indicator(']', False) + self.write_indicator(self.flow_seq_end, False) if self.event.comment and self.event.comment[0]: # eol comment on empty flow sequence self.write_post_comment(self.event) @@ -507,9 +513,9 @@ def expect_flow_sequence_item(self) -> None: popped = self.flow_context.pop() assert popped == '[' if self.canonical: - self.write_indicator(',', False) + self.write_indicator(self.flow_seq_separator, False) self.write_indent() - self.write_indicator(']', False) + self.write_indicator(self.flow_seq_end, False) if self.event.comment and self.event.comment[0]: # eol comment on flow sequence self.write_post_comment(self.event) @@ -517,7 +523,7 @@ def expect_flow_sequence_item(self) -> None: self.no_newline = False self.state = self.states.pop() else: - self.write_indicator(',', False) + self.write_indicator(self.flow_seq_separator, False) if self.canonical or self.column > self.best_width: self.write_indent() self.states.append(self.expect_flow_sequence_item) @@ -526,14 +532,14 @@ def expect_flow_sequence_item(self) -> None: # Flow mapping handlers. def expect_flow_mapping( - self, single: Optional[bool] = False, force_flow_indent: Optional[bool] = False + self, single: Optional[bool] = False, force_flow_indent: Optional[bool] = False, ) -> None: if force_flow_indent: self.increase_indent(flow=True, sequence=False) ind = self.indents.seq_flow_align( - self.best_sequence_indent, self.column, force_flow_indent + self.best_sequence_indent, self.column, force_flow_indent, ) - map_init = '{' + map_init = self.flow_map_start if ( single and self.flow_level @@ -554,7 +560,7 @@ def expect_first_flow_mapping_key(self) -> None: self.indent = self.indents.pop() popped = self.flow_context.pop() assert popped == '{' # empty flow mapping - self.write_indicator('}', False) + self.write_indicator(self.flow_map_end, False) if self.event.comment and self.event.comment[0]: # eol comment on empty mapping self.write_post_comment(self.event) @@ -580,10 +586,10 @@ def expect_flow_mapping_key(self) -> None: popped = self.flow_context.pop() assert popped in ['{', ''] if self.canonical: - self.write_indicator(',', False) + self.write_indicator(self.flow_map_separator, False) self.write_indent() if popped != '': - self.write_indicator('}', False) + self.write_indicator(self.flow_map_end, False) if self.event.comment and self.event.comment[0]: # eol comment on flow mapping, never reached on empty mappings self.write_post_comment(self.event) @@ -591,7 +597,7 @@ def expect_flow_mapping_key(self) -> None: self.no_newline = False self.state = self.states.pop() else: - self.write_indicator(',', False) + self.write_indicator(self.flow_map_separator, False) if self.canonical or self.column > self.best_width: self.write_indent() if not self.canonical and self.check_simple_key(): @@ -674,7 +680,7 @@ def expect_block_mapping_key(self, first: Any = False) -> None: self.write_indent() if self.check_simple_key(): if not isinstance( - self.event, (SequenceStartEvent, MappingStartEvent) + self.event, (SequenceStartEvent, MappingStartEvent), ): # sequence keys try: if self.event.style == '?': diff --git a/error.py b/error.py index ccdbf28..4843fdb 100644 --- a/error.py +++ b/error.py @@ -51,7 +51,7 @@ class StringMark(StreamMark): __slots__ = 'name', 'index', 'line', 'column', 'buffer', 'pointer' def __init__( - self, name: Any, index: int, line: int, column: int, buffer: Any, pointer: Any + self, name: Any, index: int, line: int, column: int, buffer: Any, pointer: Any, ) -> None: StreamMark.__init__(self, name, index, line, column) self.buffer = buffer diff --git a/events.py b/events.py index 92e3b3b..a570a0d 100644 --- a/events.py +++ b/events.py @@ -17,7 +17,7 @@ class Event: crepr = 'Unspecified Event' def __init__( - self, start_mark: Any = None, end_mark: Any = None, comment: Any = CommentCheck + self, start_mark: Any = None, end_mark: Any = None, comment: Any = CommentCheck, ) -> None: self.start_mark = start_mark self.end_mark = end_mark @@ -43,7 +43,7 @@ def __repr__(self) -> Any: if SHOW_LINES: arguments.append( f'({self.start_mark.line}:{self.start_mark.column}/' - f'{self.end_mark.line}:{self.end_mark.column})' + f'{self.end_mark.line}:{self.end_mark.column})', ) arguments = ', '.join(arguments) # type: ignore else: @@ -65,7 +65,7 @@ class NodeEvent(Event): __slots__ = ('anchor',) def __init__( - self, anchor: Any, start_mark: Any = None, end_mark: Any = None, comment: Any = None + self, anchor: Any, start_mark: Any = None, end_mark: Any = None, comment: Any = None, ) -> None: Event.__init__(self, start_mark, end_mark, comment) self.anchor = anchor diff --git a/main.py b/main.py index 9068282..92ec817 100644 --- a/main.py +++ b/main.py @@ -177,7 +177,7 @@ def __init__( break if typ_found == 0: raise NotImplementedError( - f'typ "{self.typ}" not recognised (need to install plug-in?)' + f'typ "{self.typ}" not recognised (need to install plug-in?)', ) @property @@ -550,7 +550,7 @@ def serialize_all(self, nodes: Any, stream: Optional[StreamType]) -> Any: raise def dump( - self: Any, data: Union[Path, StreamType], stream: Any = None, *, transform: Any = None + self: Any, data: Union[Path, StreamType], stream: Any = None, *, transform: Any = None, ) -> Any: if self._context_manager: if not self._output: @@ -558,7 +558,7 @@ def dump( if transform is not None: x = self.__class__.__name__ raise TypeError( - f'{x}.dump() in the context manager cannot have transform keyword' + f'{x}.dump() in the context manager cannot have transform keyword', ) self._context_manager.dump(data) else: # old style @@ -567,7 +567,7 @@ def dump( return self.dump_all([data], stream, transform=transform) def dump_all( - self, documents: Any, stream: Union[Path, StreamType], *, transform: Any = None + self, documents: Any, stream: Union[Path, StreamType], *, transform: Any = None, ) -> Any: if self._context_manager: raise NotImplementedError @@ -599,7 +599,7 @@ def Xdump_all(self, documents: Any, stream: Any, *, transform: Any = None) -> An else: stream = BytesIO() serializer, representer, emitter = self.get_serializer_representer_emitter( - stream, tlca + stream, tlca, ) try: self.serializer.open() @@ -691,7 +691,7 @@ def __init__( ) selfx._emitter = selfx._serializer = selfx._representer = selfx self.Representer.__init__( - selfx, default_style=default_style, default_flow_style=default_flow_style + selfx, default_style=default_style, default_flow_style=default_flow_style, ) rslvr.__init__(selfx) @@ -756,7 +756,7 @@ def register_class(self, cls: Any) -> Any: def t_y(representer: Any, data: Any) -> Any: return representer.represent_yaml_object( - tag, data, cls, flow_style=representer.default_flow_style + tag, data, cls, flow_style=representer.default_flow_style, ) self.representer.add_representer(cls, t_y) @@ -956,7 +956,7 @@ def yo_deco(cls: Any) -> Any: def t_y(representer: Any, data: Any) -> Any: return representer.represent_yaml_object( - tag, data, cls, flow_style=representer.default_flow_style + tag, data, cls, flow_style=representer.default_flow_style, ) yml.representer.add_representer(cls, t_y) @@ -1048,7 +1048,7 @@ def compose_all(stream: StreamTextType, Loader: Any = Loader) -> Any: def load( - stream: Any, Loader: Any = None, version: Any = None, preserve_quotes: Any = None + stream: Any, Loader: Any = None, version: Any = None, preserve_quotes: Any = None, ) -> Any: """ Parse the first YAML document in a stream @@ -1074,7 +1074,7 @@ def load( def load_all( - stream: Any, Loader: Any = None, version: Any = None, preserve_quotes: Any = None + stream: Any, Loader: Any = None, version: Any = None, preserve_quotes: Any = None, ) -> Any: # NOQA """ @@ -1250,7 +1250,7 @@ def serialize_all( def serialize( - node: Any, stream: Optional[StreamType] = None, Dumper: Any = Dumper, **kwds: Any + node: Any, stream: Optional[StreamType] = None, Dumper: Any = Dumper, **kwds: Any, ) -> Any: """ Serialize a representation tree into a YAML stream. @@ -1459,7 +1459,7 @@ def add_implicit_resolver( if hasattr(Loader, 'add_implicit_resolver'): Loader.add_implicit_resolver(tag, regexp, first) elif issubclass( - Loader, (BaseLoader, SafeLoader, ruamel.yaml.loader.Loader, RoundTripLoader) + Loader, (BaseLoader, SafeLoader, ruamel.yaml.loader.Loader, RoundTripLoader), ): Resolver.add_implicit_resolver(tag, regexp, first) else: @@ -1468,7 +1468,7 @@ def add_implicit_resolver( if hasattr(Dumper, 'add_implicit_resolver'): Dumper.add_implicit_resolver(tag, regexp, first) elif issubclass( - Dumper, (BaseDumper, SafeDumper, ruamel.yaml.dumper.Dumper, RoundTripDumper) + Dumper, (BaseDumper, SafeDumper, ruamel.yaml.dumper.Dumper, RoundTripDumper), ): Resolver.add_implicit_resolver(tag, regexp, first) else: @@ -1497,7 +1497,7 @@ def add_path_resolver( if hasattr(Loader, 'add_path_resolver'): Loader.add_path_resolver(tag, path, kind) elif issubclass( - Loader, (BaseLoader, SafeLoader, ruamel.yaml.loader.Loader, RoundTripLoader) + Loader, (BaseLoader, SafeLoader, ruamel.yaml.loader.Loader, RoundTripLoader), ): Resolver.add_path_resolver(tag, path, kind) else: @@ -1506,7 +1506,7 @@ def add_path_resolver( if hasattr(Dumper, 'add_path_resolver'): Dumper.add_path_resolver(tag, path, kind) elif issubclass( - Dumper, (BaseDumper, SafeDumper, ruamel.yaml.dumper.Dumper, RoundTripDumper) + Dumper, (BaseDumper, SafeDumper, ruamel.yaml.dumper.Dumper, RoundTripDumper), ): Resolver.add_path_resolver(tag, path, kind) else: @@ -1514,7 +1514,7 @@ def add_path_resolver( def add_constructor( - tag: Any, object_constructor: Any, Loader: Any = None, constructor: Any = Constructor + tag: Any, object_constructor: Any, Loader: Any = None, constructor: Any = Constructor, ) -> None: """ Add an object constructor for the given tag. @@ -1540,7 +1540,7 @@ def add_constructor( def add_multi_constructor( - tag_prefix: Any, multi_constructor: Any, Loader: Any = None, constructor: Any = Constructor + tag_prefix: Any, multi_constructor: Any, Loader: Any = None, constructor: Any = Constructor, # NOQA ) -> None: """ Add a multi-constructor for the given tag prefix. @@ -1567,7 +1567,7 @@ def add_multi_constructor( def add_representer( - data_type: Any, object_representer: Any, Dumper: Any = None, representer: Any = Representer + data_type: Any, object_representer: Any, Dumper: Any = None, representer: Any = Representer, # NOQA ) -> None: """ Add a representer for the given type. @@ -1595,7 +1595,7 @@ def add_representer( # this code currently not tested def add_multi_representer( - data_type: Any, multi_representer: Any, Dumper: Any = None, representer: Any = Representer + data_type: Any, multi_representer: Any, Dumper: Any = None, representer: Any = Representer, ) -> None: """ Add a representer for the given type. @@ -1660,5 +1660,5 @@ def to_yaml(cls, representer: Any, data: Any) -> Any: Convert a Python object to a representation node. """ return representer.represent_yaml_object( - cls.yaml_tag, data, cls, flow_style=cls.yaml_flow_style + cls.yaml_tag, data, cls, flow_style=cls.yaml_flow_style, ) diff --git a/nodes.py b/nodes.py index 4281368..7ab43e7 100644 --- a/nodes.py +++ b/nodes.py @@ -139,6 +139,6 @@ def __init__( anchor: Any = None, ) -> None: CollectionNode.__init__( - self, tag, value, start_mark, end_mark, flow_style, comment, anchor + self, tag, value, start_mark, end_mark, flow_style, comment, anchor, ) self.merge = None diff --git a/parser.py b/parser.py index 7a7d979..8cb9a37 100644 --- a/parser.py +++ b/parser.py @@ -275,7 +275,7 @@ def parse_document_end(self) -> Any: def parse_document_content(self) -> Any: if self.scanner.check_token( - DirectiveToken, DocumentStartToken, DocumentEndToken, StreamEndToken + DirectiveToken, DocumentStartToken, DocumentEndToken, StreamEndToken, ): event = self.process_empty_scalar(self.scanner.peek_token().start_mark) self.state = self.states.pop() @@ -291,7 +291,7 @@ def process_directives(self) -> Any: if token.name == 'YAML': if yaml_version is not None: raise ParserError( - None, None, 'found duplicate YAML directive', token.start_mark + None, None, 'found duplicate YAML directive', token.start_mark, ) major, minor = token.value if major != 1: @@ -481,14 +481,14 @@ def parse_node(self, block: bool = False, indentless_sequence: bool = False) -> comment = pt.split_old_comment() # nprint('pt1', comment) event = SequenceStartEvent( - anchor, tag, implicit, start_mark, end_mark, flow_style=False, comment=comment + anchor, tag, implicit, start_mark, end_mark, flow_style=False, comment=comment, ) self.state = self.parse_block_sequence_first_entry elif block and self.scanner.check_token(BlockMappingStartToken): end_mark = self.scanner.peek_token().start_mark comment = self.scanner.peek_token().comment event = MappingStartEvent( - anchor, tag, implicit, start_mark, end_mark, flow_style=False, comment=comment + anchor, tag, implicit, start_mark, end_mark, flow_style=False, comment=comment, ) self.state = self.parse_block_mapping_first_key elif anchor is not None or tag is not None: @@ -556,7 +556,7 @@ def parse_indentless_sequence_entry(self) -> Any: token = self.scanner.get_token() self.move_token_comment(token) if not self.scanner.check_token( - BlockEntryToken, KeyToken, ValueToken, BlockEndToken + BlockEntryToken, KeyToken, ValueToken, BlockEndToken, ): self.states.append(self.parse_indentless_sequence_entry) return self.parse_block_node() @@ -674,7 +674,7 @@ def parse_flow_sequence_entry(self, first: bool = False) -> Any: if self.scanner.check_token(KeyToken): token = self.scanner.peek_token() event: Any = MappingStartEvent( - None, None, True, token.start_mark, token.end_mark, flow_style=True + None, None, True, token.start_mark, token.end_mark, flow_style=True, ) self.state = self.parse_flow_sequence_entry_mapping_key return event @@ -742,7 +742,7 @@ def parse_flow_mapping_key(self, first: Any = False) -> Any: if self.scanner.check_token(KeyToken): token = self.scanner.get_token() if not self.scanner.check_token( - ValueToken, FlowEntryToken, FlowMappingEndToken + ValueToken, FlowEntryToken, FlowMappingEndToken, ): self.states.append(self.parse_flow_mapping_value) return self.parse_flow_node() @@ -750,7 +750,7 @@ def parse_flow_mapping_key(self, first: Any = False) -> Any: self.state = self.parse_flow_mapping_value return self.process_empty_scalar(token.end_mark) elif self.resolver.processing_version > (1, 1) and self.scanner.check_token( - ValueToken + ValueToken, ): self.state = self.parse_flow_mapping_value return self.process_empty_scalar(self.scanner.peek_token().end_mark) @@ -785,7 +785,7 @@ def process_empty_scalar(self, mark: Any, comment: Any = None) -> Any: return ScalarEvent(None, None, (True, False), "", mark, mark, comment=comment) def move_token_comment( - self, token: Any, nt: Optional[Any] = None, empty: Optional[bool] = False + self, token: Any, nt: Optional[Any] = None, empty: Optional[bool] = False, ) -> Any: pass @@ -799,7 +799,7 @@ def select_tag_transform(self, tag: Tag) -> None: tag.select_transform(True) def move_token_comment( - self, token: Any, nt: Optional[Any] = None, empty: Optional[bool] = False + self, token: Any, nt: Optional[Any] = None, empty: Optional[bool] = False, ) -> Any: token.move_old_comment(self.scanner.peek_token() if nt is None else nt, empty=empty) @@ -811,7 +811,7 @@ class RoundTripParserSC(RoundTripParser): # if self.loader.comment_handling is not None def move_token_comment( - self: Any, token: Any, nt: Any = None, empty: Optional[bool] = False + self: Any, token: Any, nt: Any = None, empty: Optional[bool] = False, ) -> None: token.move_new_comment(self.scanner.peek_token() if nt is None else nt, empty=empty) diff --git a/reader.py b/reader.py index f27ef82..3780a2c 100644 --- a/reader.py +++ b/reader.py @@ -32,7 +32,7 @@ class ReaderError(YAMLError): def __init__( - self, name: Any, position: Any, character: Any, encoding: Any, reason: Any + self, name: Any, position: Any, character: Any, encoding: Any, reason: Any, ) -> None: self.name = name self.character = character @@ -162,7 +162,7 @@ def forward(self, length: int = 1) -> None: def get_mark(self) -> Any: if self.stream is None: return StringMark( - self.name, self.index, self.line, self.column, self.buffer, self.pointer + self.name, self.index, self.line, self.column, self.buffer, self.pointer, ) else: return FileMark(self.name, self.index, self.line, self.column) @@ -183,7 +183,7 @@ def determine_encoding(self) -> None: self.update(1) NON_PRINTABLE = RegExp( - '[^\x09\x0A\x0D\x20-\x7E\x85' '\xA0-\uD7FF' '\uE000-\uFFFD' '\U00010000-\U0010FFFF' ']' + '[^\x09\x0A\x0D\x20-\x7E\x85' '\xA0-\uD7FF' '\uE000-\uFFFD' '\U00010000-\U0010FFFF' ']' # NOQA ) _printable_ascii = ('\x09\x0A\x0D' + "".join(map(chr, range(0x20, 0x7F)))).encode('ascii') diff --git a/representer.py b/representer.py index 9d122bc..7c89545 100644 --- a/representer.py +++ b/representer.py @@ -28,8 +28,8 @@ from ruamel.yaml.timestamp import TimeStamp from ruamel.yaml.anchor import Anchor +import collections import datetime -import sys import types import copyreg @@ -139,7 +139,7 @@ def add_multi_representer(cls, data_type: Any, representer: Any) -> None: cls.yaml_multi_representers[data_type] = representer def represent_scalar( - self, tag: Any, value: Any, style: Any = None, anchor: Any = None + self, tag: Any, value: Any, style: Any = None, anchor: Any = None, ) -> ScalarNode: if style is None: style = self.default_style @@ -156,7 +156,7 @@ def represent_scalar( return node def represent_sequence( - self, tag: Any, sequence: Any, flow_style: Any = None + self, tag: Any, sequence: Any, flow_style: Any = None, ) -> SequenceNode: value: List[Any] = [] if isinstance(tag, str): @@ -333,7 +333,7 @@ def represent_datetime(self, data: Any) -> ScalarNode: return self.represent_scalar('tag:yaml.org,2002:timestamp', value) def represent_yaml_object( - self, tag: Any, data: Any, cls: Any, flow_style: Any = None + self, tag: Any, data: Any, cls: Any, flow_style: Any = None, ) -> MappingNode: if hasattr(data, '__getstate__'): state = data.__getstate__() @@ -367,12 +367,9 @@ def represent_undefined(self, data: Any) -> None: SafeRepresenter.add_representer(ordereddict, SafeRepresenter.represent_ordereddict) -if sys.version_info >= (2, 7): - import collections - - SafeRepresenter.add_representer( - collections.OrderedDict, SafeRepresenter.represent_ordereddict - ) +SafeRepresenter.add_representer( + collections.OrderedDict, SafeRepresenter.represent_ordereddict, +) SafeRepresenter.add_representer(datetime.date, SafeRepresenter.represent_date) @@ -457,7 +454,7 @@ def represent_object(self, data: Any) -> Union[SequenceNode, MappingNode]: function_name = f'{function.__module__!s}.{function.__name__!s}' if not args and not listitems and not dictitems and isinstance(state, dict) and newobj: return self.represent_mapping( - 'tag:yaml.org,2002:python/object:' + function_name, state + 'tag:yaml.org,2002:python/object:' + function_name, state, ) if not listitems and not dictitems and isinstance(state, dict) and not state: return self.represent_sequence(tag + function_name, args) @@ -495,7 +492,7 @@ class RoundTripRepresenter(SafeRepresenter): # in serializer and emitter def __init__( - self, default_style: Any = None, default_flow_style: Any = None, dumper: Any = None + self, default_style: Any = None, default_flow_style: Any = None, dumper: Any = None, ) -> None: if not hasattr(dumper, 'typ') and default_flow_style is None: default_flow_style = False @@ -565,7 +562,7 @@ def represent_plain_scalarstring(self, data: Any) -> ScalarNode: return self.represent_scalar(tag, data, style=style, anchor=anchor) def insert_underscore( - self, prefix: Any, s: Any, underscore: Any, anchor: Any = None + self, prefix: Any, s: Any, underscore: Any, anchor: Any = None, ) -> ScalarNode: if underscore is None: return self.represent_scalar('tag:yaml.org,2002:int', prefix + s, anchor=anchor) @@ -703,7 +700,7 @@ def represent_scalar_float(self, data: Any) -> ScalarNode: return self.represent_scalar('tag:yaml.org,2002:float', value, anchor=anchor) def represent_sequence( - self, tag: Any, sequence: Any, flow_style: Any = None + self, tag: Any, sequence: Any, flow_style: Any = None, ) -> SequenceNode: value: List[Any] = [] # if the flow_style is None, the flow style tacked on to the object @@ -871,7 +868,7 @@ def represent_mapping(self, tag: Any, mapping: Any, flow_style: Any = None) -> M arg = self.represent_data(merge_list) arg.flow_style = True value.insert( - merge_pos, (ScalarNode(Tag(suffix='tag:yaml.org,2002:merge'), '<<'), arg) + merge_pos, (ScalarNode(Tag(suffix='tag:yaml.org,2002:merge'), '<<'), arg), ) return node @@ -1057,7 +1054,7 @@ def represent_scalar_bool(self, data: Any) -> ScalarNode: return SafeRepresenter.represent_bool(self, data, anchor=anchor) def represent_yaml_object( - self, tag: Any, data: Any, cls: Any, flow_style: Optional[Any] = None + self, tag: Any, data: Any, cls: Any, flow_style: Optional[Any] = None, ) -> MappingNode: if hasattr(data, '__getstate__'): state = data.__getstate__() @@ -1073,23 +1070,23 @@ def represent_yaml_object( RoundTripRepresenter.add_representer(type(None), RoundTripRepresenter.represent_none) RoundTripRepresenter.add_representer( - LiteralScalarString, RoundTripRepresenter.represent_literal_scalarstring + LiteralScalarString, RoundTripRepresenter.represent_literal_scalarstring, ) RoundTripRepresenter.add_representer( - FoldedScalarString, RoundTripRepresenter.represent_folded_scalarstring + FoldedScalarString, RoundTripRepresenter.represent_folded_scalarstring, ) RoundTripRepresenter.add_representer( - SingleQuotedScalarString, RoundTripRepresenter.represent_single_quoted_scalarstring + SingleQuotedScalarString, RoundTripRepresenter.represent_single_quoted_scalarstring, ) RoundTripRepresenter.add_representer( - DoubleQuotedScalarString, RoundTripRepresenter.represent_double_quoted_scalarstring + DoubleQuotedScalarString, RoundTripRepresenter.represent_double_quoted_scalarstring, ) RoundTripRepresenter.add_representer( - PlainScalarString, RoundTripRepresenter.represent_plain_scalarstring + PlainScalarString, RoundTripRepresenter.represent_plain_scalarstring, ) # RoundTripRepresenter.add_representer(tuple, Representer.represent_tuple) @@ -1113,20 +1110,17 @@ def represent_yaml_object( RoundTripRepresenter.add_representer(CommentedMap, RoundTripRepresenter.represent_dict) RoundTripRepresenter.add_representer( - CommentedOrderedMap, RoundTripRepresenter.represent_ordereddict + CommentedOrderedMap, RoundTripRepresenter.represent_ordereddict, ) -if sys.version_info >= (2, 7): - import collections - - RoundTripRepresenter.add_representer( - collections.OrderedDict, RoundTripRepresenter.represent_ordereddict - ) +RoundTripRepresenter.add_representer( + collections.OrderedDict, RoundTripRepresenter.represent_ordereddict, +) RoundTripRepresenter.add_representer(CommentedSet, RoundTripRepresenter.represent_set) RoundTripRepresenter.add_representer( - TaggedScalar, RoundTripRepresenter.represent_tagged_scalar + TaggedScalar, RoundTripRepresenter.represent_tagged_scalar, ) RoundTripRepresenter.add_representer(TimeStamp, RoundTripRepresenter.represent_datetime) diff --git a/resolver.py b/resolver.py index b97c8b6..71ba4c7 100644 --- a/resolver.py +++ b/resolver.py @@ -130,9 +130,9 @@ def parser(self) -> Any: def add_implicit_resolver_base(cls, tag: Any, regexp: Any, first: Any) -> None: if 'yaml_implicit_resolvers' not in cls.__dict__: # deepcopy doesn't work here - cls.yaml_implicit_resolvers = dict( - (k, cls.yaml_implicit_resolvers[k][:]) for k in cls.yaml_implicit_resolvers - ) + cls.yaml_implicit_resolvers = { + k: cls.yaml_implicit_resolvers[k][:] for k in cls.yaml_implicit_resolvers + } if first is None: first = [None] for ch in first: @@ -142,9 +142,9 @@ def add_implicit_resolver_base(cls, tag: Any, regexp: Any, first: Any) -> None: def add_implicit_resolver(cls, tag: Any, regexp: Any, first: Any) -> None: if 'yaml_implicit_resolvers' not in cls.__dict__: # deepcopy doesn't work here - cls.yaml_implicit_resolvers = dict( - (k, cls.yaml_implicit_resolvers[k][:]) for k in cls.yaml_implicit_resolvers - ) + cls.yaml_implicit_resolvers = { + k: cls.yaml_implicit_resolvers[k][:] for k in cls.yaml_implicit_resolvers + } if first is None: first = [None] for ch in first: @@ -237,7 +237,7 @@ def ascend_resolver(self) -> None: self.resolver_prefix_paths.pop() def check_resolver_prefix( - self, depth: int, path: Any, kind: Any, current_node: Any, current_index: Any + self, depth: int, path: Any, kind: Any, current_node: Any, current_index: Any, ) -> bool: node_check, index_check = path[depth - 1] if isinstance(node_check, str): @@ -307,7 +307,7 @@ class VersionedResolver(BaseResolver): """ def __init__( - self, version: Optional[VersionType] = None, loader: Any = None, loadumper: Any = None + self, version: Optional[VersionType] = None, loader: Any = None, loadumper: Any = None, ) -> None: if loader is None and loadumper is not None: loader = loadumper @@ -316,7 +316,7 @@ def __init__( self._version_implicit_resolver: Dict[Any, Any] = {} def add_version_implicit_resolver( - self, version: VersionType, tag: Any, regexp: Any, first: Any + self, version: VersionType, tag: Any, regexp: Any, first: Any, ) -> None: if first is None: first = [None] diff --git a/scalarfloat.py b/scalarfloat.py index d3fe12e..10b4c29 100644 --- a/scalarfloat.py +++ b/scalarfloat.py @@ -89,7 +89,7 @@ def dump(self, out: Any = sys.stdout) -> None: out.write( f'ScalarFloat({self}| w:{self._width}, p:{self._prec}, ' # type: ignore f's:{self._m_sign}, lz:{self._m_lead0}, _:{self._underscore}|{self._exp}' - f', w:{self._e_width}, s:{self._e_sign})\n' + f', w:{self._e_width}, s:{self._e_sign})\n', ) diff --git a/scalarint.py b/scalarint.py index 3a2603d..af798b7 100644 --- a/scalarint.py +++ b/scalarint.py @@ -79,14 +79,14 @@ def yaml_set_anchor(self, value: Any, always_dump: bool = False) -> None: class BinaryInt(ScalarInt): def __new__( - cls, value: Any, width: Any = None, underscore: Any = None, anchor: Any = None + cls, value: Any, width: Any = None, underscore: Any = None, anchor: Any = None, ) -> Any: return ScalarInt.__new__(cls, value, width=width, underscore=underscore, anchor=anchor) class OctalInt(ScalarInt): def __new__( - cls, value: Any, width: Any = None, underscore: Any = None, anchor: Any = None + cls, value: Any, width: Any = None, underscore: Any = None, anchor: Any = None, ) -> Any: return ScalarInt.__new__(cls, value, width=width, underscore=underscore, anchor=anchor) @@ -99,7 +99,7 @@ class HexInt(ScalarInt): """uses lower case (a-f)""" def __new__( - cls, value: Any, width: Any = None, underscore: Any = None, anchor: Any = None + cls, value: Any, width: Any = None, underscore: Any = None, anchor: Any = None, ) -> Any: return ScalarInt.__new__(cls, value, width=width, underscore=underscore, anchor=anchor) @@ -108,7 +108,7 @@ class HexCapsInt(ScalarInt): """uses upper case (A-F)""" def __new__( - cls, value: Any, width: Any = None, underscore: Any = None, anchor: Any = None + cls, value: Any, width: Any = None, underscore: Any = None, anchor: Any = None, ) -> Any: return ScalarInt.__new__(cls, value, width=width, underscore=underscore, anchor=anchor) @@ -117,6 +117,6 @@ class DecimalInt(ScalarInt): """needed if anchor""" def __new__( - cls, value: Any, width: Any = None, underscore: Any = None, anchor: Any = None + cls, value: Any, width: Any = None, underscore: Any = None, anchor: Any = None, ) -> Any: return ScalarInt.__new__(cls, value, width=width, underscore=underscore, anchor=anchor) diff --git a/scanner.py b/scanner.py index bfef0ed..11779f4 100644 --- a/scanner.py +++ b/scanner.py @@ -57,7 +57,7 @@ class SimpleKey: # See below simple keys treatment. def __init__( - self, token_number: Any, required: Any, index: int, line: int, column: int, mark: Any + self, token_number: Any, required: Any, index: int, line: int, column: int, mark: Any, ) -> None: self.token_number = token_number self.required = required @@ -539,7 +539,10 @@ def fetch_block_entry(self) -> None: # Are we allowed to start a new entry? if not self.allow_simple_key: raise ScannerError( - None, None, 'sequence entries are not allowed here', self.reader.get_mark() + None, + None, + 'sequence entries are not allowed here', + self.reader.get_mark(), ) # We may need to add BLOCK-SEQUENCE-START. if self.add_indent(self.reader.column): @@ -567,7 +570,7 @@ def fetch_key(self) -> None: # Are we allowed to start a key (not nessesary a simple)? if not self.allow_simple_key: raise ScannerError( - None, None, 'mapping keys are not allowed here', self.reader.get_mark() + None, None, 'mapping keys are not allowed here', self.reader.get_mark(), ) # We may need to add BLOCK-MAPPING-START. @@ -594,7 +597,7 @@ def fetch_value(self) -> None: key = self.possible_simple_keys[self.flow_level] del self.possible_simple_keys[self.flow_level] self.tokens.insert( - key.token_number - self.tokens_taken, KeyToken(key.mark, key.mark) + key.token_number - self.tokens_taken, KeyToken(key.mark, key.mark), ) # If this key starts a new block mapping, we need to add @@ -1113,7 +1116,7 @@ def scan_block_scalar(self, style: Any, rt: Optional[bool] = False) -> Any: style not in '|>' or (self.scanner_processing_version == (1, 1)) and getattr( - self.loader, 'top_level_block_style_scalar_no_indent_error_1_1', False + self.loader, 'top_level_block_style_scalar_no_indent_error_1_1', False, ) ): min_indent = 1 @@ -1307,8 +1310,7 @@ def scan_block_scalar_indentation(self) -> Any: if first_indent > 0 and max_indent > first_indent: start_mark = self.reader.get_mark() raise ScannerError( - 'more indented follow up line than first in a block scalar', - start_mark, + 'more indented follow up line than first in a block scalar', start_mark, ) return chunks, max_indent, end_mark @@ -2114,7 +2116,7 @@ def assign_eol(self, tokens: Any) -> Any: return idx = 1 while tokens[-idx].start_mark.line > comment_line or isinstance( - tokens[-idx], ValueToken + tokens[-idx], ValueToken, ): idx += 1 xprintf('idx1', idx) @@ -2126,7 +2128,7 @@ def assign_eol(self, tokens: Any) -> Any: return try: if isinstance(tokens[-idx], ScalarToken) and isinstance( - tokens[-(idx + 1)], KeyToken + tokens[-(idx + 1)], KeyToken, ): try: eol_idx = self.unused.pop(0) @@ -2141,7 +2143,7 @@ def assign_eol(self, tokens: Any) -> Any: pass try: if isinstance(tokens[-idx], ScalarToken) and isinstance( - tokens[-(idx + 1)], (ValueToken, BlockEntryToken) + tokens[-(idx + 1)], (ValueToken, BlockEntryToken), ): try: eol_idx = self.unused.pop(0) @@ -2175,7 +2177,7 @@ def assign_post(self, token: Any) -> Any: def str_unprocessed(self) -> Any: return ''.join( - (f' {ind:2} {x.info()}\n' for ind, x in self.comments.items() if x.used == ' ') + (f' {ind:2} {x.info()}\n' for ind, x in self.comments.items() if x.used == ' '), ) @@ -2254,11 +2256,11 @@ def scan_to_next_token(self) -> None: # we have a comment if start_mark.column == 0: self.comments.add_full_line_comment( # type: ignore - comment, comment_start_mark.column, comment_start_mark.line + comment, comment_start_mark.column, comment_start_mark.line, ) else: self.comments.add_eol_comment( # type: ignore - comment, comment_start_mark.column, comment_start_mark.line + comment, comment_start_mark.column, comment_start_mark.line, ) comment = "" # gather any blank lines or full line comments following the comment as well diff --git a/serializer.py b/serializer.py index e36b3b5..1ac46d2 100644 --- a/serializer.py +++ b/serializer.py @@ -102,8 +102,8 @@ def serialize(self, node: Any) -> None: raise SerializerError('serializer is closed') self.emitter.emit( DocumentStartEvent( - explicit=self.use_explicit_start, version=self.use_version, tags=self.use_tags - ) + explicit=self.use_explicit_start, version=self.use_version, tags=self.use_tags, + ), ) self.anchor_node(node) self.serialize_node(node, None, None) @@ -170,7 +170,7 @@ def serialize_node(self, node: Any, parent: Any, index: Any) -> None: node.value, style=node.style, comment=node.comment, - ) + ), ) elif isinstance(node, SequenceNode): implicit = node.ctag == self.resolver.resolve(SequenceNode, node.value, True) @@ -192,7 +192,7 @@ def serialize_node(self, node: Any, parent: Any, index: Any) -> None: implicit, flow_style=node.flow_style, comment=node.comment, - ) + ), ) index = 0 for item in node.value: @@ -218,7 +218,7 @@ def serialize_node(self, node: Any, parent: Any, index: Any) -> None: flow_style=node.flow_style, comment=node.comment, nr_items=len(node.value), - ) + ), ) for key, value in node.value: self.serialize_node(key, node, None) diff --git a/setup.py b/setup.py index 98f7e93..b60f159 100644 --- a/setup.py +++ b/setup.py @@ -49,9 +49,9 @@ class NameConstant: if sys.version_info < (3,): - open_kw = dict() + open_kw = {} else: - open_kw = dict(encoding='utf-8') + open_kw = dict(encoding='utf-8') # NOQA: C408 if sys.version_info < (2, 7) or platform.python_implementation() == 'Jython': @@ -113,7 +113,7 @@ def _convert(node): elif isinstance(node, Set): return set(map(_convert, node.elts)) elif isinstance(node, Dict): - return dict((_convert(k), _convert(v)) for k, v in zip(node.keys, node.values)) + return {_convert(k): _convert(v) for k, v in zip(node.keys, node.values)} elif isinstance(node, NameConstant): return node.value elif sys.version_info < (3, 4) and isinstance(node, Name): @@ -144,7 +144,7 @@ def _convert(node): elif isinstance(node, Call): func_id = getattr(node.func, 'id', None) if func_id == 'dict': - return dict((k.arg, _convert(k.value)) for k in node.keywords) + return {k.arg: _convert(k.value) for k in node.keywords} elif func_id == 'set': return set(_convert(node.args[0])) elif func_id == 'date': @@ -202,8 +202,8 @@ def _package_data(fn): if index == e.lineno - 1: print( '{0:{1}} {2}^--- {3}'.format( - ' ', w, ' ' * e.offset, e.node - ) + ' ', w, ' ' * e.offset, e.node, + ), ) raise break @@ -400,7 +400,7 @@ def namespace_directories(self, depth=None): def package_dir(self): d = { # don't specify empty dir, clashes with package_data spec - self.full_package_name: '.' + self.full_package_name: '.', } if 'extra_packages' in self._pkg_data: return d @@ -438,7 +438,7 @@ def check(self): # installed packages. As we don't know the order in namespace_packages # do some magic prefix = self.split[0] - prefixes = set([prefix, prefix.replace('_', '-')]) + prefixes = {prefix, prefix.replace('_', '-')} for p in sys.path: if not p: continue # directory with setup.py @@ -461,7 +461,7 @@ def check(self): if self.command == 'develop': raise InstallationError( 'Cannot mix develop (pip install -e),\nwith ' - 'non-develop installs for package name {0}'.format(fn) + 'non-develop installs for package name {0}'.format(fn), ) elif fn == prefix: raise InstallationError('non directory package {0} in {1}'.format(fn, p)) @@ -473,7 +473,7 @@ def check(self): if fn.endswith('-link') and self.command == 'install': raise InstallationError( 'Cannot mix non-develop with develop\n(pip install -e)' - ' installs for package name {0}'.format(fn) + ' installs for package name {0}'.format(fn), ) def entry_points(self, script_name=None, package_name=None): @@ -491,7 +491,7 @@ def entry_points(self, script_name=None, package_name=None): def pckg_entry_point(name): return '{0}{1}:main'.format( - name, '.__main__' if os.path.exists('__main__.py') else "" + name, '.__main__' if os.path.exists('__main__.py') else "", ) ep = self._pkg_data.get('entry_points', True) @@ -512,8 +512,8 @@ def pckg_entry_point(name): script_name = package_name.rsplit('.', 1)[-1] return { 'console_scripts': [ - '{0} = {1}'.format(script_name, pckg_entry_point(package_name)) - ] + '{0} = {1}'.format(script_name, pckg_entry_point(package_name)), + ], } @property @@ -586,8 +586,8 @@ def _setup_classifiers(self): 'Operating System :: OS Independent', 'Programming Language :: Python', ] - + [self.pn(x) for x in self._pkg_data.get('classifiers', [])] - ) + + [self.pn(x) for x in self._pkg_data.get('classifiers', [])], + ), ) @property @@ -843,12 +843,12 @@ def main(): nsp.check() # nsp.create_dirs() MySdist.nsp = nsp - cmdclass = dict(install_lib=MyInstallLib, sdist=MySdist) + cmdclass = dict(install_lib=MyInstallLib, sdist=MySdist) # NOQA: C408 if _bdist_wheel_available: MyBdistWheel.nsp = nsp cmdclass['bdist_wheel'] = MyBdistWheel - kw = dict( + kw = dict( # NOQA: C408 name=nsp.full_package_name, version=version_str, packages=nsp.packages, diff --git a/tokens.py b/tokens.py index 0cf37f2..0c73dcf 100644 --- a/tokens.py +++ b/tokens.py @@ -217,7 +217,7 @@ class StreamStartToken(Token): id = '' def __init__( - self, start_mark: Any = None, end_mark: Any = None, encoding: Any = None + self, start_mark: Any = None, end_mark: Any = None, encoding: Any = None, ) -> None: Token.__init__(self, start_mark, end_mark) self.encoding = encoding @@ -318,7 +318,7 @@ class ScalarToken(Token): id = '' def __init__( - self, value: Any, plain: Any, start_mark: Any, end_mark: Any, style: Any = None + self, value: Any, plain: Any, start_mark: Any, end_mark: Any, style: Any = None, ) -> None: Token.__init__(self, start_mark, end_mark) self.value = value @@ -331,7 +331,7 @@ class CommentToken(Token): id = '' def __init__( - self, value: Any, start_mark: Any = None, end_mark: Any = None, column: Any = None + self, value: Any, start_mark: Any = None, end_mark: Any = None, column: Any = None, ) -> None: if start_mark is None: assert column is not None diff --git a/tox.ini b/tox.ini index 078a3dc..9070ba6 100755 --- a/tox.ini +++ b/tox.ini @@ -16,6 +16,11 @@ basepython = python3.11 deps = flake8 flake8-bugbear;python_version>="3.11" + flake8-2020==1.8.1 + flake8-commas==2.1.0 + flake8-comprehensions==3.14.0 + flake8-length==0.3.1 + flake8-logging-format==0.9.0 commands = flake8 []{posargs} @@ -24,13 +29,18 @@ basepython = python3.11 deps = flake8 flake8-bugbear;python_version>="3.11" + flake8-2020==1.8.1 + flake8-commas==2.1.0 + flake8-comprehensions==3.14.0 + flake8-length==0.3.1 + flake8-logging-format==0.9.0 commands = flake8 []{posargs} [flake8] show-source = True max-line-length = 95 -ignore = W503,F405,E203 +ignore = W503,F405,E203,C408 exclude = _test/lib,branch_default,.hg,.git,.tox,dist,.cache,__pycache__,ruamel.zip2tar.egg-info [pytest] diff --git a/util.py b/util.py index 39d71b4..b621ce0 100644 --- a/util.py +++ b/util.py @@ -102,7 +102,7 @@ def create_timestamp( tz_hour = int(tz_hour) tz_minute = int(tz_minute) if tz_minute else 0 delta = datetime.timedelta( - hours=tz_hour, minutes=tz_minute, seconds=1 if frac > MAX_FRAC else 0 + hours=tz_hour, minutes=tz_minute, seconds=1 if frac > MAX_FRAC else 0, ) if tz_sign == '-': delta = -delta