Контроль положения сгиба при использовании репрезентации в PyYAML - PullRequest
1 голос
/ 30 октября 2019

Я могу вывести код YAML с длинными строками в сложенном виде с помощью этого кода:

import yaml

class folded_str(str): pass

def folded_str_representer(dumper, data):
    return dumper.represent_scalar(u'tag:yaml.org,2002:str', data, style='>')

yaml.add_representer(folded_str, folded_str_representer)

data = {
    'foo': folded_str(('abcdefghi ' * 10) + 'end\n'),
}

print(yaml.dump(data))

Вывод для приведенного выше кода:

foo: >
  abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi
  abcdefghi abcdefghi end

Возможно ликонтролировать длину, после которой должны возникать складки? Например, если я хочу, чтобы строки сгибались после 70 символов, то результат будет выглядеть следующим образом:

foo: >
  abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi
  abcdefghi abcdefghi abcdefghi end

Есть ли способ заставить PyYAML сделать это?

1 Ответ

1 голос
/ 31 октября 2019

Простой способ контролировать, как долго строки, которые PyYAML выводит со свертыванием, состоит в том, чтобы обеспечить (глобальную) длину строки параметром width:

import sys
import yaml

class folded_str(str): pass

def folded_str_representer(dumper, data):
    return dumper.represent_scalar(u'tag:yaml.org,2002:str', data, style='>')

yaml.add_representer(folded_str, folded_str_representer)

data = {
    'foo': folded_str(('abcdefghi ' * 10) + 'end\n'),
}

yaml.dump(data, sys.stdout, width=70)

, который дает:

foo: >
  abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi
  abcdefghi abcdefghi abcdefghi end

Как видите, я удалил ваш звонок на print. PyYAML имеет интерфейс потоковой передачи, и, поскольку поток не направляется напрямую на выход, он должен интерпретировать вывод в памяти, что является излишне медленным и неэффективным использованием памяти.

Конечно, это также влияет на любые другие строки, которые выводятся (длинные не свернутые скаляры, списки в стиле потока, глубоко вложенные структуры данных.

Непростой способ - не вызыватьподпрограмму represent_scalar и адаптировать ScalarNode PyYAML (или создать свой собственный тип Node), который затем выводит новую строку в соответствующей позиции при излучении.


My ruamel.yaml имеетэта функциональность встроена, чтобы разрешить такой вывод в обоих направлениях с сохранением положения сгиба (даже при том, что ширина вывода по умолчанию такая же, как у PyYAML)

import sys
import ruamel.yaml

yaml_str = """\
[long, scalar]: "This is just a filler to show that the default width is 80 chars"
foo: >
  abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi
  abcdefghi abcdefghi abcdefghi end
"""

yaml = ruamel.yaml.YAML()
data = yaml.load(yaml_str)
yaml.dump(data, sys.stdout)

, что дает:

[long, scalar]: This is just a filler to show that the default width is 80 chars
foo: >
  abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi
  abcdefghi abcdefghi abcdefghi end

Хотя вы можете создать такую ​​сложенную строку с нуля, она не является тривиальной (отсутствует API, и внутреннее представление может измениться). Я рекомендую просто создать сложенные данные строки и затем загрузить их, определив folded_str по-разному:

import sys
import ruamel.yaml

yaml = ruamel.yaml.YAML()

def folded_str(s, pos=70):
    parts = []
    r = ""
    for part in s.split(' '):
        if not r:
            r = part
        elif len(r) + len(part) >= pos:
            parts.append(r + '\n')
            r = part
        else:
            r += ' ' + part
    parts.append(r)
    return yaml.load(">\n" + "".join(parts))

data = {
    'foo': folded_str(('abcdefghi ' * 10) + 'end\n'),
}

yaml.dump(data, sys.stdout)

, что дает:

foo: >
  abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi
  abcdefghi abcdefghi abcdefghi end
...