Argparse не чете ли unicode от командния ред?

Изпълнение на 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

Това означава ли, че не мога да използвам никакви уникод знаци с модула argparse на python?


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: Имам малък опит с не-unicode конзоли, но тук хората казват, че 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