1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-11-08

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

原因

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

同様の問題を抱えている人は少なくなく
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'

参考リンク

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?