Skip to content

Adding Class Representer to YAML Results in Nonsense Error #540

Closed
@JacobLChrzanowski

Description

@JacobLChrzanowski

Hello,

I am trying to load and store a config from a yaml, and I want to have a custom class able to be dumped and loaded from yaml.
I have this working outside of HASS/PyScript, but it totally bites the dust in PyScript.

Versions

Home Assistant Core: 2023.8.4
Home Assistant OS: 10.5
PyScript version: 1.5.0
HASS PyYAML library: 6.0.1
Debian PyYAML library: 6.0.1, and also worked on 5.3.1

(venv) jacobc@webprime:~/python_venv$ pip list | grep -i yaml
PyYAML        6.0.1
jacobc@webprime:~/python_venv$ deactivate
jacobc@webprime:~/python_venv$ pip list | grep -i yaml
PyYAML              5.3.1

Here we go, the MVP:

import yaml
from enum import Enum, Flag, auto
Action = Flag('Action', ['Press', 'Hold', 'TerminateHold', 'Indeterminate', 'Up', 'Down', 'Left', 'Right', 'Center'])

def Action_representer(dumper, data: Action):
    """
    Custom representer for an enum.Flag subclass 'Action' to enable customized YAML dumping.
    The function works by:
      converting the binary representation of the Action value into a set of power-of-two components,
      joining their corresponding Action names with '|',
      and then representing the result as a scalar in the YAML format.
    For instance:
        Action.Hold -> "!Action 'Hold'"
        Action.Hold | Action.Center -> "!Action 'Hold|Center'"
    Args:
      dumper: YAML dumper instance.
      data (Action): The Action object to be represented in the YAML format.
    Returns:
      Represents the Action object as a scalar in the custom YAML format.
    """
    binary_str = bin(data.value)[2:][::-1]
    binary_pieces = [2**(i+0) for i, bit in enumerate(binary_str) if bit == '1']
    repr_str = '|'.join([Action(x).name for x in binary_pieces])
    return dumper.represent_scalar(u'!Action', repr_str)
yaml.add_representer(Action, Action_representer)

print(yaml.dump(Action.Hold))

Debian Host:

This outputs as expected in an ipython shell,

In [4]: print(yaml.dump(Action.Hold))
!Action 'Hold'

Inside of PyScript:

Before running yaml.add_representer(Action, Action_representer)

log.info(yaml.dump({'hello': Action.Hold}))
->
2023-10-23 22:16:21.202 INFO (MainThread) [custom_components.pyscript.file.example.async_foo] hello: !!python/object/apply:builtins.getattr
- !!python/name:custom_components.pyscript.eval.Action ''
- Hold

After running yaml.add_representer(Action, Action_representer)

log.info(yaml.dump({'hello': Action.Hold}))
->
2023-10-23 22:16:41.349 ERROR (MainThread) [custom_components.pyscript.file.example.async_foo] Exception in <file.example.async_foo> line 196:
        log.info(yaml.dump({'hello': Action.Hold}))
                            ^
EmitterError: expected NodeEvent, but got MappingEndEvent()

No clue where to even start here, there isn't much on Google that is very helpful. Anyone have thoughts? Ideas?

All the best,
Jacob C.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions