[英]ruamel.yaml custom CommentedMapping for custom tags
我有一個帶有自定義標簽的 YAML 文件,如下所示:
flow123d_version: 3.1.0
problem: !modulek.Coupling_Sequential
description: Simple dual porosity test - steady flow, simple transport
mesh:
mesh_file: ../00_mesh/square_1x1_40el.msh
flow_equation: !Flow_Darcy_MH
nonlinear_solver:
linear_solver: !Petsc
a_tol: 1.0e-07
到目前為止,我的代碼可以加載它並將其轉儲回來。 我的問題是我希望能夠檢查每個自定義!
並檢查其他文件是否正確。 讓我們看看我的文件的第二行。 你可以看到我的第一個自定義標簽,它由 module.class_name 組成,我需要檢查它們。 我想將“modulek”解析為模塊,將“Coupling_Sequential”解析為 class_name。 我的代碼看起來像這樣。
import types
import re
import ruamel.yaml as ruml
from ruamel.yaml.comments import CommentedMap, CommentedSeq
CommentsTag = ruml.comments.Tag
class CommentedScalar:
"""
Class to store all scalars with their tags
"""
original_constructors = {}
def __str__(self):
return str(self.value)
def __repr__(self):
return str(self.value)
@classmethod
def to_yaml(cls, dumper, data):
representer = dumper.yaml_representers[type(data.value).__mro__[0]]
node = representer(dumper, data.value)
if data.tag.value is None:
tag = node.tag
elif data.tag.value.startswith(u'tag:yaml.org,2002'):
tag = node.tag
else:
tag = data.tag.value
# print("val: ", data.value, "repr: ", node.value, "tag: ", tag)
return dumper.represent_scalar(tag, node.value)
def __init__(self, tag, value):
complete_tag = tag.split('.')
self.tag.value = tag
self.value = value
# self.module.value = complete_tag
self.module = '.'.join(complete_tag[:len(complete_tag) - 1])
self.class_name = complete_tag[-1]
@property
def tag(self):
# type: () -> Any
if not hasattr(self, CommentsTag.attrib):
setattr(self, CommentsTag.attrib, CommentsTag())
return getattr(self, CommentsTag.attrib)
def construct_any_tag(self, tag_suffix, node):
if tag_suffix is None:
orig_tag = None
else:
orig_tag = "!" + tag_suffix
if isinstance(node, ruml.ScalarNode):
implicit_tag = self.composer.resolver.resolve(ruml.ScalarNode, node.value, (True, None))
if implicit_tag in self.yaml_constructors:
# constructor = CommentedScalar.original_constructors[implicit_tag]
constructor = self.yaml_constructors[implicit_tag]
else:
constructor = self.construct_undefined
data = constructor(self, node)
if isinstance(data, types.GeneratorType):
generator = data
data = next(generator) # type: ignore
scal = CommentedScalar(orig_tag, data)
yield scal
elif isinstance(node, ruml.SequenceNode):
for seq in self.construct_yaml_seq(node):
seq.yaml_set_tag(orig_tag)
yield seq
elif isinstance(node, ruml.MappingNode):
for map in self.construct_yaml_map(node):
map.yaml_set_tag(orig_tag)
yield map
else:
for dummy in self.construct_undefined(node):
yield dummy
def represent_commented_seq(cls, data):
if data.tag.value is None:
tag = u'tag:yaml.org,2002:seq'
else:
tag = data.tag.value
return cls.represent_sequence(tag, data)
def get_yaml_serializer():
"""
Get YAML serialization/deserialization object with proper
configuration for conversion.
:return: Confugured instance of ruamel.yaml.YAML.
"""
yml = ruml.YAML(typ='rt')
yml.indent(mapping=2, sequence=4, offset=2)
yml.width = 120
yml.representer.add_representer(CommentedScalar, CommentedScalar.to_yaml)
yml.representer.add_representer(CommentedSeq, represent_commented_seq)
yml.representer.add_representer(CommentedMap, CommentedMapping.to_yaml)
yml.constructor.add_multi_constructor("!", construct_any_tag)
return yml
def get_node_tag(node):
if hasattr(node, "tag"):
tag = node.tag.value
if tag and len(tag) > 1 and tag[0] == '!' and tag[1] != '!':
return tag
return ""
def load_yaml(path):
yml = get_yaml_serializer()
with open(path, 'r') as stream:
data = yml.load(stream)
return data
def write_yaml(data, path):
yml = get_yaml_serializer()
with open(path, 'w')as stream:
yml.dump(data, stream)
我正在考慮編寫類似於 CommentedScalar 的“CommentedMapping”,但我被困在這里並且找不到任何工作。
@classmethod
def to_yaml(cls, dumper, data):
...
...
return ???
概括
如果有人將我推向正確的方向,我會很高興。 我什至不知道這是否是正確的方法。
YAML 輸入中所有顯式標記的節點都是映射節點,因此永遠不會創建您的CommentedScalar
(使用此輸入)。
由於往返模式下的 ruamel.yaml 已經可以加載和轉儲您的 YAML,因此您最好只遍歷加載的數據並檢查標簽屬性。
然而,它是可能加載這些映射節點,但不使用yield
在你的方式(而你只需要yield
為復雜節點(映射,序列)不是簡單的節點)。
import sys
import ruamel.yaml
yaml_str = """\
flow123d_version: 3.1.0
problem: !modulek.Coupling_Sequential
description: Simple dual porosity test - steady flow, simple transport
mesh:
mesh_file: ../00_mesh/square_1x1_40el.msh
flow_equation: !Flow_Darcy_MH
nonlinear_solver:
linear_solver: !Petsc
a_tol: 1.0e-07
"""
yaml = ruamel.yaml.YAML()
@yaml.register_class
class MyMap(ruamel.yaml.comments.CommentedMap):
def __init__(self, tag):
ruamel.yaml.comments.CommentedMap.__init__(self)
self._tag = tag + "@@" # just to make clear things were changed here
@classmethod
def to_yaml(cls, representer, data):
return representer.represent_mapping(data._tag, data)
def construct_any_tag(self, tag_suffix, node):
if tag_suffix is None:
orig_tag = None
else:
orig_tag = "!" + tag_suffix
if isinstance(node, ruamel.yaml.nodes.MappingNode):
data = MyMap(orig_tag)
yield data
state = ruamel.yaml.constructor.SafeConstructor.construct_mapping(self, node, deep=True)
data.update(state)
else:
raise NotImplementedError
yaml = ruamel.yaml.YAML()
yaml.constructor.add_multi_constructor("!", construct_any_tag)
data = yaml.load(yaml_str)
yaml.dump(data, sys.stdout)
這使:
flow123d_version: 3.1.0
problem: !modulek.Coupling_Sequential@@
description: Simple dual porosity test - steady flow, simple transport
mesh:
mesh_file: ../00_mesh/square_1x1_40el.msh
flow_equation: !Flow_Darcy_MH@@
nonlinear_solver:
linear_solver: !Petsc@@
a_tol: 1.0e-07
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.