【问题标题】:Change <TEST> in a yaml file python在 yaml 文件 python 中更改 <TEST>
【发布时间】:2016-09-14 22:56:46
【问题描述】:

我必须在 yaml 文件中替换这些标签。
以前被替换的数据存储在一个列表中。
我有这个 YAML 文件

vagrantfile:    
    target: local
    vm:
        provider:
            local:
                box: puphpet/ubuntu1404-x<BITS> # MEERKEUZE: 32 OF 64, STANDAARD 64
                box_url: puphpet/ubuntu1404-x<BITS> # MEERKEUZE: 32 OF 64, STANDAARD 64
                box_version: '0'
                chosen_virtualizer: <virtualiser>  # MEERKEUZE: virtualbox OF vmware, STANDAARD 64
                virtualizers:
                    virtualbox:
                        modifyvm:
                            natdnshostresolver1: false
                        showgui: 0
                    vmware:
                        numvcpus: 1
                    parallels:
                        use_linked_clone: 0
                        check_guest_tools: 0
                        update_guest_tools: 0
                machines:
                    vflm_7orc03npv15g:
                        id: <ID> # STRING
                        hostname: <HOSTNAME> # STRING
                        network:
                            private_network: <IP-ADDRESS> #lOKAAL IP, STANDARAARD 192.168.50.101
                            forwarded_port:
                                hon1d:
                                    host: '80'
                                    guest: '80'
                        memory: '<MEGABYTES>' # AANTAL, STANDAARD VEELVOUD VAN 1024
                        cpus: '<CORES>' # AANTAL CPUS, STANDAARD AANTAL CORES - 1, NIET HOGER DAN AANTAL CORES

我可以做些什么来更改所有这些标签?

【问题讨论】:

标签: python tags yaml


【解决方案1】:

您应该在 YAML 级别执行此操作,以确保如果您的替换强制结果字符串被引用,这确实发生了。例如。如果您的 &lt;ID&gt; 需要替换为 @abc 之类的内容,则 YAML 文件中的实际行需要变为

id: '@abc'

而不是

id: '@abc' 

@ 是保留的。有几个这样的警告,所以在字符串级别替换不是一个好主意。

你可以这样做:

import sys
import ruamel.yaml

yaml_str = """\
vagrantfile:
    target: local
    vm:
        provider:
            local:
                box: puphpet/ubuntu1404-x<BITS> # MEERKEUZE: 32 OF 64, STANDAARD 64
                box_url: puphpet/ubuntu1404-x<BITS> # MEERKEUZE: 32 OF 64, STANDAARD 64
                box_version: '0'
                chosen_virtualizer: <virtualiser>  # MEERKEUZE: virtualbox OF vmware, STANDAARD 64
                virtualizers:
                    virtualbox:
                        modifyvm:
                            natdnshostresolver1: false
                        showgui: 0
                    vmware:
                        numvcpus: 1
                    parallels:
                        use_linked_clone: 0
                        check_guest_tools: 0
                        update_guest_tools: 0
                machines:
                    vflm_7orc03npv15g:
                        id: <ID> # STRING
                        hostname: <HOSTNAME> # STRING
                        network:
                            private_network: <IP-ADDRESS> #lOKAAL IP, STANDARAARD 192.168.50.101
                            forwarded_port:
                                hon1d:
                                    host: '80'
                                    guest: '80'
                        memory: '<MEGABYTES>' # AANTAL, STANDAARD VEELVOUD VAN 1024
                        cpus: '<CORES>' # AANTAL CPUS, STANDAARD AANTAL CORES - 1, NIET HOGER DAN AANTAL CORES
"""


def replace(data, values):
    def do_one(data, values):
        if isinstance(data, dict):
            for k in data:
                data[k] = do_one(data[k], values)
            return data
        elif isinstance(data, list):
            for idx, elem in enumerate(data):
                data[idx] = do_one(elem, values)
            return data
        elif isinstance(data, str):
            for k in values:  # full match
                if data == k:
                    return values[k]
            if '<' in data and '>' in data:
                for k in values:
                    data = data.replace(k, str(values[k]))
                return data


    expanded = { ('<' + k + '>'): v for (k, v) in values.iteritems()}
    do_one(data, expanded)

data = ruamel.yaml.round_trip_load(yaml_str)

replace(data, {
    'BITS': 64,
    'virtualiser': 'virtualbox',
    'HOSTNAME': 'localhost',
    'IP-ADDRESS': '192.168.0.1',
    'ID': '@abc',
    'MEGABYTES': 2048,
    'CORES': 8,
    })

