2017-10-13 45 views
0

我正在寻找几天,试图找出为什么我的yaml解析器(使用PyYaml)不保存YAML,因为它处于原始状态。python yaml包解析不需要的新行

在YAML原线路:

healthcheck: 
    test: ["CMD-SHELL", "[ x\"`curl -k --silent -w '%{http_code}' https://localhost:4433 | grep 401`\" = x\"\" ] && exit 1 || exit 0"]  
    interval: 30s 

但新线(只需加载该文件,并再次将其保存回):

healthcheck: 
     interval: 30s 
     test: 
     - CMD-SHELL 
     - '[ x"`curl -k --silent -w ''%{http_code}'' https://localhost:4433 | grep 401`" 
     = x"" ] && exit 1 || exit 0' 

有这里有两个问题: 1) “测试”值成为列表而不是1行键值对。 2)其实有3 新线这里,

a) -CMD-SHELL 
b)- '[ x"`curl -k --silent -w ''%{http_code}'' https://localhost:4433 | grep 401`" 
c)= x"" ] && exit 1 || exit 0' 

所以另一个问题是,为什么第三行是从第二线坏了吗? (如果我显示空格,你会看到在第二行的末尾有LF ,然后开始第三行

回答

1

我想你可能会对YAML语法一些误解。这样的:如果我把你的例子为

- "This is a 
    string value" 

test: ["this", "is", "a", "list"] 

完全等价的:

test: 
    - this 
    - is 
    - a 
    - list 

而且这样的:

- "This is a string value" 

完全等价一个文件data.yml

$ cat data.yml 
healthcheck: 
    test: ["CMD-SHELL", "[ x\"`curl -k --silent -w '%{http_code}' https://localhost:4433 | grep 401`\" = x\"\" ] && exit 1 || exit 0"] 
    interval: 30s 

然后用PyYAML分析它:

>>> import yaml 
>>> with open('data.yml') as fd: 
... data = yaml.load(fd) 
... 

我得到以下Python数据结构:

>>> pprint.pprint(data) 
{'healthcheck': {'interval': '30s', 
       'test': ['CMD-SHELL', 
          '[ x"`curl -k --silent -w \'%{http_code}\' https://localhost:4433 | grep 401`" = x"" ] && exit 1 || exit 0']}} 

如果我倾倒,使用PyYAML,我得到:

>>> print yaml.dump(data) 
healthcheck: 
    interval: 30s 
    test: [CMD-SHELL, '[ x"`curl -k --silent -w ''%{http_code}'' https://localhost:4433 
     | grep 401`" = x"" ] && exit 1 || exit 0'] 

...这似乎很好。我可以要求更详细的列表语法,在这种情况下,我让你在你的例子显示什么:

>>> print yaml.dump(data, default_flow_style=False) 
healthcheck: 
    interval: 30s 
    test: 
    - CMD-SHELL 
    - '[ x"`curl -k --silent -w ''%{http_code}'' https://localhost:4433 | grep 401`" 
    = x"" ] && exit 1 || exit 0' 

...这将解析到完全相同的Python数据结构与原文档。除了“看起来不同”之外,实际数据是相同的。

0

PyYAML在保存往返行程风格方面不是很好(加载,修改,安全),它实际上可能不会像使用其加载/转储参数一样保留输入。为此,您需要修改PyYAML分析器。

这就是ruamel.yaml(免责声明:我是该作者的作者包),这是专门开发,以支持此类程序化往返(包括保留意见):

import sys 
import ruamel.yaml 
from pathlib import Path 

yaml_file = Path('test.yaml') 
out_file = Path('out.yaml') 

yaml = ruamel.yaml.YAML() 
yaml.width = 2048 
yaml.preserve_quotes = True 
data = yaml.load(yaml_file) 
yaml.dump(data, out_file) 

这给你out.yamltest.yaml完全相同的内容。

默认宽度(80)将像PyYAML中那样包裹线条,因此将其设置为比最大长度线更长的东西。 preserve_quotes是必要的,否则"CMD-SHELL"中的多余引号将会丢失。

上述假设的Python 3(对于pathlib),如果你仍然运行Python 2可以用手在正确打开普通文件句柄:

with open('test.yaml') as fp: 
    data = yaml.load(fp) 
with open('out.yaml', 'w') as fp: 
    yaml.dump(data, fp)