【问题标题】:How to dump Scalar node如何转储标量节点
【发布时间】:2022-06-15 18:37:44
【问题描述】:

我想在文件 configuration.yaml 中获得以下输出:

platform: manual
name: "AB"
code: !secret AB
arming_time: 15
delay_time: 15
trigger_time: 2
disarmed:
  trigger_time: 0
armed_home:
  arming_time: 0
  delay_time: 0

我需要这个输出。但是,当我对带有 YAML 文件中节点的字典使用 dump() 时,我会收到以下输出(检查“代码”的值):

  armed_home:
    arming_time: 0
    delay_time: 0
  arming_time: 15
  code: !!python/object:yaml.nodes.ScalarNode
    end_mark: !!python/object:yaml.error.Mark
      buffer: null
      column: 24
      index: 101
      line: 5
      name: ch/standart/alarm_control_panel.yaml
      pointer: null
    start_mark: !!python/object:yaml.error.Mark
      buffer: null
      column: 10
      index: 87
      line: 5
      name: ch/standart/alarm_control_panel.yaml
      pointer: null
    style: null
    tag: '!secret'
    value: home_alarm
  delay_time: 15
  disarmed:
    trigger_time: 0
  name: Home Alarm
  platform: manual
  trigger_time: 2

我的代码在这里供您参考。 “秘密”是一个文件夹。也许,我需要创建一个新的 Class()。这将只转储()节点的标签和值。这样,输出将与所需的相同。

import yaml
from typing import Any, IO
import json
import sys
import os
from pathlib import Path
import ast

class Loader(yaml.SafeLoader):
    """YAML Loader with `!include` constructor."""

    def __init__(self, stream: IO) -> None:
        """Initialise Loader."""

        try:
            self._root = os.path.split(stream.name)[0]
        except AttributeError:
            if AttributeError == IsADirectoryError:
                print('lol')
            else:
                self._root = os.path.curdir

        super().__init__(stream)


def construct_include(loader: Loader, node: yaml.Node) -> Any:
    """Include file referenced at node."""
    try:
        filename = os.path.abspath(os.path.join(loader._root, loader.construct_scalar(node)))
        extension = os.path.splitext(filename)[1].lstrip('.')
        return node
    except IsADirectoryError:
        print('lol')

yaml.add_constructor('!secret', construct_include, Loader)

p = os.path.abspath('configuration.yaml')

with open(p, 'r') as f:
    data = yaml.load(f, Loader=Loader)
d = {}
for i in data:
    d[i] = data[i]
file = open("configuration.yaml", "w")
yaml.dump(d, file)

【问题讨论】:

标签: python yaml dump


【解决方案1】:

你可以使用内置的TaggedScalarDoubleQuotedScalarString, 得到你想要的输出:

import sys
import ruamel.yaml

TS = ruamel.yaml.comments.TaggedScalar
DS = ruamel.yaml.scalarstring.DoubleQuotedScalarString
            
d = dict(
  platform = 'manual',
  name =     DS('AB'),
  code = TS('AB', tag='!secret'),
  arming_time = 15,
  delay_time = 15,
  trigger_time = 2,
  disarmed = dict(trigger_time = 0),
  armed_home = dict(arming_time = 0, delay_time = 0),
)

yaml = ruamel.yaml.YAML()
# yaml.indent(mapping=2, sequence=4, offset=2) 
yaml.dump(d, sys.stdout)

给出:

platform: manual
name: "AB"
code: !secret AB
arming_time: 15
delay_time: 15
trigger_time: 2
disarmed:
  trigger_time: 0
armed_home:
  arming_time: 0
  delay_time: 0

你的两个位置的缩进是默认的,所以你不需要调用.indent()

您可以使用yaml.dump(d, Path('configuration.yaml')) 流式传输到文件

【讨论】:

  • 你能不能让它 import yaml 而不是 import ruamel.yaml
  • TLDR:我不会。理论上这是可能的,因为ruamel.yaml 是多年前从 PyYAML 派生的。但它有很多错误修复、支持 YAML 1.2 的更改和其他改进,到了这个时候,你需要相互依赖,基本上需要覆盖 PyYAML 的每个文件。所以这没有任何意义,而且无论如何也不符合 SO 的限制。这些包是共存的,因此请使用ruamel.yaml,如果您不想更改其他代码,请使用 PyYAML。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-29
  • 2012-06-12
  • 2012-05-10
  • 2020-07-17
  • 1970-01-01
相关资源
最近更新 更多