通过 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'):