web-dev-qa-db-ja.com

PyYAMLダンプ形式

SOに関するこれに関する質問はいくつかありますが、探しているものが見つかりませんでした。

pyyaml を使用して_.yml_ファイルを読み取り(.load())、キーを変更または追加してから、もう一度書き込みます(.dump())。問題は、ダンプ後のファイル形式を保持したいのですが、変更されることです。

たとえば、キー_en.test.index.few_を編集して、_"Bye"_ではなく_"Hello"_と言います。

Python:

_with open(path, 'r', encoding = "utf-8") as yaml_file:
    self.dict = pyyaml.load(yaml_file)
_

次に、キーをさらに変更します。

_with open(path, 'w', encoding = "utf-8") as yaml_file:
    dump = pyyaml.dump(self.dict, default_flow_style = False, allow_unicode = True, encoding = None)
    yaml_file.write( dump )
_

Yaml:

前:

_en:
  test:
    new: "Bye"
    index:
      few: "Hello"
  anothertest: "Something"
_

後:

_en:
  anothertest: Something
  test:
    index:
      few: Hello
    new: Bye
_

同じ形式を保持する方法はありますか?(例えば、qoutesとorder)。これに間違ったツールを使用していますか?

元のファイルが完全に正しいわけではないかもしれませんが、それを制御することはできません(Ruby on Rails i18nファイル)。

どうもありがとうございました。

32
nicosantangelo

代わりに _ruamel.yaml_ を使用します。

図書館ファイト! 2つの図書館の物語

PyYAMLは 事実上無効 であり、数年前から存在しています。さらに複雑なことに、公式プロジェクトのホーム http://pyyaml.org は最近削除されたようです。このサイトは、PyYAML課題トラッカー、ドキュメント、およびダウンロードをホストしていました。これを書いている時点で、すべてはなくなっています。これは災難にほかなりません。オープンソースのちょうど別の日へようこそ。

_ruamel.yaml_は アクティブに維持 です。 PyYAMLとは異なり、_ruamel.yaml_は以下をサポートします。

  • YAML <= 1.2。PyYAMLはYAML <= 1.1のみをサポートします。 YAML 1.2は意図的に 後方互換性を破る いくつかのEdgeのケースでYAML 1.1との関係であるため、これは重要です。これは通常悪いことです。この場合、これにより、YAML 1.2はJSONの厳密なスーパーセットになります。 YAML 1.1はnotJSONの厳密なスーパーセットなので、これは良いことです。
  • ラウンドトリップ保存。yaml.dump()を呼び出して、yaml.load():[への以前の呼び出しによってロードされた辞書をダンプする場合。 ____。]
    • PyYAMLは、コメント、順序付け、引用、空白など、すべての入力フォーマットを単純に無視します。非常に多くのデジタル廃棄物のように、最も近い利用可能なビットバケットに捨てられます。
    • _ruamel.yaml_は、all入力フォーマットを巧みに尊重します。すべて。スタイル全体のエンチラーダ。文学的なシバン全体。 すべて

ライブラリの移行:コードの涙の軌跡

_ruamel.yaml_はPyYAMLフォークであり、したがってPyYAML APIに準拠しているため、既存のアプリケーションでPyYAMLから_ruamel.yaml_に切り替えることは通常、このすべてのインスタンスを置き換えるのと同じくらい簡単です。

_# This imports PyYAML. Stop doing this.
import yaml
_

...これとともに:

_# This imports "ruamel.yaml". Always do this.
from ruamel import yaml
_

それだけです。

他の変更は必要ありません。 yaml.load()およびyaml.dump()関数は引き続き期待どおりに動作するはずです-YAML 1.2をサポートし、バグ修正を積極的に受け取るという追加の利点があります。

往復保存とそれがあなたにできること

PyYamlとの後方互換性のために、yaml.load()およびyaml.dump()関数はデフォルトでラウンドトリップ保存を行いますnot。これを行うには、明示的に渡します:

  • yaml.load()へのオプションの_Loader=ruamel.yaml.RoundTripLoader_キーワードパラメータ。
  • yaml.dump()へのオプションの_Dumper=ruamel.yaml.RoundTripDumper_キーワードパラメータ。

_ruamel.yaml_ documentation から親切に「借りた」例:

_import ruamel.yaml

inp = """\
# example
name:
  # Yet another Great Duke of Hell. He's not so bad, really.
  family: TheMighty
  given: Ashtaroth
"""

code = ruamel.yaml.load(inp, Loader=ruamel.yaml.RoundTripLoader)
code['name']['given'] = 'Astarte'  # Oh no you didn't.

print(ruamel.yaml.dump(code, Dumper=ruamel.yaml.RoundTripDumper), end='')
_

完了です。コメント、順序付け、引用、空白はそのまま保存されます。

tl; dr

常に_ruamel.yaml_を使用します。 PyYAMLを使用しないでください。 _ruamel.yaml_は生きています。 PyYAMLは、PyPiの成形用の納骨堂で腐敗している悪臭を放つ死体です。

長生き_ruamel.yaml_。

72
Cecil Curry

最初の

辞書データを表すには、次のコードを使用します。

mapping = list(mapping.items())
    try:
        mapping = sorted(mapping)
    except TypeError:
        pass

順序が変更される理由です

2番目

スカラー型の表示方法に関する情報(二重引用符付きまたはなし)は、読み取り時に失われます(これはライブラリの主要なアプローチです)

概要

「Dumper」に基づいて独自のクラスを作成し、「represent_mapping」メソッドをオーバーロードして、辞書の表示方法を変更できます。

スカラーの二重引用符に関する情報を保存するには、「ローダー」に基づいて独自のクラスを作成する必要がありますが、他のクラスに影響を与え、それを困難にすることを恐れています

2
Habibutsu

私の場合、値に_"_または_{_が含まれる場合は_}_が必要です。例えば:

_ en:
   key1: value is 1
   key2: 'value is {1}'
_

これを実行するには、モジュールrepresent_str()をファイルPyYamlのファイルrepresenter.pyからコピーし、文字列に_{_または_}_が含まれる場合は別のスタイルを使用します。

_def represent_str(self, data):
    tag = None
    style = None
    # Add these two lines:
    if '{' in data or '}' in data:
        style = '"'
    try:
        data = unicode(data, 'ascii')
        tag = u'tag:yaml.org,2002:str'
    except UnicodeDecodeError:
        try:
            data = unicode(data, 'utf-8')
            tag = u'tag:yaml.org,2002:str'
        except UnicodeDecodeError:
            data = data.encode('base64')
            tag = u'tag:yaml.org,2002:binary'
            style = '|'
    return self.represent_scalar(tag, data, style=style)
_

コードで使用するには:

_import yaml

def represent_str(self, data):
  ...

yaml.add_representer(str, represent_str)
_

この場合、キーと値の間に違いはなく、それで十分です。キーと値に異なるスタイルが必要な場合は、関数_represent_mapping_で同じことを実行します

0
Nelson G.