<p>Imagine we have a folder of <code>.yaml</code> files containing kubernetes objects, let's say, deployments, configmaps and HPAs.</p>
<pre><code>./file1.yaml # {'kind': 'Deployment', ... }, {'kind': 'ConfigMap', ...}
./file2.yaml # {'kind': 'ConfigMap', ... }, {'kind': 'HorizontalPodAutoscaler', ... }
</code></pre>
<p>I need to deserialize them into instances of a proper class, but unlike the regular deserialization method, I want to avoid relying on YAML tags and make a choice by YAML body instead (which is why i have doubts about <code>register_class()</code> approach). There is a key <code>'kind'</code> that should identify the proper class instance.</p>
<p>The end goal is to parse, modify and dump those objects back (<strong>preserving comments and formatting</strong>, so those classes would be a subclass of a CommentedMap or something similar).</p>
<p>Is there a way in ruamel.yaml how could I parse YAML into</p>
<pre><code>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
</code></pre>

user4638
<p>I am not entirely sure what the YAML files actually look like. The part after <code>#</code> in your example
isn't correct YAML, so I made things up.</p>
<p>This doesn't affect processing to get what you want. As long as you have valid, loadable YAML,
just recursive over the data and replace entries.</p>
<p>You need to somehow map the value for <code>kind</code> to your actual classes. If there are not
that many classes just make a string to class dictionary, if you have many, you should
scan your Python files and create that map automatically (either from the class name
or from some class attribute):</p>
<pre class="lang-py prettyprint-override"><code>import sys
import ruamel.yaml
FA = ruamel.yaml.comments.Format.attrib
from pathlib import Path

file1 = Path('file1.yaml')
file1.write_text(&quot;&quot;&quot;\
- {'kind': 'Deployment', a: 1}
- kind: ConfigMap
  b:
    kind: Deployment
    c: 3
    x: 42
&quot;&quot;&quot;)
file2 = Path('file2.yaml')
file2.write_text(&quot;&quot;&quot;\
[
{'kind': 'ConfigMap', d: 4}, 
{'kind': 'HorizontalPodAutoscaler', e: 5},
]
&quot;&quot;&quot;)

    
kob_map = {}
class KubeObjectBase(ruamel.yaml.comments.CommentedMap):
    def some_additional_func(self):
        pass

    def __repr__(self):
        return f&quot;{self.__class__.__name__}({', '.join([f'{k}: {v}' for k, v in self.items()])})&quot;

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)
</code></pre>
<p>which gives:</p>
<pre class="lang-none prettyprint-override"><code>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}]
</code></pre>