ruamel.yaml.round_trip_dump(data, stream=sys.stdout, indent=4)

这会给你:

vagrantfile:
    target:
    vm:
        provider:
            local:
                box: puphpet/ubuntu1404-x64     # MEERKEUZE: 32 OF 64, STANDAARD 64
                box_url: puphpet/ubuntu1404-x64     # MEERKEUZE: 32 OF 64, STANDAARD 64
                box_version:
                chosen_virtualizer: virtualbox     # MEERKEUZE: virtualbox OF vmware, STANDAARD 64
                virtualizers:
                    virtualbox:
                        modifyvm:
                            natdnshostresolver1:
                        showgui:
                    vmware:
                        numvcpus:
                    parallels:
                        use_linked_clone:
                        check_guest_tools:
                        update_guest_tools:
                machines:
                    vflm_7orc03npv15g:
                        id: '@abc' # STRING
                        hostname: localhost  # STRING
                        network:
                            private_network: 192.168.0.1  #lOKAAL IP, STANDARAARD 192.168.50.101
                            forwarded_port:
                                hon1d:
                                    host:
                                    guest:
                        memory: 2048          # AANTAL, STANDAARD VEELVOUD VAN 1024
                        cpus: 8         # AANTAL CPUS, STANDAARD AANTAL CORES - 1, NIET HOGER DAN AANTAL CORES

请注意:

  • cmets 被保留
  • cpusmemory 的值是整数,而不是字符串
  • id 的值在必要时被正确引用。

以上使用ruamel.yaml:免责声明我是那个包的作者。你可以用 PyYAML 做同样的事情,但是你会失去 cmets,你需要将自己限制在 YAML 1.1 标准(从 2005 年开始)而不是 YAML 1.2 标准(从 2009 年开始)

【讨论】:

    【解决方案2】:

    可能最容易使用 pyyaml。例如。设置cpus 值:

    import yaml
    foo = yaml.load(open('file.yml', 'r'))
    foo['vagrantfile']['vm']['provider']['local']['machines']['vflm_7orc03npv15g']['memory'] = 'bar'
    yaml.dump(foo, open('out.yml', 'w'))
    

    唯一的问题是这样你会丢失 cmets。

    【讨论】:

    • 不应该有迭代文件和替换标签的选项吗?
    • 因为我用的是python 2.7
    • 啊,我想我没有意识到标签总是一样的。在这种情况下,我会使用带有字符串模板的吉普赛解决方案(我个人会使用花括号和.format)。
    【解决方案3】:

    您可以将yaml转换为字符串模板,并使用字符串格式化来实现这一点

    template = """vagrantfile:    
        target: local
        vm:
            provider:
                local:
                    box: puphpet/ubuntu1404-x%(BITS)s # MEERKEUZE: 32 OF 64, STANDAARD 64
                    box_url: puphpet/ubuntu1404-x%(BITS)s # MEERKEUZE: 32 OF 64, STANDAARD 64
                    box_version: '0'
                    chosen_virtualizer: %(virtualiser)s  # MEERKEUZE: virtualbox OF vmware, STANDAARD 64
                    virtualizers:
                        virtualbox:
                            modifyvm:
                                natdnshostresolver1: false
                            showgui: 0
                        vmware:
                            numvcpus: 1
                        parallels:
                            use_linked_clone: 0
                            check_guest_tools: 0
                            update_guest_tools: 0
                    machines:
                        vflm_7orc03npv15g:
                            id: %(ID)s # STRING
                            hostname: %(OSTNAME)s # STRING
                            network:
                                private_network: %(IP-ADDRESS)s #lOKAAL IP, STANDARAARD 192.168.50.101
                                forwarded_port:
                                    hon1d:
                                        host: '80'
                                        guest: '80'
                            memory: '%(MEGABYTES)s' # AANTAL, STANDAARD VEELVOUD VAN 1024
                            cpus: '%(CORES)s' # AANTAL CPUS, STANDAARD AANTAL CORES - 1, NIET HOGER DAN AANTAL CORES"""
    
    
    replaced = template % {"BITS": "some value", "virtualiser": "something", "ID": 2412, "OSTNAME": "OS name", "IP-ADDRESS": "some ip", "MEGABYTES": 100, "CORES": 16}
    

    【讨论】:

    • 根据您替换的值,这可能会导致 YAML 解析器无法解析的输出。
    猜你喜欢
    • 2023-04-07
    • 1970-01-01
    • 2020-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-01
    • 2018-02-16
    • 2011-12-13
    相关资源
    最近更新 更多