Skip to content

Commit 425fd97

Browse files
authored
Support the new FullLoader in PyYAML v5.1+ (#16)
Support the new FullLoader in PyYAML v5.1+
1 parent 98ca46e commit 425fd97

File tree

4 files changed

+81
-108
lines changed

4 files changed

+81
-108
lines changed

.travis.yml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,21 @@ python:
77
- "3.4"
88
- "3.5"
99
- "3.6"
10+
- "3.7-dev"
1011
- "nightly"
1112
- "pypy"
12-
- "pypy3.5"
13+
- "pypy3"
1314

1415
env:
1516
- PYYAML_VERSION="3.13"
1617
# - PYYAML_VERSION="4.1" # this was pulled from the index (!) ..wtf, Ingy?
1718
- PYYAML_VERSION="4.2b4"
19+
- PYYAML_VERSION="5.1"
1820

1921
matrix:
2022
fast_finish: true
2123
allow_failures:
2224
- python: "nightly"
23-
include:
24-
- python: 3.7
25-
dist: xenial
26-
sudo: true
2725

2826
install:
2927
- pip install pyyaml~=$PYYAML_VERSION

oyaml.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
import platform
12
import sys
23
from collections import OrderedDict
34

45
import yaml as pyyaml
56

67

7-
_items = 'viewitems' if sys.version_info < (3,) else 'items'
8+
_items = "viewitems" if sys.version_info < (3,) else "items"
9+
_std_dict_is_order_preserving = sys.version_info >= (3, 7) or (
10+
sys.version_info >= (3, 6) and platform.python_implementation() == "CPython"
11+
)
812

913

1014
def map_representer(dumper, data):
@@ -17,32 +21,28 @@ def map_constructor(loader, node):
1721

1822

1923
if pyyaml.safe_dump is pyyaml.dump:
20-
# PyYAML v4.1
24+
# PyYAML v4.x
2125
SafeDumper = pyyaml.dumper.Dumper
2226
DangerDumper = pyyaml.dumper.DangerDumper
23-
SafeLoader = pyyaml.loader.Loader
24-
DangerLoader = pyyaml.loader.DangerLoader
2527
else:
2628
SafeDumper = pyyaml.dumper.SafeDumper
2729
DangerDumper = pyyaml.dumper.Dumper
28-
SafeLoader = pyyaml.loader.SafeLoader
29-
DangerLoader = pyyaml.loader.Loader
3030

3131
pyyaml.add_representer(dict, map_representer, Dumper=SafeDumper)
3232
pyyaml.add_representer(OrderedDict, map_representer, Dumper=SafeDumper)
3333
pyyaml.add_representer(dict, map_representer, Dumper=DangerDumper)
3434
pyyaml.add_representer(OrderedDict, map_representer, Dumper=DangerDumper)
3535

3636

37-
if sys.version_info < (3, 7):
38-
pyyaml.add_constructor('tag:yaml.org,2002:map', map_constructor, Loader=SafeLoader)
39-
pyyaml.add_constructor('tag:yaml.org,2002:map', map_constructor, Loader=DangerLoader)
40-
41-
42-
del map_constructor, map_representer
37+
Loader = None
38+
if not _std_dict_is_order_preserving:
39+
for loader_name in pyyaml.loader.__all__:
40+
Loader = getattr(pyyaml.loader, loader_name)
41+
pyyaml.add_constructor("tag:yaml.org,2002:map", map_constructor, Loader=Loader)
4342

4443

4544
# Merge PyYAML namespace into ours.
4645
# This allows users a drop-in replacement:
4746
# import oyaml as yaml
47+
del map_constructor, map_representer, SafeDumper, DangerDumper, Loader
4848
from yaml import *

setup.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
from setuptools import setup
22

33
setup(
4-
name='oyaml',
5-
version='0.7',
6-
description='Ordered YAML: drop-in replacement for PyYAML which preserves dict ordering',
7-
long_description=open('README.rst').read(),
8-
author='Wim Glenn',
9-
author_email='hey@wimglenn.com',
10-
url='https://github.com/wimglenn/oyaml',
11-
license='MIT',
12-
py_modules=['oyaml'],
13-
install_requires=['pyyaml'],
4+
name="oyaml",
5+
version="0.8",
6+
description="Ordered YAML: drop-in replacement for PyYAML which preserves dict ordering",
7+
long_description=open("README.rst").read(),
8+
author="Wim Glenn",
9+
author_email="hey@wimglenn.com",
10+
url="https://github.com/wimglenn/oyaml",
11+
license="MIT",
12+
py_modules=["oyaml"],
13+
install_requires=["pyyaml"],
1414
)

test_oyaml.py

Lines changed: 56 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,84 @@
1-
import sys
21
from collections import OrderedDict
32
from types import GeneratorType
43

54
import pytest
5+
from yaml.representer import RepresenterError
66

77
import oyaml as yaml
8+
from oyaml import _std_dict_is_order_preserving
89

910

10-
data = OrderedDict([('x', 1), ('z', 3), ('y', 2)])
11-
12-
13-
# this release was pulled from index, but still might be seen in the wild
14-
pyyaml_41 = yaml.pyyaml.__version__ == '4.1'
11+
data = OrderedDict([("x", 1), ("z", 3), ("y", 2)])
1512

1613

1714
def test_dump():
18-
assert yaml.dump(data) == '{x: 1, z: 3, y: 2}\n'
15+
assert yaml.dump(data, default_flow_style=None) == "{x: 1, z: 3, y: 2}\n"
1916

2017

2118
def test_safe_dump():
22-
assert yaml.safe_dump(data) == '{x: 1, z: 3, y: 2}\n'
23-
24-
25-
@pytest.mark.skipif(not pyyaml_41, reason="requires PyYAML version == 4.1")
26-
def test_danger_dump():
27-
assert yaml.danger_dump(data) == '{x: 1, z: 3, y: 2}\n'
19+
assert yaml.safe_dump(data, default_flow_style=None) == "{x: 1, z: 3, y: 2}\n"
2820

2921

3022
def test_dump_all():
31-
assert yaml.dump_all(documents=[data, {}]) == '{x: 1, z: 3, y: 2}\n--- {}\n'
23+
assert (
24+
yaml.dump_all(documents=[data, {}], default_flow_style=None)
25+
== "{x: 1, z: 3, y: 2}\n--- {}\n"
26+
)
3227

3328

34-
@pytest.mark.skipif(pyyaml_41, reason="requires PyYAML version != 4.1")
3529
def test_dump_and_safe_dump_match():
36-
mydict = {'x': 1, 'z': 2, 'y': 3}
30+
mydict = {"x": 1, "z": 2, "y": 3}
3731
# don't know if mydict is ordered in the implementation or not (but don't care)
3832
assert yaml.dump(mydict) == yaml.safe_dump(mydict)
3933

4034

41-
@pytest.mark.skipif(not pyyaml_41, reason="requires PyYAML version == 4.1")
42-
def test_danger_dump_and_safe_dump_match():
43-
mydict = {'x': 1, 'z': 2, 'y': 3}
44-
assert yaml.danger_dump(mydict) == yaml.safe_dump(mydict)
45-
46-
4735
def test_safe_dump_all():
48-
assert yaml.safe_dump_all(documents=[data, {}]) == '{x: 1, z: 3, y: 2}\n--- {}\n'
36+
assert (
37+
yaml.safe_dump_all(documents=[data, {}], default_flow_style=None)
38+
== "{x: 1, z: 3, y: 2}\n--- {}\n"
39+
)
4940

5041

5142
def test_load():
52-
loaded = yaml.load('{x: 1, z: 3, y: 2}')
53-
assert loaded == {'x': 1, 'z': 3, 'y': 2}
43+
loaded = yaml.load("{x: 1, z: 3, y: 2}")
44+
assert loaded == {"x": 1, "z": 3, "y": 2}
5445

5546

5647
def test_safe_load():
57-
loaded = yaml.safe_load('{x: 1, z: 3, y: 2}')
58-
assert loaded == {'x': 1, 'z': 3, 'y': 2}
48+
loaded = yaml.safe_load("{x: 1, z: 3, y: 2}")
49+
assert loaded == {"x": 1, "z": 3, "y": 2}
5950

6051

6152
def test_load_all():
62-
gen = yaml.load_all('{x: 1, z: 3, y: 2}\n--- {}\n')
53+
gen = yaml.load_all("{x: 1, z: 3, y: 2}\n--- {}\n")
6354
assert isinstance(gen, GeneratorType)
6455
ordered_data, empty_dict = gen
6556
assert empty_dict == {}
6657
assert ordered_data == data
6758

6859

69-
@pytest.mark.skipif(sys.version_info >= (3, 7), reason="requires python3.6-")
60+
@pytest.mark.skipif(_std_dict_is_order_preserving, reason="requires old dict impl")
7061
def test_loads_to_ordered_dict():
71-
loaded = yaml.load('{x: 1, z: 3, y: 2}')
62+
loaded = yaml.load("{x: 1, z: 3, y: 2}")
7263
assert isinstance(loaded, OrderedDict)
7364

7465

75-
@pytest.mark.skipif(sys.version_info < (3, 7), reason="requires python3.7+")
66+
@pytest.mark.skipif(not _std_dict_is_order_preserving, reason="requires new dict impl")
7667
def test_loads_to_std_dict():
77-
loaded = yaml.load('{x: 1, z: 3, y: 2}')
68+
loaded = yaml.load("{x: 1, z: 3, y: 2}")
7869
assert not isinstance(loaded, OrderedDict)
7970
assert isinstance(loaded, dict)
8071

8172

82-
@pytest.mark.skipif(sys.version_info >= (3, 7), reason="requires python3.6-")
73+
@pytest.mark.skipif(_std_dict_is_order_preserving, reason="requires old dict impl")
8374
def test_safe_loads_to_ordered_dict():
84-
loaded = yaml.safe_load('{x: 1, z: 3, y: 2}')
75+
loaded = yaml.safe_load("{x: 1, z: 3, y: 2}")
8576
assert isinstance(loaded, OrderedDict)
8677

8778

88-
@pytest.mark.skipif(sys.version_info < (3, 7), reason="requires python3.7+")
79+
@pytest.mark.skipif(not _std_dict_is_order_preserving, reason="requires new dict impl")
8980
def test_safe_loads_to_std_dict():
90-
loaded = yaml.safe_load('{x: 1, z: 3, y: 2}')
81+
loaded = yaml.safe_load("{x: 1, z: 3, y: 2}")
9182
assert not isinstance(loaded, OrderedDict)
9283
assert isinstance(loaded, dict)
9384

@@ -96,24 +87,15 @@ class MyOrderedDict(OrderedDict):
9687
pass
9788

9889

99-
@pytest.mark.skipif(pyyaml_41, reason="requires PyYAML version != 4.1")
100-
def test_subclass_dump_pyyaml3():
101-
data = MyOrderedDict([('x', 1), ('y', 2)])
102-
assert '!!python/object/apply:test_oyaml.MyOrderedDict' in yaml.dump(data)
103-
with pytest.raises(yaml.pyyaml.representer.RepresenterError, match='cannot represent an object') as cm:
90+
def test_subclass_dump():
91+
data = MyOrderedDict([("x", 1), ("y", 2)])
92+
assert "!!python/object/apply:test_oyaml.MyOrderedDict" in yaml.dump(data)
93+
with pytest.raises(RepresenterError, match="cannot represent an object"):
10494
yaml.safe_dump(data)
10595

10696

107-
@pytest.mark.skipif(not pyyaml_41, reason="requires PyYAML version == 4.1")
108-
def test_subclass_dump_pyyaml4():
109-
data = MyOrderedDict([('x', 1), ('y', 2)])
110-
assert '!!python/object/apply:test_oyaml.MyOrderedDict' in yaml.danger_dump(data)
111-
with pytest.raises(yaml.pyyaml.representer.RepresenterError, match='cannot represent an object') as cm:
112-
yaml.dump(data)
113-
114-
11597
def test_anchors_and_references():
116-
text = '''
98+
text = """
11799
defaults:
118100
all: &all
119101
product: foo
@@ -125,53 +107,46 @@ def test_anchors_and_references():
125107
platform:
126108
<<: *development
127109
host: baz
128-
'''
110+
"""
129111
expected_load = {
130-
'defaults': {
131-
'all': {
132-
'product': 'foo',
133-
},
134-
'development': {
135-
'product': 'foo',
136-
'profile': 'bar',
137-
},
112+
"defaults": {
113+
"all": {"product": "foo"},
114+
"development": {"product": "foo", "profile": "bar"},
138115
},
139-
'development': {
140-
'platform': {
141-
'host': 'baz',
142-
'product': 'foo',
143-
'profile': 'bar',
144-
},
116+
"development": {
117+
"platform": {"host": "baz", "product": "foo", "profile": "bar"}
145118
},
146119
}
147120
assert yaml.load(text) == expected_load
148121

149122

150123
def test_omap():
151-
text = '''
124+
text = """
152125
Bestiary: !!omap
153126
- aardvark: African pig-like ant eater. Ugly.
154127
- anteater: South-American ant eater. Two species.
155128
- anaconda: South-American constrictor snake. Scaly.
156-
'''
129+
"""
157130
expected_load = {
158-
'Bestiary': ([
159-
('aardvark', 'African pig-like ant eater. Ugly.'),
160-
('anteater', 'South-American ant eater. Two species.'),
161-
('anaconda', 'South-American constrictor snake. Scaly.'),
162-
])
131+
"Bestiary": (
132+
[
133+
("aardvark", "African pig-like ant eater. Ugly."),
134+
("anteater", "South-American ant eater. Two species."),
135+
("anaconda", "South-American constrictor snake. Scaly."),
136+
]
137+
)
163138
}
164139
assert yaml.load(text) == expected_load
165140

166141

167142
def test_omap_flow_style():
168-
text = 'Numbers: !!omap [ one: 1, two: 2, three : 3 ]'
169-
expected_load = {'Numbers': ([('one', 1), ('two', 2), ('three', 3)])}
143+
text = "Numbers: !!omap [ one: 1, two: 2, three : 3 ]"
144+
expected_load = {"Numbers": ([("one", 1), ("two", 2), ("three", 3)])}
170145
assert yaml.load(text) == expected_load
171146

172147

173148
def test_merge():
174-
text = '''
149+
text = """
175150
- &CENTER { x: 1, y: 2 }
176151
- &LEFT { x: 0, y: 2 }
177152
- &BIG { r: 10 }
@@ -198,15 +173,15 @@ def test_merge():
198173
<< : [ *BIG, *LEFT, *SMALL ]
199174
x: 1
200175
label: center/big
201-
'''
176+
"""
202177
data = yaml.load(text)
203178
assert len(data) == 8
204179
center, left, big, small, map1, map2, map3, map4 = data
205-
assert center == {'x': 1, 'y': 2}
206-
assert left == {'x': 0, 'y': 2}
207-
assert big == {'r': 10}
208-
assert small == {'r': 1}
209-
expected = {'x': 1, 'y': 2, 'r': 10, 'label': 'center/big'}
180+
assert center == {"x": 1, "y": 2}
181+
assert left == {"x": 0, "y": 2}
182+
assert big == {"r": 10}
183+
assert small == {"r": 1}
184+
expected = {"x": 1, "y": 2, "r": 10, "label": "center/big"}
210185
assert map1 == expected
211186
assert map2 == expected
212187
assert map3 == expected

0 commit comments

Comments
 (0)