Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/300.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用ruamel.yaml(python)加载和转储多个yaml文件_Python_Yaml_Ruamel.yaml - Fatal编程技术网

使用ruamel.yaml(python)加载和转储多个yaml文件

使用ruamel.yaml(python)加载和转储多个yaml文件,python,yaml,ruamel.yaml,Python,Yaml,Ruamel.yaml,使用python 2(atm)和ruamel.yaml 0.13.14(RedHat EPEL) 我目前正在编写一些代码来加载yaml定义,但它们被分成多个文件。用户可编辑部分包含以下内容: users: xxxx1: timestamp: '2018-10-22 11:38:28.541810' << : *userdefaults xxxx2: << : *userdefaults timestamp: '2018-10-22

使用python 2(atm)和ruamel.yaml 0.13.14(RedHat EPEL)

我目前正在编写一些代码来加载yaml定义,但它们被分成多个文件。用户可编辑部分包含以下内容:

users:
  xxxx1:
    timestamp: '2018-10-22 11:38:28.541810'
    << : *userdefaults
  xxxx2:
    << : *userdefaults
    timestamp: '2018-10-22 11:38:28.541810'
我可以通过同时加载和压缩字符串,然后通过正确解析所有内容的
merged_data=list(yaml.load_all({}\n{}).format(defaults_data,user_data,Loader=yaml.RoundTripLoader))运行它们,从而一起处理这些内容。(当不使用RoundTripLoader时,我会出现无法解析引用的错误,这是正常的)


现在,我想通过python代码进行一些更新(例如更新时间戳),为此,我只需要写回用户部分。这就是事情变得棘手的地方。我还没有找到一种方法来编写yaml文档,不是两个都写。

要编写用户部分,您必须手动拆分
yaml.dump()
多文件输出的输出,并将适当的部分写回用户yaml文件

import datetime
import StringIO

import ruamel.yaml

yaml = ruamel.yaml.YAML(typ='rt')
data = None

with open('defaults.yaml', 'r') as defaults:
    with open('users.yaml', 'r') as users:
        raw = "{}\n{}".format(''.join(defaults.readlines()), ''.join(users.readlines()))
        data = list(yaml.load_all(raw))

data[0]['users']['xxxx1']['timestamp'] = datetime.datetime.now().isoformat()

with open('users.yaml', 'w') as outfile:
    sio = StringIO.StringIO()
    yaml.dump(data[0], sio)
    out = sio.getvalue()
    outfile.write(out.split('\n\n')[1]) # write the second part here as this is the contents of users.yaml

首先,除非默认文件中有多个文档,否则 不必使用
load\u all
,因为您不需要将两个文档连接到一个文档中 多文档流。如果您使用带有文档结尾的格式字符串 标记(
“{}\n...\n{}”
)或带有指令结束标记(
“{}\n--\n{}”
) 根据 YAML规格:

alias节点使用不存在的锚点是错误的 以前出现在文档中

锚点必须在文档中,而不仅仅是在流中(流可以由多个锚点组成) 文件)


我尝试了一些骗术,预先填充了已经呈现的字典 锚定节点的数量:

import sys
import datetime
from ruamel import yaml

def load():
    with open('defaults.yaml') as fp:
        defaults_data = fp.read()
    with open('user.yaml') as fp:
        user_data = fp.read()
    merged_data = yaml.load("{}\n{}".format(defaults_data, user_data), 
                            Loader=yaml.RoundTripLoader)
    return merged_data

class MyRTDGen(object):
    class MyRTD(yaml.RoundTripDumper):
        def __init__(self, *args, **kw):
            pps = kw.pop('pre_populate', None)
            yaml.RoundTripDumper.__init__(self, *args, **kw)
            if pps is not None:
                for pp in pps:
                    try:
                        anchor = pp.yaml_anchor()
                    except AttributeError:
                        anchor = None
                    node = yaml.nodes.MappingNode(
                        u'tag:yaml.org,2002:map', [], flow_style=None, anchor=anchor)
                    self.represented_objects[id(pp)] = node

    def __init__(self, pre_populate=None):
        assert isinstance(pre_populate, list)
        self._pre_populate = pre_populate 

    def __call__(self, *args, **kw):
        kw1 = kw.copy()
        kw1['pre_populate'] = self._pre_populate
        myrtd = self.MyRTD(*args, **kw1)
        return myrtd


def update(md, file_name):
    ud = md.pop('userdefaults')
    MyRTD = MyRTDGen([ud])
    yaml.dump(md, sys.stdout, Dumper=MyRTD)
    with open(file_name, 'w') as fp:
        yaml.dump(md, fp, Dumper=MyRTD)

md = load()
md['users']['xxxx2']['timestamp'] = str(datetime.datetime.utcnow())
update(md, 'user.yaml')
由于基于PyYAML的API需要类而不是对象,因此需要 使用一个类生成器,它实际上添加了要预填充的数据元素 来自withing
yaml.load()
的飞行

但这不起作用,因为一个节点只有在被锚定后才会被写出 确定使用了锚(即存在第二个参考)。所以实际上 第一个合并键作为锚点写入。虽然我很熟悉 有了代码库,我无法在合理的时间内使其正常工作

因此,我只能依靠一个事实,即只有一个键匹配 组合文件转储根级别的
users.yaml
的第一个键 在那之前把所有东西都锉掉

import sys
import datetime
from ruamel import yaml

with open('defaults.yaml') as fp:
    defaults_data = fp.read()
with open('user.yaml') as fp:
    user_data = fp.read()
merged_data = yaml.load("{}\n{}".format(defaults_data, user_data), 
                        Loader=yaml.RoundTripLoader)

# find the key
for line in user_data.splitlines():
    line = line.split('# ')[0].rstrip()  # end of line comment, not checking for strings
    if line and line[-1] == ':' and line[0] != ' ':
        split_key = line
        break

merged_data['users']['xxxx2']['timestamp'] = str(datetime.datetime.utcnow())

buf = yaml.compat.StringIO()
yaml.dump(merged_data, buf, Dumper=yaml.RoundTripDumper)
document = split_key + buf.getvalue().split('\n' + split_key)[1]
sys.stdout.write(document)
其中:

users:
  xxxx1:
    <<: *userdefaults
    timestamp: '2018-10-22 11:38:28.541810'
  xxxx2:
    <<: *userdefaults
    timestamp: '2018-10-23 09:59:13.829978'
用户:
三十一:

虽然该方法还可以,但在0.13.14中不起作用,因为OP指示正在使用该方法。也不需要使用
load_all
,转换为列表,然后只使用第一个元素,除非
默认值中有多个文档。yaml
文件(然后更新
数据[0]
将不起作用)。
users:
  xxxx1:
    <<: *userdefaults
    timestamp: '2018-10-22 11:38:28.541810'
  xxxx2:
    <<: *userdefaults
    timestamp: '2018-10-23 09:59:13.829978'