Ruamel.Yaml:在不使用标记的情况下将Yaml反序列化为python类实例



假设我们有一个.yaml文件文件夹,其中包含kubernetes对象,例如部署,配置映射和hpa。

./file1.yaml # {'kind': 'Deployment', ... }, {'kind': 'ConfigMap', ...}
./file2.yaml # {'kind': 'ConfigMap', ... }, {'kind': 'HorizontalPodAutoscaler', ... }

我需要将它们反序列化为适当类的实例,但与常规的反序列化方法不同,我想避免依赖YAML标记,而是由YAML主体做出选择(这就是为什么我对register_class()方法有疑问)。有一个键'kind',应该识别适当的类实例。

最终目标是解析、修改和转储这些对象(保留注释和格式化)。(所以这些类将是commenttedmap的子类或类似的东西)。

在ruamel中有方法吗?如何将yaml解析为

from ruamel.yaml.comments import CommentedMap
class KubeObjectBase(CommentedMap):
def some_additional_func(self):
pass
class Deployment(KubeObjectBase):
def deployment_method(self):
pass
class ConfigMap(KubeObjectBase):
pass

我不完全确定YAML文件实际上是什么样子的。在你的例子中#之后的部分是不正确的YAML,所以我编了一些东西。

这并不影响你得到你想要的东西的处理。只要你有有效的、可加载的YAML,只是对数据递归并替换条目。

您需要以某种方式将kind的值映射到您的实际类。如果没有很多类只是创建一个字符串到类的字典,如果你有很多,你应该扫描Python文件并自动创建该映射(从类名开始)或者从某个类属性):

import sys
import ruamel.yaml
FA = ruamel.yaml.comments.Format.attrib
from pathlib import Path
file1 = Path('file1.yaml')
file1.write_text("""
- {'kind': 'Deployment', a: 1}
- kind: ConfigMap
b:
kind: Deployment
c: 3
x: 42
""")
file2 = Path('file2.yaml')
file2.write_text("""
[
{'kind': 'ConfigMap', d: 4}, 
{'kind': 'HorizontalPodAutoscaler', e: 5},
]
""")

kob_map = {}
class KubeObjectBase(ruamel.yaml.comments.CommentedMap):
def some_additional_func(self):
pass
def __repr__(self):
return f"{self.__class__.__name__}({', '.join([f'{k}: {v}' for k, v in self.items()])})"
class Deployment(KubeObjectBase):
def deployment_method(self):
pass
kob_map['Deployment'] = Deployment

class ConfigMap(KubeObjectBase):
pass
kob_map['ConfigMap'] = ConfigMap

class HorizontalPodAutoscaler(KubeObjectBase):
pass
kob_map['HorizontalPodAutoscaler'] = HorizontalPodAutoscaler
yaml = ruamel.yaml.YAML()
for v in kob_map.values():
yaml.Representer.add_representer(v, yaml.Representer.represent_dict)

def un_kind(d, map):
if isinstance(d, dict):
for k, v in d.items():
un_kind(v, map)
try:
if 'kind' in v:
# typ = map[v.pop('kind')]
typ = nv = map[v['kind']]
d[k] = typ(v)
setattr(nv, FA, v.fa)
setattr(nv, '_comment_attrib', v.ca)
except TypeError:
pass
elif isinstance(d, list):
for idx, elem in enumerate(d):
un_kind(elem, map)
try:
if 'kind' in elem:
# typ = map[elem.pop('kind')]
typ = map[elem['kind']]
d[idx] = nv = typ(elem)
setattr(nv, FA, elem.fa)
setattr(nv, '_comment_attrib', elem.ca)
except TypeError:
pass

for fn in Path('.').glob('*.yaml'):
data = yaml.load(fn)
print(f'{fn}:')
un_kind(data, kob_map)
print(list(data))
yaml.dump(data, sys.stdout)

给了:

file1.yaml:
[Deployment(kind: Deployment, a: 1), ConfigMap(kind: ConfigMap, b: Deployment(kind: Deployment, c: 3, x: 42))]
- {kind: Deployment, a: 1}
- kind: ConfigMap
b:
kind: Deployment
c: 3
x: 42
file2.yaml:
[ConfigMap(kind: ConfigMap, d: 4), HorizontalPodAutoscaler(kind: HorizontalPodAutoscaler, e: 5)]
[{kind: ConfigMap, d: 4}, {kind: HorizontalPodAutoscaler, e: 5}]

相关内容

  • 没有找到相关文章

最新更新