【问题标题】:Overwrite variable value in yaml mapping覆盖 yaml 映射中的变量值
【发布时间】:2015-11-07 21:05:05
【问题描述】:

我在yaml 中定义了一个如下所示的映射:

default: &DEFAULT
    bucket: &bucket  default_path
    # Make sure that the second parameter of join doesn't start with a / 
    # otherwise it is interpreted as an absolute path and join won't work
    path1: !!python/object/apply:os.path.join [*bucket, work_area/test1]
    path2: !!python/object/apply:os.path.join [*bucket, work_area/test2]

我需要定义更多键,其中唯一要覆盖的值是bucket,比如:

production:
    <<: *DEFAULT
    bucket: "s3://production-bucket"

但我仍然得到
conf['production']['path1'] => 'default_path/work_area/test1'
而不是
conf['production']['path1'] =&gt; 's3://production-bucket/work_area/test1'.
yaml有没有办法做到这一点?

从语法中可以看出,我使用pyyaml 来解析文件。

【问题讨论】:

  • 您使用的是哪个版本的 PyYAML?在 3.10 中,当我尝试重新定义 bucket 锚时出现 ComposerError。
  • 感谢您的评论。我实际上使用的是 3.11,但我在问题中复制粘贴了错误的大小写。我现在编辑它。当使用`bucket:&bucket "s3://production-bucket"`时我也得到了ComposerError
  • 现在你永远不会重新定义锚bucket。我认为您对映射键使用与锚相同的名称会使自己感到困惑,但这与定义锚(和解析别名)完全无关。看我的回答。

标签: yaml pyyaml


【解决方案1】:

YAML 解释器应采用锚点的最新定义:

别名节点由“*”指示符表示。别名是指具有相同锚点的最近的先前节点。别名节点使用文档中以前未出现的锚是错误的。指定不被任何别名节点使用的锚并不是错误。

因此,即使 PyYAML (3.10/3.11) 在您尝试解析时不会抛出 ComposerError

default: &DEFAULT
    bucket: &bucket  default_path
    # Make sure that the second parameter of join doesn't start with a / 
    # otherwise it is interpreted as an absolute path and join won't work
    path1: !!python/object/apply:os.path.join [*bucket, work_area/test1]
    path2: !!python/object/apply:os.path.join [*bucket, work_area/test2]
production:
    <<: *DEFAULT
    bucket: &bucket "s3://production-bucket"

使用&lt;&lt;: *DEFAULT* 插入path1path2 键将为您提供带有default_path 的扩展版本,因为这是解析器在读取[*bucket, work_area/test1] 时可用的定义

别名的“扩展”是在从 YAML 源读入别名后立即完成的,而不是在文件末尾的某个点,当所有锚定数据都已读入时。


在您更新的示例中,除了标量“default_path”的锚点之外,没有定义其他锚点bucket。对锚点和键使用相同的名称 (bucket) 会让您感到困惑,但键名与解析别名 *bucket 完全无关。

如果您可以重新排列您的 YAML,您可能会通过执行 ¹ 获得一些可以接受的用例:

import ruamel.yaml

yaml_str = """\
default: &DEFAULT
    bucket: &klm default_path
production:
    &klm "s3://production-bucket"
result:
    <<: *DEFAULT
    # Make sure that the second parameter of join doesn't start with a /
    # otherwise it is interpreted as an absolute path and join won't work
    path1: !!python/object/apply:os.path.join [*klm, work_area/test1]
    path2: !!python/object/apply:os.path.join [*klm, work_area/test2]
"""

conf = ruamel.yaml.load(yaml_str)
print(conf['result']['path1'])

这会给你:

s3://production-bucket/work_area/test1

¹ 这是使用ruamel.yaml 完成的,我是其中的作者。

【讨论】:

    猜你喜欢
    • 2016-09-20
    • 1970-01-01
    • 2018-05-23
    • 1970-01-01
    • 2012-02-20
    • 2021-06-10
    • 2015-12-27
    • 2018-09-01
    • 1970-01-01
    相关资源
    最近更新 更多