Не argparse читает юникод из командной строки?

Запуск Python 2.7

При выполнении:

$ python client.py get_emails -a "åäö"

Я получил:

usage: client.py get_emails [-h] [-a AREA] [-t {rfc2822,plain}]
client.py get_emails: error: argument -a/--area: invalid unicode value: '\xc3\xa5\xc3\xa4\xc3\xb6'

Это мой парсер:

def _argparse():
    desc = """
           Simple CLI-client for...
           """
    argparser = argparse.ArgumentParser(description=desc)
    subparsers = argparser.add_subparsers(dest='command')

    # create the parser for the "get_emails" command
    parser_get_emails = subparsers.add_parser('get_emails', help=u'Get email list')
    parser_get_emails.add_argument('-a', '--area', type=unicode, help='Limit to area')
    parser_get_emails.add_argument('-t', '--out_type', choices=['rfc2822', 'plain'],
                                   default='rfc2822', help='Type of output')

    args = argparser.parse_args()
    return args

Означает ли это, что я не могу использовать символы Юникода с модулем Python argparse?


person Niclas Nilsson    schedule 08.04.2014    source источник
comment
Какая кодировка у вашего терминала?   -  person BrenBarn    schedule 09.04.2014
comment
Ваш терминал использует кодировку UTF-8, но Python по умолчанию использует ASCII, поэтому unicode использует неправильную кодировку для преобразования байтов в объект unicode.   -  person chepner    schedule 09.04.2014


Ответы (2)


Можешь попробовать

type=lambda s: unicode(s, 'utf8')

вместо

type=unicode

Без аргумента кодировки unicode() по умолчанию использует ascii.

person georg    schedule 08.04.2014
comment
Отлично, я проверю это завтра, когда снова буду перед компьютером. Думал об использовании lambda s: unicode(s, locale.getdefaultlocale()[1]), я полагаю, это было бы более гибко. Есть предостережения? - person Niclas Nilsson; 09.04.2014
comment
@NiclasNilsson: getdefaultlocale может возвращать None, None при определенных обстоятельствах, поэтому вам понадобится запасной вариант, например getdefaultlocale()[1] or 'utf8' - person georg; 09.04.2014
comment
кодировка может быть другой. Используйте здесь sys.getfilesystemencoding() вместо жестко заданного utf8. - person jfs; 15.04.2014
comment
Это более безопасно, чем locale.getdefaultlocale()[1]? - person Niclas Nilsson; 15.04.2014
comment
@NiclasNilsson: у меня мало опыта работы с консолями без юникода, но здесь люди говорят, что getfilesystemencoding не является кодировкой argv. Хотя может быть sys.stdin.encoding. - person georg; 16.04.2014
comment
@georg: я не вижу sys.getfilesystemencoding() в предоставленной вами ссылке. Как вы думаете, почему sys.argv элементов нет в sys.getfilesystemencoding()? Есть проблемы с недекодируемыми аргументами, но это другая проблема. - person jfs; 05.07.2014

Аргументы командной строки кодируются с использованием sys.getfilesystemencoding():

import sys

def commandline_arg(bytestring):
    unicode_string = bytestring.decode(sys.getfilesystemencoding())
    return unicode_string

# ...
parser_get_emails.add_argument('-a', '--area', type=commandline_arg)

Примечание. В Python 3 это не требуется (аргументы уже имеют кодировку Unicode). В этом случае используется os.fsdecode(), потому что иногда аргументы командной строки могут быть недекодируемыми. См. PEP 383 -- Недекодируемые байты в интерфейсах системных символов.

person jfs    schedule 15.04.2014
comment
фактический ответ может быть более сложным, если вам нужно поддерживать имена файлов, не поддающиеся декодированию в текущей локальной кодировке (Unicode API в Windows, неправильно настроенная локаль в Linux). Подробнее см. в разделе Как работать с путями c русскими символами? (спросите, нужен ли вам перевод) - person jfs; 03.06.2016
comment
Это работает для меня. В моем случае значением аргумента является строка китайских иероглифов. Принятый ответ жалуется invalid <lambda> value:. - person ElpieKay; 16.03.2021