2017-10-13 52 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)