Можно ли сделать подстановку строк в YAML?



Есть ли способ заменить строку в YAML. Например, я хотел бы определить sub один раз и использовать его во всем файле YAML.



sub: ['a', 'b', 'c']
command:
params:
cmd1:
type: string
enum : # Get the list defined in 'sub'
description: Exclude commands from the test list.
cmd2:
type: string
enum: # Get the list defined in 'sub'
531   1  

1 ответ:

Вы не можете действительно заменить строковые значения в YAML, как при замене подстроки некоторой строки на другую подстроку1. Однако у YAML есть возможность пометить узел (в вашем случае список ['a', 'b', 'c'] с помощью якорь и повторно использовать это как узел псевдонима.

Якоря

Принимают вид &some_id и вставляются перед узлом, а узлы псевдонимов задаются *some_id (вместо узла).

Это не то же самое, что замена на строковом уровне, потому что при разборе файла YAML ссылка может быть сохранена. Как и в случае загрузки YAML в Python для любых якорей на типах коллекций (т. е. Не при использовании якорей на скалярах):

import sys
import ruamel.yaml as yaml

yaml_str = """\
sub: &sub0 [a, b, c]
command:
    params:
        cmd1:
            type: string
            # Get the list defined in 'sub'
            enum : *sub0
            description: Exclude commands from the test list.
        cmd2:
            type: string
            # Get the list defined in 'sub'
            enum: *sub0
"""

data1 = yaml.load(yaml_str, Loader=yaml.RoundTripLoader)

# the loaded elements point to the same list
assert data1['sub'] is data1['command']['params']['cmd1']['enum']

# change in cmd2
data1['command']['params']['cmd2']['enum'][3] = 'X'


yaml.dump(data1, sys.stdout, Dumper=yaml.RoundTripDumper, indent=4)

Это выведет:

sub: &sub0 [a, X, c]
command:
    params:
        cmd1:
            type: string
            # Get the list defined in 'sub'
            enum: *sub0
            description: Exclude commands from the test list.
        cmd2:
            type: string
            # Get the list defined in 'sub'
            enum: *sub0
Обратите внимание, что оригинальное имя якоря сохранено в ruamel.ямл .

Если вам не нужны якоря и псевдонимы в выходных данных, вы можете переопределить метод ignore_aliases в подклассе RoundTripRepresenter RoundTripDumper (этот метод принимает два аргумента, но при использовании lambda *args: .... Вам не обязательно об этом знать):

dumper = yaml.RoundTripDumper
dumper.ignore_aliases = lambda *args : True
yaml.dump(data1, sys.stdout, Dumper=dumper, indent=4)

Что дает:

sub: [a, X, c]
command:
    params:
        cmd1:
            type: string
            # Get the list defined in 'sub'
            enum: [a, X, c]
            description: Exclude commands from the test list.
        cmd2:
            type: string
            # Get the list defined in 'sub'
            enum: [a, X, c]

И этот трюк можно использовать для чтения в файле YAML, как если бы вы сделали подстановку строк, перечитав материал, который вы сбросили, игнорируя псевдонимы:

data2 = yaml.load(yaml.dump(yaml.load(yaml_str, Loader=yaml.RoundTripLoader),
                    Dumper=dumper, indent=4), Loader=yaml.RoundTripLoader)

# these are lists with the same value
assert data2['sub'] == data2['command']['params']['cmd1']['enum']
# but the loaded elements do not point to the same list
assert data2['sub'] is not data2['command']['params']['cmd1']['enum']

data2['command']['params']['cmd2']['enum'][5] = 'X'

yaml.dump(data2, sys.stdout, Dumper=yaml.RoundTripDumper, indent=4)

И теперь только один 'b' заменен на 'X':

sub: [a, b, c]
command:
    params:
        cmd1:
            type: string
            # Get the list defined in 'sub'
            enum: [a, b, c]
            description: Exclude commands from the test list.
        cmd2:
            type: string
            # Get the list defined in 'sub'
            enum: [a, X, c]

Как указано выше, это необходимо только при использовании якорей / псевдонимов для типов коллекций, а не когда вы используйте его на скаляре.


1 поскольку ЯМЛ может создавать объекты, однако возможно влиять на них. синтаксический анализатор, если эти объекты создаются. этот ответ описывает, как это сделать.
2 сохранение имен изначально не было доступно, но было реализовано в обновлении ruamel.ямл

Comments

    Ничего не найдено.