web-dev-qa-db-ja.com

pythonを使用してyamlファイルを更新する方法

私はsome.yaml以下の内容のファイル。

    init_config: {}
    instances:
        - Host: <IP>
          username: <username>
          password: <password>

Yamlファイルは、以下のように解析および更新する必要があります。

    init_config: {}
    instances:
        - Host: 1.2.3.4
          username: Username
          password: Password

値を解析して適切に更新するにはどうすればよいですか?

16
Chetan

ruamel.yaml パッケージは、この種のラウンドトリップ、プログラムによる更新を行うために(PyYAMLから始めて)特に強化されました。

で始まる場合(余分な初期スペースを削除したことに注意してください):

init_config: {}
instances:
    - Host: <IP>              # update with IP
      username: <username>    # update with user name
      password: <password>    # update with password

そして実行:

import ruamel.yaml

file_name = 'input.yaml'
config, ind, bsi = ruamel.yaml.util.load_yaml_guess_indent(open(file_name))

instances = config['instances']
instances[0]['Host'] = '1.2.3.4'
instances[0]['username'] = 'Username'
instances[0]['password'] = 'Password'

with open('output.yaml', 'w') as fp:
    yaml.dump(config, fp)

出力は次のようになります。

init_config: {}
instances:
    - Host: 1.2.3.4           # update with IP
      username: Username      # update with user name
      password: Password      # update with password

マッピングキーの順序(Hostusernameおよびpassword)、スタイル、およびコメントそれ以上の特定のアクションなしで保存されます。

インデントとブロックシーケンスのインデントを推測する代わりに、手動で従来のロードを実行し、インデント値を自分で設定できます。

yaml = ruamel.yaml.YAML()
yaml.indent(mapping=6, sequence=4)
with open(file_name) as fp:
    config = yaml.load(fp)

この回答の履歴を見ると、より制限されたPyYAMLのようなAPIでこれを行う方法がわかります。

17
Anthon

これは、上記のファイルから読み取り、必要に応じて解析および更新する方法です。

import yaml

fname = "some.yaml"

stream = open(fname, 'r')
data = yaml.load(stream)

data['instances'][0]['Host'] = '1.2.3.4'
data['instances'][0]['username'] = 'Username'
data['instances'][0]['password'] = 'Password'

with open(fname, 'w') as yaml_file:
    yaml_file.write( yaml.dump(data, default_flow_style=False))
8
Chetan

YAMLが必要かどうかわかりません。 YAMLタグの使用は別として、YAMLドキュメントには関心がないようです。それでは、なぜJinja2またはテンプレート言語を使用しないのでしょうか?

from jinja2 import Template

tmpl = Template(u'''\
    init_config: {}
    instances:
         - Host: {{ IP }}
           username: {{ username }}
           password: {{ password }}
''')

print tmpl.render(
     IP=u"1.2.3.4",
     username=u"Username",
     password=u"Password"
)

良いアイデアかどうかはわかりませんが、一部のフィールドが変更されたファイルを取得するだけであれば、YAMLドキュメントを実際に解析する必要はなく、テンプレート言語を直接利用できます。


ボーナス:ユースケース

タグが不明な非常に複雑なYAMLドキュメントを扱ってきました

...
  propertiesIDs: { 1, 2, 3, 4 }
  globalID: !myapplication.InterfaceID &primitiveID

replication: !myapplication.replication
  beginDate: 2012-09-10T20:00:03
  endDate: 2020-09-10T20:00:04
  replicant_uuid:
    ? 17169504-B6AB-11E4-8437-36E258BB2172
    ? 206B5842-B6AB-11E4-AAC3-36E258BB2172
...

このドキュメントの有効な解析を実行することは難しく、時間がかかります。いくつかの値を設定するだけで、YAMLがサードパーティアプリケーションに送信されます。そのため、YAMLを解析したり、pyyamlを使用して有効なドキュメントを直接生成しようとする代わりに、テンプレートを使用して直接生成する方が簡単です(時間効率が高く、バグが発生しにくい)。さらに、テンプレート言語をループで簡単に使用して、動的にサイズ設定されたフィールドを設定できます。

4
MariusSiuram

開発者、プロダクション、ステージなどのドッカークレーンテンプレートを生成する方法は次のとおりです。

  1. mkdir crane_templates
  2. クレーン_テンプレートをタッチ/init.py
  3. Nano crane_templates/some.yamlを使用してテンプレートコンテンツを追加する
  4. ナノクレーン_gen.py

--- crane_gen.py ---

#!/usr/bin/env python
from jinja2 import Environment, PackageLoader

env = Environment(loader=PackageLoader('crane_templates', './'))
tmpl = env.get_template('crane.yaml.tmpl')

result = tmpl.render(
     IP=u"1.2.3.4",
     username=u"Username",
     password=u"Password"
)

5. python crane_gen.py> result.yaml

@MariusSiuramに触発された回答

1
Kostyantyn

以下は、PyYamlを使用したサンプルです。私が理解しているように、あなたはyaml形式のテンプレートのようなものを持っているので、山括弧内の場所を実際の値に置き換える必要があります。

import yaml

s = """
    init_config: {}
    instances:
        - Host: <IP>
          username: <username>
          password: <password>
"""

dict_obj = yaml.load(s) # loads string in internal data structure - dict
dict_obj['instances'][0]['Host'] = 'localhost' # change values
print yaml.dump(dict_obj) # dumps dict to yaml format back
0
Deck