Python 在不更改格式的情况下更新 YAML

Python update YAML without changing formatting

我想更新 yaml 文件中的特定 属性,同时保持其余部分不变,包括格式、评论等。我正在使用 raumel.yaml。但是当我保存文件时,它的格式被弄乱了。我正在使用 python 3.9.5 和 raumel.yaml 版本:0.17.10.

test.yaml:

sso:
  version: 1.0.0
  configs:
  - configName: config1.conf
    fileContent: 'startDelaySeconds: 0

      lowercaseOutputName: true

      lowercaseOutputLabelNames: false

      whitelistObjectNames: [''org.apache.commons.pool2:*'']

      blacklistObjectNames: []

      rules:

      - pattern: ".*"

      '

我将版本更新为:

from ruamel.yaml import YAML
yaml = YAML()
with open('test.yaml') as f:
    test = yaml.load(f)
test['sso']['version'] = '1.0.1'
with open('test2.yaml', 'w') as f:
    yaml.dump(test, f)

但是保存文件的 fileContent 格式发生了变化(换行符被 \n 等代替)。 test2.yaml:

sso:
  version: 1.0.1
  configs:
  - configName: config1.conf
    fileContent: "startDelaySeconds: 0\nlowercaseOutputName: true\nlowercaseOutputLabelNames:\
      \ false\nwhitelistObjectNames: ['org.apache.commons.pool2:*']\nblacklistObjectNames:\
      \ []\nrules:\n- pattern: \".*\"\n"

您可能错过的是值中的引号 对于您的输出从单引号更改为双引号。默认 ruamel.yaml 不会尝试保留引号,从而能够删除任何多余的 引号,或者在这种情况下使用更紧凑的表示。 在标量中使用不需要单引号的双引号 被复制。

您可以通过设置 .preserve_quotes 属性来保留引号:

import sys
from ruamel.yaml import YAML

yaml = YAML()
yaml.preserve_quotes = True
with open('test.yaml') as f:
    test = yaml.load(f)
test['sso']['version'] = '1.0.1'
yaml.dump(test, sys.stdout)

给出:

sso:
  version: 1.0.1
  configs:
  - configName: config1.conf
    fileContent: 'startDelaySeconds: 0

      lowercaseOutputName: true

      lowercaseOutputLabelNames: false

      whitelistObjectNames: [''org.apache.commons.pool2:*'']

      blacklistObjectNames: []

      rules:

      - pattern: ".*"

      '

我建议考虑对值使用文字样式标量 包含换行符的,因为在那些你不需要加倍换行符的情况下, 也不需要在标量中加双单引号:

yaml_str = """
sso:
  version: 1.0.0
  configs:
  - configName: config1.conf
    fileContent: |
      startDelaySeconds: 0
      lowercaseOutputName: true
      lowercaseOutputLabelNames: false
      whitelistObjectNames: ['org.apache.commons.pool2:*']
      blacklistObjectNames: []
      rules:
      - pattern: ".*"
  
"""

import sys
from ruamel.yaml import YAML

yaml = YAML()
yaml.preserve_quotes = True
with open('test.yaml') as f:
    test = yaml.load(f)

data = yaml.load(yaml_str)
assert data['sso']['configs'][0]['fileContent']  == test['sso']['configs'][0]['fileContent']