chronos
chronos

Reputation: 355

Cannot write custom dictionaries to YAML

I have working python code that makes use of three nested classes:

@dataclass
class PanelGroup:
    num_panels: int
    panel_efficiency: float
    panel_surface: float
    elevation: int


class PanelString(dict[str, PanelGroup]):
    pass


class SolarInstallation(dict[str, PanelString]):
    pass

The way I create instances of these classes, statically, from my code is:

solar_installation = SolarInstallation(
        SSW_12=PanelString(G1=PanelGroup(4, 0.191, 1.705, 50),
                           G2=PanelGroup(5, 0.191, 1.705, 50)))

I want to make this configuration come from a YAML file, so I trying to get to work the following snippet of code to dump the correct YAML contents to a file:

yaml = ruamel.yaml.YAML()
yaml.register_class(SolarInstallation)
yaml.register_class(PanelString)
yaml.register_class(PanelGroup)
yaml.dump(solar_installation, sys.stdout)

But the only thing I get is an empty dictionary:

!SolarInstallation {}

What am I doing wrong?

Upvotes: 1

Views: 207

Answers (1)

Anthon
Anthon

Reputation: 76632

You'll need to tell ruamel.yaml how to dump your classes, just registering is not enough:

import sys
from dataclasses import dataclass
import ruamel.yaml


@dataclass
class PanelGroup:
    num_panels: int
    panel_efficiency: float
    panel_surface: float
    elevation: int

    @classmethod
    def to_yaml(cls, representer, node):
        d = {}
        for k in node.__annotations__:
            d[k] = node.__getattribute__(k)
        return representer.represent_mapping('!' + cls.__name__, d)

class PanelString(dict[str, PanelGroup]):
    @classmethod
    def to_yaml(cls, representer, node):
        return representer.represent_mapping('!' + cls.__name__, node)


class SolarInstallation(dict[str, PanelString]):
    @classmethod
    def to_yaml(cls, representer, node):
        return representer.represent_mapping('!' + cls.__name__, node)

solar_installation = SolarInstallation(
        SSW_12=PanelString(G1=PanelGroup(4, 0.191, 1.705, 50),
                           G2=PanelGroup(5, 0.191, 1.705, 50)))
yaml = ruamel.yaml.YAML()
yaml.register_class(SolarInstallation)
yaml.register_class(PanelString)
yaml.register_class(PanelGroup)
yaml.dump(solar_installation, sys.stdout)

which gives:

!SolarInstallation
SSW_12: !PanelString
  G1: !PanelGroup
    num_panels: 4
    panel_efficiency: 0.191
    panel_surface: 1.705
    elevation: 50
  G2: !PanelGroup
    num_panels: 5
    panel_efficiency: 0.191
    panel_surface: 1.705
    elevation: 50

Upvotes: 1

Related Questions