Using yaml.dumper without Alias by PyYAML – PyYAML の yaml.dumpでaliasを無効にする

2pt   2018-11-09 03:15
IT技術情報局

Overview

PyYAMLを使ってyaml dumpをしていると
&id001*id001 と言った出力を見かけたことがないだろうか。

非常に簡単な例を挙げると以下のようなものだ。

サンプルコード

import yaml sample_dict = { "username": "User", "password": "Password", } yaml_data = [sample_dict, sample_dict] print(yaml.dump(yaml_data))

出力結果

$ python sample.py - &id001 {password: Password, username: User} - *id001

期待した動作

$ python sample.py - {password: Password, username: User} - {password: Password, username: User}

サンプルコード2

YAMLファイルを生成するならば
より読みやすい出力にすることが多いと思われるので
default_flow_style = False としたサンプルも貼っておく

import yaml sample_dict = { "username": "User", "password": "Password", } yaml_data = [sample_dict, sample_dict] print(yaml.dump(yaml_data, default_flow_style=False,))

出力結果2

$ python sample.py - &id001 password: Password username: User - *id001 原因

平たく言うとバグ。若しくは仕様のようだ。
トップページに事例付きで解説が書いてある。

https://pypi.org/project/pyaml/

同様の問題を抱えている人は少なくなく
Qiitaでもこちらで対処法が記載されていたり、
Issue103、及びIssue104でチケットが上がっている。

残念ながら2018年11月現在においてもこの問題は解消されておらず
WorkArround対応となっている。

Issue104に記載があるが
yaml.dump(data, ignore_aliases=True) を実装すると、逆にAliasの有るYAMLを読み込んだ際に
無限ループに陥ってしまうらしく、双方をええ具合によろしくやってくれる方法はまだ無いようだ。

従ってWork Arroundで対処する必要がある。

対処方法 - &id001 password: Password username: User - *id001 import yaml from pathlib import Path """Load yaml file""" yaml_data = Path().parent.joinpath('sample.yml').open('r') data = yaml.load(yaml_data) """Solution1""" class NoAliasDumper(yaml.Dumper): def ignore_aliases(self, data): return True out1 = yaml.dump(data, Dumper=NoAliasDumper) print(out1) """Solution2""" noalias_dumper = yaml.dumper.Dumper noalias_dumper.ignore_aliases = lambda self, data: True out2 = yaml.dump(data, Dumper=noalias_dumper) print(out2) python sample_read.py - {password: Password, username: User} - {password: Password, username: User} - {password: Password, username: User} - {password: Password, username: User}

どちらで対処するかはお好みで。
なお、Dumper を SafeDumperにすることはできるが
yaml.dump を yaml.safe_dumpにはできない。
yaml.safe_dumpにすると以下のようなエラーが出てしまう

TypeError: dump_all() got multiple values for keyword argument 'Dumper' 参考リンク

Source: python tag

   ITアンテナトップページへ
情報処理/ITの話題が沢山。