在ruamel中使用构造_undefined from_yaml

在ruamel中使用构造_undefined from_yaml,yaml,ruamel.yaml,Yaml,Ruamel.yaml,我正在创建一个自定义yaml标记MyTag。它可以包含任何给定的有效yaml映射、标量、锚点、序列等 如何实现类MyTag来对该标记建模,以便ruamel解析的内容!mytag与解析任何给定yaml的方式完全相同?MyTag实例只存储yaml内容的解析结果 下面的代码可以工作,断言应该准确地演示它应该做什么,并且它们都可以通过 但我不确定它是否有正确的原因。特别是在from_yaml类方法中,使用注释的\u obj=constructor.construct_undefined(node)是实现

我正在创建一个自定义yaml标记MyTag。它可以包含任何给定的有效yaml映射、标量、锚点、序列等

如何实现类MyTag来对该标记建模,以便ruamel解析
的内容!mytag
与解析任何给定yaml的方式完全相同?
MyTag
实例只存储yaml内容的解析结果

下面的代码可以工作,断言应该准确地演示它应该做什么,并且它们都可以通过

但我不确定它是否有正确的原因。特别是在
from_yaml
类方法中,使用
注释的\u obj=constructor.construct_undefined(node)
是实现这一点的推荐方法,并且从生成的生成器中消耗1且仅消耗1是正确的吗?这不仅仅是偶然发生的

我应该改为使用类似于
construct\u object
,或
construct\u map
或。?我能找到的示例往往知道它正在构造什么类型,因此可以使用
construct\u map
construct\u sequence
选择要构造的对象类型。在这种情况下,我实际上是想利用通常/标准的ruamel解析来处理其中可能存在的任何未知类型,并将其存储在自己的类型中

导入ruamel.yaml
从ruamel.yaml.comments导入CommentedMap、CommentedSeq、TaggedScalar
类MyTag():
yaml_标签='!mytag'
定义初始值(自身,值):
自我价值=价值
@类方法
来自_yaml的def(cls、构造函数、节点):
注释的\u obj=构造函数。构造\u未定义(节点)
flag=False
对于注释对象中的数据:
如果标志:
raise AssertionError('在生成器中应仅为1件事??)
flag=True
返回cls(数据)
打开('mytag-sample.yaml')作为yaml_文件:
yaml_parser=ruamel.yaml.yaml()
yaml_解析器.寄存器_类(MyTag)
yaml=yaml\u parser.load(yaml\u文件)
自定义标签,标签列表=yaml['root'][0]['arb']['k2']
断言类型(带有列表的自定义标记)为MyTag
断言类型(带有列表值的自定义标记)为CommentedSeq
打印(带有列表值的自定义标签)
标准列表=yaml['root'][0]['arb']['k3']
断言类型(标准_列表)为注释seq
断言标准\u列表==带有\u list.value的自定义\u标记\u
自定义_标记_,带有_map=yaml['root'][1]['arb']
断言类型(带有映射的自定义标记)为MyTag
断言类型(带有映射值的自定义标记)为CommentedMap
打印(带有映射值的自定义标记)
标准映射=yaml['root'][1]['arb\u no\u tag']
断言类型(标准映射)为CommentedMap
断言标准\u映射==带有\u map.value的自定义\u标记\u
自定义标记标量=yaml['root'][2]
断言类型(自定义标记标量)为MyTag
断言类型(custom_tag_scalar.value)是TaggedScalar
标准标签标量=yaml['root'][3]
断言类型(标准标记标量)为str
断言标准标记标量==str(自定义标记标量.value)
和一些样本yaml:

根目录:
-项目:废话
仲裁委员会:
k1:v1
k2:!我的标签
-一个
-两个
-三-k1:三-v1
3-k2:3-v2
three-k3:123#arb评论
三-k4:
-a
-b
-真的
k3:
-一个
-两个
-三-k1:三-v1
3-k2:3-v2
three-k3:123#arb评论
三-k4:
-a
-b
-真的
-项目:argh
阿尔布:!我的标签
k1:v1
k2:123
#废话第1行
#废话第二行
k3:
k31:v31
k32:
-假的
-系在这里
- 321
arb_无标签:
k1:v1
k2:123
#废话第1行
#废话第二行
k3:
k31:v31
k32:
-假的
-系在这里
- 321
- !mytag纯标量
-纯标量
-项目:无可奉告
仲裁委员会:
-一
-两个2

在YAML中,您可以使用锚定和别名,而将对象作为其自身的子对象(使用别名)是非常好的。如果要转储Python数据结构
数据

data = [1, 2, 4, dict(a=42)]
data[3]['b'] = data
它转储到:

&id001
- 1
- 2
- 4
- a: 42
  b: *id001
为此,锚和别名是必要的

加载这样的构造时,ruamel.yaml会递归到嵌套的数据结构中,但如果顶级节点没有导致构造一个锚可以引用的真实对象,则递归叶无法解析别名

为了解决这个问题,除了标量值之外,还使用了一个生成器。它首先创建一个空对象,然后递归并更新它的值。在调用构造函数的代码中,检查是否返回了生成器,在这种情况下,对数据执行
next()
,并“解决”潜在的自递归

因为您调用
construct\u undefined()
,所以始终会得到一个生成器。实际上,如果该方法检测到标量节点(当然不能递归),则该方法可以返回一个值,但它不会。如果会,您的代码将无法加载以下YAML文档:

!mytag 1

在没有修改的情况下,测试是否有生成器,正如ruamel.yaml中调用各种构造函数的代码所做的那样,它可以处理
construct\u undefined
construct\u yaml\u int
(它不是生成器)。

在yaml中,可以有锚和别名,让一个对象成为它自己的子对象(使用别名)是非常好的。如果要转储Python数据结构
数据

data = [1, 2, 4, dict(a=42)]
data[3]['b'] = data
它转储到:

&id001
- 1
- 2
- 4
- a: 42
  b: *id001
为此,锚和别名是必要的

加载这样的构造时,ruamel.yaml会递归到嵌套的数据结构中,但如果顶级节点没有导致构造一个锚可以引用的真实对象,则递归叶无法解析别名

为了解决这个问题,除了标量值之外,还使用了一个生成器。信息技术