If you don't read the YAML specification you would expect mappings in YAML files to be ordered, as the text representation in a YAML file is ordered. Unfortunately this intuitive assumption is false, the YAML 1.2 explicitly states that this [should be interpreted as] an unordered set of key: value pairs.
This of course makes comparing YAML files using tools like diff virtually impossible if you use mappings and load/change/dump them, and makes checking these kind of file into revision control systems result in spurious extra revision that are semantically the same, but not syntactically.
I set out to improve PyYAML for other reasons as well (YAML 1.2 compatibility instead of the old 1.1 spec, preservation of comments, bug fixes), but ruamel.yaml also preserves ordering as mappings if you use its round_trip_dump:
import ruamel.yaml
from ruamel.yaml.comments import CommentedMap as OrderedDict
a = OrderedDict()
a['name'] = 'hello'
a['msgs'] = ['hello', 'world']
with open("b.yaml", 'w') as stream:
ruamel.yaml.round_trip_dump(a, stream, indent=5, block_seq_indent=3)
which gives you a file b.yaml with content:
name : hello
msgs:
- hello
- world
which is exactly what you expected.
Please note that I passed in the stream to the round_trip_dump, if you use PyYAML you should do this as well, as it is more efficient.
You need to use the CommentedMap, which is just a thin wrapper around OrderedDict/ordereddict that allows preservation of comments etc.
Default indent is 2 and block_seq_indent is 0.
If you load your file using round_trip_dump, you'll get a CommentedMap again in which the order of the keys will be as expected.