From b057a59bb909c0222ab86ff9922e80e7466731ae Mon Sep 17 00:00:00 2001 From: wim glenn Date: Wed, 27 Jun 2018 00:11:39 -0500 Subject: [PATCH 1/2] support PyYAML 4.1.0 --- .travis.yml | 5 +++++ oyaml.py | 17 ++++++++++++----- setup.py | 2 +- test_oyaml.py | 16 +++++++++++++--- 4 files changed, 31 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1a9122a..ffcf965 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,12 +11,17 @@ python: - "pypy" - "pypy3.5" +env: + - PYYAML_VERSION="3.12" + - PYYAML_VERSION="4.1" + matrix: fast_finish: true allow_failures: - python: "nightly" install: + - pip install pyyaml~=$PYYAML_VERSION - pip install --editable . - pip install pytest-cov coveralls diff --git a/oyaml.py b/oyaml.py index 0fdf8e4..b78ebde 100644 --- a/oyaml.py +++ b/oyaml.py @@ -15,11 +15,18 @@ def map_constructor(loader, node): loader.flatten_mapping(node) return OrderedDict(loader.construct_pairs(node)) - -pyyaml.add_representer(dict, map_representer) -pyyaml.add_representer(OrderedDict, map_representer) -pyyaml.add_representer(dict, map_representer, Dumper=pyyaml.dumper.SafeDumper) -pyyaml.add_representer(OrderedDict, map_representer, Dumper=pyyaml.dumper.SafeDumper) +if pyyaml.safe_dump is pyyaml.dump: + # PyYAML >= 4 + SafeDumper = pyyaml.dumper.Dumper + DangerDumper = pyyaml.dumper.DangerDumper +else: + SafeDumper = pyyaml.dumper.SafeDumper + DangerDumper = pyyaml.dumper.Dumper + +pyyaml.add_representer(dict, map_representer, Dumper=SafeDumper) +pyyaml.add_representer(OrderedDict, map_representer, Dumper=SafeDumper) +pyyaml.add_representer(dict, map_representer, Dumper=DangerDumper) +pyyaml.add_representer(OrderedDict, map_representer, Dumper=DangerDumper) if sys.version_info < (3, 7): diff --git a/setup.py b/setup.py index 0d8f6fb..df039dc 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='oyaml', - version='0.4', + version='0.5', description='Ordered YAML: drop-in replacement for PyYAML which preserves dict ordering', long_description=open('README.rst').read(), author='Wim Glenn', diff --git a/test_oyaml.py b/test_oyaml.py index 69ff6d1..260d317 100644 --- a/test_oyaml.py +++ b/test_oyaml.py @@ -58,11 +58,12 @@ def test_loads_to_std_dict(): assert isinstance(loaded, dict) -def test_subclass_dump(): +class MyOrderedDict(OrderedDict): + pass - class MyOrderedDict(OrderedDict): - pass +@pytest.mark.skipif(yaml.pyyaml.__version__ >= '4', reason="requires PyYAML version < 4") +def test_subclass_dump_pyyaml3(): data = MyOrderedDict([('x', 1), ('y', 2)]) assert '!!python/object/apply:test_oyaml.MyOrderedDict' in yaml.dump(data) with pytest.raises(yaml.pyyaml.representer.RepresenterError) as cm: @@ -70,6 +71,15 @@ class MyOrderedDict(OrderedDict): assert str(cm.value) == "cannot represent an object: MyOrderedDict([('x', 1), ('y', 2)])" +@pytest.mark.skipif(yaml.pyyaml.__version__ < '4', reason="requires PyYAML version >= 4") +def test_subclass_dump_pyyaml4(): + data = MyOrderedDict([('x', 1), ('y', 2)]) + assert '!!python/object/apply:test_oyaml.MyOrderedDict' in yaml.danger_dump(data) + with pytest.raises(yaml.pyyaml.representer.RepresenterError) as cm: + yaml.dump(data) + assert str(cm.value) == "('cannot represent an object', MyOrderedDict([('x', 1), ('y', 2)]))" + + def test_anchors_and_references(): text = ''' defaults: From 6a41ce7d614fa4b3a5c337629c2d31965e54554a Mon Sep 17 00:00:00 2001 From: wim glenn Date: Wed, 27 Jun 2018 00:36:47 -0500 Subject: [PATCH 2/2] more tests --- test_oyaml.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/test_oyaml.py b/test_oyaml.py index 260d317..a97383f 100644 --- a/test_oyaml.py +++ b/test_oyaml.py @@ -18,16 +18,28 @@ def test_safe_dump(): assert yaml.safe_dump(data) == '{x: 1, z: 3, y: 2}\n' +@pytest.mark.skipif(yaml.pyyaml.__version__ < '4', reason="requires PyYAML version >= 4") +def test_danger_dump(): + assert yaml.danger_dump(data) == '{x: 1, z: 3, y: 2}\n' + + def test_dump_all(): assert yaml.dump_all(documents=[data, {}]) == '{x: 1, z: 3, y: 2}\n--- {}\n' +@pytest.mark.skipif(yaml.pyyaml.__version__ >= '4', reason="requires PyYAML version < 4") def test_dump_and_safe_dump_match(): mydict = {'x': 1, 'z': 2, 'y': 3} # don't know if mydict is ordered in the implementation or not (but don't care) assert yaml.dump(mydict) == yaml.safe_dump(mydict) +@pytest.mark.skipif(yaml.pyyaml.__version__ < '4', reason="requires PyYAML version >= 4") +def test_danger_dump_and_safe_dump_match(): + mydict = {'x': 1, 'z': 2, 'y': 3} + assert yaml.danger_dump(mydict) == yaml.safe_dump(mydict) + + def test_safe_dump_all(): assert yaml.safe_dump_all(documents=[data, {}]) == '{x: 1, z: 3, y: 2}\n--- {}\n' @@ -113,3 +125,26 @@ def test_anchors_and_references(): }, } assert yaml.load(text) == expected_load + + +def test_omap(): + text = ''' + Bestiary: !!omap + - aardvark: African pig-like ant eater. Ugly. + - anteater: South-American ant eater. Two species. + - anaconda: South-American constrictor snake. Scaly. + ''' + expected_load = { + 'Bestiary': ([ + ('aardvark', 'African pig-like ant eater. Ugly.'), + ('anteater', 'South-American ant eater. Two species.'), + ('anaconda', 'South-American constrictor snake. Scaly.'), + ]) + } + assert yaml.load(text) == expected_load + + +def test_omap_flow_style(): + text = 'Numbers: !!omap [ one: 1, two: 2, three : 3 ]' + expected_load = {'Numbers': ([('one', 1), ('two', 2), ('three', 3)])} + assert yaml.load(text) == expected_load