通过 Python 中的字符串表示形式对加载的 yaml 进行字典查找
Dictionary lookup of loaded yaml via a string representation in Python
所以我正在使用 ruamel 读取位于 github 的 yaml 文件,一切顺利。我可以看到它已正确加载。现在我的场景是这个负载在我正在访问的 class 中的一个函数中。现在这个函数有一个字符串变量 "entry" 这是我想要搜索的。目标是在不同的深度进行搜索,我知道位置,所以我不会去寻找它。
Yaml 文件示例:
description: temp_file
image: beta1
group: dev
depends:
- image: base
basetag: 1.0.0
入口字符串变量传入
我想为变量 "entry" 保留一个字符串,就好像使用 .get 查找顶级查找一样 return 我的值就好了。只是如果我想收集类似 ["depends"][0]["image"] 的值之类的东西,我无法弄清楚如何构建它以便我可以进行正确的获取。
entry = "image" # works fine
entry = '["depends"][0]["image"]' #never works
gho.get_entry_from_ivpbuild_yml(repo, commit, entry)
Class中的代码
# imports
from ruamel.yaml import YAML
yaml = YAML()
yaml.preserve_quotes = True
def get_entry_from_loaded_yml(self, repo, commit, entry, failflag=True):
"""
:param repo: str (github repo)
:param commit: str (sha of commit to view)
:param entry: str (entry within yml you want to search for)
:param failflag: bool (Determines if script fails or not if entry is not found within yaml)
:return: str: (value of entry in yml you want to search for)
"""
yml_file = "sample.yaml"
try:
logger.debug("opening yaml for commit:{}".format(commit))
yml = self.gho.get_repo(repo).get_file_contents(yml_file, commit)
except Exception as e:
logger.error("Could not open yaml file:{} for repo:{} commit:{}:{}".format(yml_file, repo, commit, e))
sys.exit(1)
loaded = yaml.load(yml.decoded_content)
if not loaded.get(entry, default=None):
logger.error("Could not find value for {} in {}".format(entry, yml_file))
if failflag:
sys.exit(1)
return None
如您所知,您不能将字符串 '["depends"][0]["image"]'
之类的内容传递给 dict.get
并期望它起作用。但是,如果您确实需要在这样的嵌套数据结构中为对象指定 "path",则有几个选项。
第一种是显式执行,只传递一系列键而不是单个键:
def get_entry_from_loaded_yml(self, repo, commit, entry_keys, failflag=True):
# ...
try:
entry = loaded
for key in entry_keys:
entry = entry[key]
except LookupError:
logger.error("Could not find value for {} in {}".format(entry, yml_file))
if failflag:
sys.exit(1)
return None
else:
return entry
现在,您可以这样做:
gho.get_entry_from_ivpbuild_yml(repo, commit, ('depends', 0, 'image'))
或者,您可以使用处理 "key paths" 的库,格式如 dpath
(本质上是 XPath 的简化版本)或 ObjectiveC 的 KVC。 PyPI 上有多个库可以执行此操作(尽管有些库处理未解码的 JSON 字符串而不是解码的嵌套对象,以允许有效地搜索巨大的 JSON 文本;那些显然不适合你......我不知道有什么可以在 YAML 而不是 JSON 上工作,但它们可能存在)。那么您的代码将如下所示:
def get_entry_from_loaded_yml(self, repo, commit, entry, failflag=True):
# ...
result = dpath_search(loaded, entry, default=None):
if result is None:
logger.error("Could not find value for {} in {}".format(entry, yml_file))
if failflag:
sys.exit(1)
return None
else:
return result
# ...
gho.get_entry_from_ivpbuild_yml(repo, commit, 'depends/0/image')
这样做的好处是,如果您需要查找一个(可能嵌套的)多个值序列,它可以像这样简单:
for result in dpath_search(loaded, 'depends/*/image'):
所以我正在使用 ruamel 读取位于 github 的 yaml 文件,一切顺利。我可以看到它已正确加载。现在我的场景是这个负载在我正在访问的 class 中的一个函数中。现在这个函数有一个字符串变量 "entry" 这是我想要搜索的。目标是在不同的深度进行搜索,我知道位置,所以我不会去寻找它。
Yaml 文件示例:
description: temp_file
image: beta1
group: dev
depends:
- image: base
basetag: 1.0.0
入口字符串变量传入
我想为变量 "entry" 保留一个字符串,就好像使用 .get 查找顶级查找一样 return 我的值就好了。只是如果我想收集类似 ["depends"][0]["image"] 的值之类的东西,我无法弄清楚如何构建它以便我可以进行正确的获取。
entry = "image" # works fine
entry = '["depends"][0]["image"]' #never works
gho.get_entry_from_ivpbuild_yml(repo, commit, entry)
Class中的代码
# imports
from ruamel.yaml import YAML
yaml = YAML()
yaml.preserve_quotes = True
def get_entry_from_loaded_yml(self, repo, commit, entry, failflag=True):
"""
:param repo: str (github repo)
:param commit: str (sha of commit to view)
:param entry: str (entry within yml you want to search for)
:param failflag: bool (Determines if script fails or not if entry is not found within yaml)
:return: str: (value of entry in yml you want to search for)
"""
yml_file = "sample.yaml"
try:
logger.debug("opening yaml for commit:{}".format(commit))
yml = self.gho.get_repo(repo).get_file_contents(yml_file, commit)
except Exception as e:
logger.error("Could not open yaml file:{} for repo:{} commit:{}:{}".format(yml_file, repo, commit, e))
sys.exit(1)
loaded = yaml.load(yml.decoded_content)
if not loaded.get(entry, default=None):
logger.error("Could not find value for {} in {}".format(entry, yml_file))
if failflag:
sys.exit(1)
return None
如您所知,您不能将字符串 '["depends"][0]["image"]'
之类的内容传递给 dict.get
并期望它起作用。但是,如果您确实需要在这样的嵌套数据结构中为对象指定 "path",则有几个选项。
第一种是显式执行,只传递一系列键而不是单个键:
def get_entry_from_loaded_yml(self, repo, commit, entry_keys, failflag=True):
# ...
try:
entry = loaded
for key in entry_keys:
entry = entry[key]
except LookupError:
logger.error("Could not find value for {} in {}".format(entry, yml_file))
if failflag:
sys.exit(1)
return None
else:
return entry
现在,您可以这样做:
gho.get_entry_from_ivpbuild_yml(repo, commit, ('depends', 0, 'image'))
或者,您可以使用处理 "key paths" 的库,格式如 dpath
(本质上是 XPath 的简化版本)或 ObjectiveC 的 KVC。 PyPI 上有多个库可以执行此操作(尽管有些库处理未解码的 JSON 字符串而不是解码的嵌套对象,以允许有效地搜索巨大的 JSON 文本;那些显然不适合你......我不知道有什么可以在 YAML 而不是 JSON 上工作,但它们可能存在)。那么您的代码将如下所示:
def get_entry_from_loaded_yml(self, repo, commit, entry, failflag=True):
# ...
result = dpath_search(loaded, entry, default=None):
if result is None:
logger.error("Could not find value for {} in {}".format(entry, yml_file))
if failflag:
sys.exit(1)
return None
else:
return result
# ...
gho.get_entry_from_ivpbuild_yml(repo, commit, 'depends/0/image')
这样做的好处是,如果您需要查找一个(可能嵌套的)多个值序列,它可以像这样简单:
for result in dpath_search(loaded, 'depends/*/image'):