将YAML文件加载到Python保留别名中



我正在制作一个程序,需要检查某些字段是否使用正确的别名字符串定义。例如:

networks:
base: 
name: build
address: &dummyname
url: 192.168.1.1
port: 8080 
first: 
name: masterA
address: *dummyname
second: 
name: masterB
address: *dummyname

我需要检查字段地址是否用别名"*dummyname"定义在第一和第二,无论别名的内容是什么。

当使用PyYaml执行加载时,总是呈现别名,所以我无法检查:

data = yaml.safe_load(file_data)

数据呈现为python字典:

networks:
base: 
name: build
address: 
url: 192.168.1.1
port: 8080 
first: 
name: masterA
address: 
url: 192.168.1.1
port: 8080 
second: 
name: masterB
address: 
url: 192.168.1.1
port: 8080 

我看到过类似的帖子,以另一种方式,转储python对象到YAML而不创建别名/锚,但我还没有找到解决方案。

如何访问YAML文档中使用的别名?

正如您所指出的,PyYAML不允许您访问锚/别名,它在内部使用它来解决这个问题。当您再次转储data时,您会注意到您获得了一个通用锚(例如&id0001)。

如果您使用ruamel.yaml以这种方式往返您的数据,您可以看到您的保留实际的锚/别名:

import sys
import ruamel.yaml
file_in = Path('input.yaml')

yaml = ruamel.yaml.YAML()
data = yaml.load(file_in)
yaml.dump(data, sys.stdout)

如下所示:

networks:
base:
name: build
address: &dummyname
url: 192.168.1.1
port: 8080
first:
name: masterA
address: *dummyname
second:
name: masterB
address: *dummyname

你可以检查加载的数据结构:

# you get the same object, whether using `first`, `second` or `base`
address = data['networks']['first']['address']
print(address, type(address))
print('n'.join([k for k in dir(address) if k[0] != '_']))  # skip the build-in attributes

给了:

ordereddict([('url', '192.168.1.1'), ('port', 8080)]) <class 'ruamel.yaml.comments.CommentedMap'>
add_referent
add_yaml_merge
anchor
ca
clear
copy
copy_attributes
fa
fromkeys
get
insert
items
keys
lc
merge
mlget
move_to_end
non_merged_items
pop
popitem
rya
setdefault
tag
update
update_key_value
values
yaml_add_eol_comment
yaml_anchor
yaml_end_comment_extend
yaml_key_comment_extend
yaml_set_anchor
yaml_set_comment_before_after_key
yaml_set_start_comment
yaml_set_tag
yaml_value_comment_extend

可能的候选属性是anchor,这实际上是一个Anchor实例可以检索原始字符串:

print(f'anchor: {address.anchor.value}')

给:

anchor: dummyname

请注意,这些类型的内部可能会改变,所以固定ruamel.yaml的版本,你正在使用和升级前测试

最新更新