如果srv2
是一個關鍵是爲所有在你的YAML映射的唯一,那麼「容易」的方式要循環使用直線,測試去除線條的版本是否以srv2:
開頭,請注意前導空格的數量並註釋掉該行,並按照直到您注意到具有等於或少於前導空格的行。這樣做的好處除了簡單和快捷以外,它可以處理不規則的縮進(例如:在srv1
之前的4個位置和在some-volume
之前的6個位置)。
在使用ruamel.yaml
時也可以這樣做,但不太簡單。您必須知道,當round_trip_loading時,ruamel.yaml通常會對已處理的最後一個結構(映射/序列)附加註釋,並且由於該註釋的結果srv1
在您的示例中完全不同於srv2
(即第一個鍵值對,如果註釋掉,則不同於所有其他鍵值對)。
如果您正常化的預期輸出到四個位置縮進和srv1
之前添加註釋供分析之用,加載,你可以搜索在評論結束:
from ruamel.yaml.util import load_yaml_guess_indent
yaml_str = """\
version: '2'
services:
#a
#b
srv1:
image: alpine
container_name: srv1
volumes:
- some-volume:/some/path
#srv2:
# image: alpine
# container_name: srv2
# volumes_from:
# - some-volume
volumes:
some-volume:
"""
data, indent, block_seq_indent = load_yaml_guess_indent(yaml_str)
print('indent', indent, block_seq_indent)
c0 = data['services'].ca
print('c0:', c0)
c0_0 = c0.comment[1][0]
print('c0_0:', repr(c0_0.value), c0_0.start_mark.column)
c1 = data['services']['srv1']['volumes'].ca
print('c1:', c1)
c1_0 = c1.end[0]
print('c1_0:', repr(c1_0.value), c1_0.start_mark.column)
它打印:
indent 4 2
c0: Comment(comment=[None, [CommentToken(), CommentToken()]],
items={})
c0_0: '#a\n' 4
c1: Comment(comment=[None, None],
items={},
end=[CommentToken(), CommentToken(), CommentToken(), CommentToken(), CommentToken()])
c1_0: '#srv2:\n' 4
所以,你「只」,如果有您註釋掉第一個鍵值對創建第一個類型的註釋(c0
),你必須創建其他(c1
)如果您註釋掉任何行吟詩人r鍵值對。 startmark
是StreamMark()
(來自ruamel/yaml/error.py),創建註釋時該實例的唯一重要屬性爲column
。
幸運的是,上面顯示的過程稍微簡單一些,因爲沒有必要將註釋附加到值volumes
的「結尾」,將它們附加到值爲srv1
的末尾具有相同的效果。
在下面的comment_block
需要一個鍵列表,它是要註釋的元素的路徑。
import sys
from copy import deepcopy
from ruamel.yaml import round_trip_dump
from ruamel.yaml.util import load_yaml_guess_indent
from ruamel.yaml.error import StreamMark
from ruamel.yaml.tokens import CommentToken
yaml_str = """\
version: '2'
services:
srv1:
image: alpine
container_name: srv1
volumes:
- some-volume:/some/path
srv2:
image: alpine
container_name: srv2 # second container
volumes_from:
- some-volume
volumes:
some-volume:
"""
def comment_block(d, key_index_list, ind, bsi):
parent = d
for ki in key_index_list[:-1]:
parent = parent[ki]
# don't just pop the value for key_index_list[-1] that way you lose comments
# in the original YAML, instead deepcopy and delete what is not needed
data = deepcopy(parent)
keys = list(data.keys())
found = False
previous_key = None
for key in keys:
if key != key_index_list[-1]:
if not found:
previous_key = key
del data[key]
else:
found = True
# now delete the key and its value
del parent[key_index_list[-1]]
if previous_key is None:
if parent.ca.comment is None:
parent.ca.comment = [None, []]
comment_list = parent.ca.comment[1]
else:
comment_list = parent[previous_key].ca.end = []
parent[previous_key].ca.comment = [None, None]
# startmark can be the same for all lines, only column attribute is used
start_mark = StreamMark(None, None, None, ind * (len(key_index_list) - 1))
for line in round_trip_dump(data, indent=ind, block_seq_indent=bsi).splitlines(True):
comment_list.append(CommentToken('#' + line, start_mark, None))
for srv in ['srv1', 'srv2']:
data, indent, block_seq_indent = load_yaml_guess_indent(yaml_str)
comment_block(data, ['services', srv], ind=indent, bsi=block_seq_indent)
round_trip_dump(data, sys.stdout,
indent=indent, block_seq_indent=block_seq_indent,
explicit_end=True,
)
它打印:
version: '2'
services:
#srv1:
# image: alpine
# container_name: srv1
# volumes:
# - some-volume:/some/path
srv2:
image: alpine
container_name: srv2 # second container
volumes_from:
- some-volume
volumes:
some-volume:
...
version: '2'
services:
srv1:
image: alpine
container_name: srv1
volumes:
- some-volume:/some/path
#srv2:
# image: alpine
# container_name: srv2 # second container
# volumes_from:
# - some-volume
volumes:
some-volume:
...
(該explicit_end=True
是沒有必要的,這裏用來獲取兩個YAML之間的一些界限自動轉儲)。
以這種方式刪除評論也可以完成。遞歸搜索註釋屬性(.ca
)以查找註釋掉的候選人(可能會提供關於從何處開始的提示)。從註釋中去除前導#
並連接,然後round_trip_load。根據註釋列,您可以確定在哪裏附加未註釋的鍵值對。
我的樣本輸出是嚴格通過4個空格縮進,它的怪異,爲什麼它打印6您的瀏覽器中有空格。 – cherrot
@cherrot在'some-volume:'之前不是,在它們之前有6個短劃線偏移4的縮進(即塊順序縮進)。這當然是你如何計算的,但是像'-a'這樣的序列元素被計數爲縮進2,偏移量爲0.這就是'某個音量'的's'比'v'的'v'卷「,這是計爲6 indents – Anthon
@cherrot這不是我想出的,這是PyYAML只有一個」縮進「控制的映射和序列中的短劃線不計數的結果。我曾經考慮過把它分成兩個參數ruamel.yaml,但遇到了很多問題。添加'block-sequence-indent'是目前我能做的最好的。 – Anthon