Загрузка специальных символов с помощью PyYaml

Я работаю над загрузкой списка символов emoji в простой python 3.6 script. Структура YAML состоит по существу следующим образом:

- 🙂   
- 😁
- 😬

Мой python script выглядит следующим образом:

import yaml
f = open('emojis.yml')
EMOJIS = yaml.load(f)
f.close()

Я получаю следующее исключение:

yaml.reader.ReaderError: unacceptable character #x001d: special characters are not allowed in "emojis.yml", position 2

Я видел параметр allow_unicode=True, но, похоже, доступен только для yaml.dump. Похоже, что у людей были проблемы с подобными проблемами в Python2, но поскольку все строки должны быть unicode, мне трудно понять, почему это не работает.

Я также попробовал обернуть свою emojis в кавычки и использовать конструктор клиента для "tag: yaml.org, 2002: str". Мой пользовательский конструктор никогда даже не попадает, по-видимому, из-за того, что yaml lib не распознает мой emoji как имеющий тип строки. Я также наблюдаю такое же поведение, когда я определяю свой emoji непосредственно как строку в источнике.

Есть ли способ загрузить файл yaml, содержащий emojis с PyYAML?

Ответ 1

Вам следует перейти на ruamel.yaml (отказ от ответственности: я являюсь автором этого пакета), в котором исправлены эта и многие другие давние проблемы PyYAML:

import sys
from ruamel.yaml import YAML

yaml = YAML()

with open('emojis.yml') as fp:
    idx = 0
    for c in fp.read():
        print('{:08x}'.format(ord(c)), end=' ')
        idx += 1
        if idx % 4 == 0:
            print()

with open('emojis.yml') as fp:
    data = yaml.load(fp)
yaml.dump(data, sys.stdout)

дает:

0000002d 00000020 0001f642 0000000a 
0000002d 00000020 0001f601 0000000a 
0000002d 00000020 0001f62c 0000000a 
['🙂', '😁', '😬']

Если вам действительно нужно придерживаться PyYAML, вы можете сделать следующее:

import yaml.reader
import re

yaml.reader.Reader.NON_PRINTABLE = re.compile(
    u'[^\x09\x0A\x0D\x20-\x7E\x85\xA0-\uD7FF\uE000-\uFFFD\U00010000-\U0010FFFF]')

чтобы избавиться от ошибки.


Начиная с версии 0.15.16, ruamel.yaml теперь также сбрасывает все дополнительные Unicode плоскости, не возвращаясь к \Uxxxxxxxx (управляемый в новом API через .unicode_supplementary и в зависимости от allow_unicode).

Ответ 2

Обновление

последняя версия pyyaml исправила эту ошибку, обновите до pyyaml>=5


Оригинальный ответ

Кажется, это ошибка в pyyaml, обходной путь - использовать их escape-последовательности:

$ cat test.yaml
- "\U0001f642"
- "\U0001f601"
- "\U0001f62c"

$ python
...
>>> yaml.load(open('test.yaml'))
['🙂', '😁', '😬']