如何对齐 ruamel.yaml 中的 eol 注释,使它们都在同一列中
How do I align the eol comments in ruamel.yaml so that they are all in the same column
我目前正在使用一些配置值自动生成 YAML 文件。
有时这些值附有注释,注释会添加到 YAML 文件中。
简单示例
import sys
from ruamel.yaml import CommentedMap, YAML
top = CommentedMap()
top['sub_key1'] = data = CommentedMap()
data['a'] = 1
data['b'] = 'asdf'
data['c'] = 3.3333
data.yaml_add_eol_comment('comment 1', 'a')
data.yaml_add_eol_comment('comment 2', 'b')
data.yaml_add_eol_comment('comment 3', 'c')
top['sub_key2'] = data = CommentedMap()
data['a'] = 'long text'
data['b'] = 'an even longer text'
data.yaml_add_eol_comment('comment 4', 'a')
data.yaml_add_eol_comment('comment 5', 'b')
YAML().dump(top, sys.stdout)
这有效并按预期输出
sub_key1:
a: 1 # comment 1
b: asdf # comment 2
c: 3.3333 # comment 3
sub_key2:
a: long text # comment 4
b: an even longer text # comment 5
但是我真的很想像这样对齐注释(或者在值后有两个空格更好)。
sub_key1:
a: 1 # comment 1
b: asdf # comment 2
c: 3.3333 # comment 3
sub_key2:
a: long text # comment 4
b: an even longer text # comment 5
添加eol注释时无法使用column参数,因为column从一开始就是绝对的,我不知道
- 我在哪个级别
- 生成的 key/value 对有多长
- 当前缩进多少i
有什么方法可以在创建后对齐评论吗?
您可以在不设置列的情况下进行转储,读回生成的 YAML 并进行分析
评论结构 ( data['sub_key1']ca.items
) 以获得最大的列值,然后
使用该值再转储一次。
或者当您的数据加载了评论时,只需将评论中的所有列值设置为
最大值或最大值加一得到最长值后两个空格:
import sys
import io
from ruamel.yaml import CommentedMap, YAML
yaml = YAML()
top = CommentedMap()
top['sub_key1'] = data = CommentedMap()
data['a'] = 1
data['b'] = 'asdf'
data['c'] = 3.3333
data.yaml_add_eol_comment('comment 1', 'a')
data.yaml_add_eol_comment('comment 2', 'b')
data.yaml_add_eol_comment('comment 3', 'c')
top['sub_key2'] = data = CommentedMap()
data['a'] = 'long text'
data['b'] = 'an even longer text'
data.yaml_add_eol_comment('comment 4', 'a')
data.yaml_add_eol_comment('comment 5', 'b')
buf = io.BytesIO()
yaml.dump(top, buf)
top = yaml.load(buf.getvalue())
def align_comments(d, extra=0):
def align_one(d, extra=0):
comments = d.ca.items.values()
if not comments:
return
max = -1
for comment in comments:
if comment[2].column > max:
max = comment[2].column
for comment in comments:
comment[2].column = max + extra
if isinstance(d, dict):
align_one(d, extra=extra)
for val in d.values():
align_comments(val, extra=extra)
elif isinstance(d, list):
align_one(d, extra=extra)
for elem in d:
align_comments(elem, extra=extra)
align_comments(top, extra=1)
yaml.dump(top, sys.stdout)
给出:
sub_key1:
a: 1 # comment 1
b: asdf # comment 2
c: 3.3333 # comment 3
sub_key2:
a: long text # comment 4
b: an even longer text # comment 5
确保固定您正在使用的 ruamel.yaml
版本。由于这些内部结构
会改变。
@Anthon:
为了更好的可读性,我稍微修改了你的例子。
感谢您的帮助
def align_comments(d, extra_indent=0):
is_dict = isinstance(d, dict)
if not is_dict and not isinstance(d, list):
return None
comments = d.ca.items.values()
if comments:
max_col = max(map(lambda x: x[2].column, comments), default=0)
for comment in comments:
comment[2].column = max_col + extra_indent
for element in (d.values() if is_dict else d):
align_comments(element, extra_indent=extra_indent)
return None
用法:
buf = io.BytesIO()
yaml.dump(top, buf)
top = yaml.load(buf.getvalue())
align_comments(top, extra=1)
yaml.dump(top, sys.stdout)
我目前正在使用一些配置值自动生成 YAML 文件。 有时这些值附有注释,注释会添加到 YAML 文件中。
简单示例
import sys
from ruamel.yaml import CommentedMap, YAML
top = CommentedMap()
top['sub_key1'] = data = CommentedMap()
data['a'] = 1
data['b'] = 'asdf'
data['c'] = 3.3333
data.yaml_add_eol_comment('comment 1', 'a')
data.yaml_add_eol_comment('comment 2', 'b')
data.yaml_add_eol_comment('comment 3', 'c')
top['sub_key2'] = data = CommentedMap()
data['a'] = 'long text'
data['b'] = 'an even longer text'
data.yaml_add_eol_comment('comment 4', 'a')
data.yaml_add_eol_comment('comment 5', 'b')
YAML().dump(top, sys.stdout)
这有效并按预期输出
sub_key1:
a: 1 # comment 1
b: asdf # comment 2
c: 3.3333 # comment 3
sub_key2:
a: long text # comment 4
b: an even longer text # comment 5
但是我真的很想像这样对齐注释(或者在值后有两个空格更好)。
sub_key1:
a: 1 # comment 1
b: asdf # comment 2
c: 3.3333 # comment 3
sub_key2:
a: long text # comment 4
b: an even longer text # comment 5
添加eol注释时无法使用column参数,因为column从一开始就是绝对的,我不知道
- 我在哪个级别
- 生成的 key/value 对有多长
- 当前缩进多少i
有什么方法可以在创建后对齐评论吗?
您可以在不设置列的情况下进行转储,读回生成的 YAML 并进行分析
评论结构 ( data['sub_key1']ca.items
) 以获得最大的列值,然后
使用该值再转储一次。
或者当您的数据加载了评论时,只需将评论中的所有列值设置为 最大值或最大值加一得到最长值后两个空格:
import sys
import io
from ruamel.yaml import CommentedMap, YAML
yaml = YAML()
top = CommentedMap()
top['sub_key1'] = data = CommentedMap()
data['a'] = 1
data['b'] = 'asdf'
data['c'] = 3.3333
data.yaml_add_eol_comment('comment 1', 'a')
data.yaml_add_eol_comment('comment 2', 'b')
data.yaml_add_eol_comment('comment 3', 'c')
top['sub_key2'] = data = CommentedMap()
data['a'] = 'long text'
data['b'] = 'an even longer text'
data.yaml_add_eol_comment('comment 4', 'a')
data.yaml_add_eol_comment('comment 5', 'b')
buf = io.BytesIO()
yaml.dump(top, buf)
top = yaml.load(buf.getvalue())
def align_comments(d, extra=0):
def align_one(d, extra=0):
comments = d.ca.items.values()
if not comments:
return
max = -1
for comment in comments:
if comment[2].column > max:
max = comment[2].column
for comment in comments:
comment[2].column = max + extra
if isinstance(d, dict):
align_one(d, extra=extra)
for val in d.values():
align_comments(val, extra=extra)
elif isinstance(d, list):
align_one(d, extra=extra)
for elem in d:
align_comments(elem, extra=extra)
align_comments(top, extra=1)
yaml.dump(top, sys.stdout)
给出:
sub_key1:
a: 1 # comment 1
b: asdf # comment 2
c: 3.3333 # comment 3
sub_key2:
a: long text # comment 4
b: an even longer text # comment 5
确保固定您正在使用的 ruamel.yaml
版本。由于这些内部结构
会改变。
@Anthon: 为了更好的可读性,我稍微修改了你的例子。 感谢您的帮助
def align_comments(d, extra_indent=0):
is_dict = isinstance(d, dict)
if not is_dict and not isinstance(d, list):
return None
comments = d.ca.items.values()
if comments:
max_col = max(map(lambda x: x[2].column, comments), default=0)
for comment in comments:
comment[2].column = max_col + extra_indent
for element in (d.values() if is_dict else d):
align_comments(element, extra_indent=extra_indent)
return None
用法:
buf = io.BytesIO()
yaml.dump(top, buf)
top = yaml.load(buf.getvalue())
align_comments(top, extra=1)
yaml.dump(top, sys.stdout)