Ответ 1
Попробуйте использовать RawTextHelpFormatter
:
from argparse import RawTextHelpFormatter
parser = ArgumentParser(description='test', formatter_class=RawTextHelpFormatter)
Я использую argparse
в Python 2.7 для анализа параметров ввода. Один из моих вариантов - это множественный выбор. Я хочу сделать список в его тексте справки, например.
from argparse import ArgumentParser
parser = ArgumentParser(description='test')
parser.add_argument('-g', choices=['a', 'b', 'g', 'd', 'e'], default='a',
help="Some option, where\n"
" a = alpha\n"
" b = beta\n"
" g = gamma\n"
" d = delta\n"
" e = epsilon")
parser.parse_args()
Однако argparse
разделяет все строки новой строки и последовательные пробелы. Результат выглядит как
~/Downloads:52$ python2.7 x.py -h usage: x.py [-h] [-g {a,b,g,d,e}] test optional arguments: -h, --help show this help message and exit -g {a,b,g,d,e} Some option, where a = alpha b = beta g = gamma d = delta e = epsilon
Как вставить строки в текст справки?
Попробуйте использовать RawTextHelpFormatter
:
from argparse import RawTextHelpFormatter
parser = ArgumentParser(description='test', formatter_class=RawTextHelpFormatter)
Если вы просто хотите переопределить один параметр, вы не должны использовать RawTextHelpFormatter
. Вместо этого подкласс HelpFormatter
и предоставить специальное введение для параметров, которые должны обрабатываться "raw" (я использую "R|rest of help"
):
import argparse
class SmartFormatter(argparse.HelpFormatter):
def _split_lines(self, text, width):
if text.startswith('R|'):
return text[2:].splitlines()
# this is the RawTextHelpFormatter._split_lines
return argparse.HelpFormatter._split_lines(self, text, width)
И используйте его:
from argparse import ArgumentParser
parser = ArgumentParser(description='test', formatter_class=SmartFormatter)
parser.add_argument('-g', choices=['a', 'b', 'g', 'd', 'e'], default='a',
help="R|Some option, where\n"
" a = alpha\n"
" b = beta\n"
" g = gamma\n"
" d = delta\n"
" e = epsilon")
parser.parse_args()
Любые другие вызовы .add_argument()
, где справка не начинается с R|
, будут завернуты как обычно.
Это часть моих улучшений в argparse. Полный SmartFormatter также поддерживает добавление
значения по умолчанию для всех параметров и исходный ввод описания утилиты. Полная версия
имеет свой собственный метод _split_lines
, так что любое форматирование, выполненное, например, строки версии сохраняются:
parser.add_argument('--version', '-v', action="version",
version="version...\n 42!")
Другой простой способ сделать это - включить textwrap.
Например,
import argparse, textwrap
parser = argparse.ArgumentParser(description='some information',
usage='use "python %(prog)s --help" for more information',
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('--argument', default=somedefault, type=sometype,
help= textwrap.dedent('''\
First line
Second line
More lines ... '''))
Таким образом, мы можем избежать длинного пустого пространства перед каждой выходной строкой.
usage: use "python your_python_program.py --help" for more information
Prepare input file
optional arguments:
-h, --help show this help message and exit
--argument ARGUMENT
First line
Second line
More lines ...
Я столкнулся с подобной проблемой (Python 2.7.6). Я попытался разбить раздел описания на несколько строк, используя RawTextHelpFormatter
:
parser = ArgumentParser(description="""First paragraph
Second paragraph
Third paragraph""",
usage='%(prog)s [OPTIONS]',
formatter_class=RawTextHelpFormatter)
options = parser.parse_args()
И получил:
usage: play-with-argparse.py [OPTIONS] First paragraph Second paragraph Third paragraph optional arguments: -h, --help show this help message and exit
Так что RawTextHelpFormatter
не является решением. Поскольку он печатает описание так, как оно выглядит в исходном коде, сохраняя все пробельные символы (я хочу сохранить дополнительные вкладки в моем исходном коде для удобства чтения, но я не хочу печатать их все. Кроме того, raw formatter не переносит строки, когда это слишком длинный, более 80 символов например).
Спасибо @Anton, который вдохновил правильное направление выше. Но это решение нуждается в небольшой модификации, чтобы отформатировать раздел описания.
В любом случае, нужен специальный форматер. Я расширил существующий класс HelpFormatter
и _fill_text
метод _fill_text
следующим образом:
import textwrap as _textwrap
class MultilineFormatter(argparse.HelpFormatter):
def _fill_text(self, text, width, indent):
text = self._whitespace_matcher.sub(' ', text).strip()
paragraphs = text.split('|n ')
multiline_text = ''
for paragraph in paragraphs:
formatted_paragraph = _textwrap.fill(paragraph, width, initial_indent=indent, subsequent_indent=indent) + '\n\n'
multiline_text = multiline_text + formatted_paragraph
return multiline_text
Сравните с исходным исходным кодом из модуля argparse:
def _fill_text(self, text, width, indent):
text = self._whitespace_matcher.sub(' ', text).strip()
return _textwrap.fill(text, width, initial_indent=indent,
subsequent_indent=indent)
В оригинальном коде все описание упаковано. В пользовательском редакторе выше весь текст разбит на несколько кусков, и каждый из них форматируется независимо.
Итак, с помощью пользовательского форматера:
parser = ArgumentParser(description= """First paragraph
|n
Second paragraph
|n
Third paragraph""",
usage='%(prog)s [OPTIONS]',
formatter_class=MultilineFormatter)
options = parser.parse_args()
выход:
usage: play-with-argparse.py [OPTIONS] First paragraph Second paragraph Third paragraph optional arguments: -h, --help show this help message and exit
Я хотел иметь как ручные разрывы строк в тексте описания, так и автоматическую его упаковку; но ни одно из предложений здесь не работало для меня - поэтому я закончил модификацию класса SmartFormatter, приведенного в ответах здесь; проблемы с именами методов argparse не являются общедоступными API, вот что я имею (как файл с именем test.py
):
import argparse
from argparse import RawDescriptionHelpFormatter
# call with: python test.py -h
class SmartDescriptionFormatter(argparse.RawDescriptionHelpFormatter):
#def _split_lines(self, text, width): # RawTextHelpFormatter, although function name might change depending on Python
def _fill_text(self, text, width, indent): # RawDescriptionHelpFormatter, although function name might change depending on Python
#print("splot",text)
if text.startswith('R|'):
paragraphs = text[2:].splitlines()
rebroken = [argparse._textwrap.wrap(tpar, width) for tpar in paragraphs]
#print(rebroken)
rebrokenstr = []
for tlinearr in rebroken:
if (len(tlinearr) == 0):
rebrokenstr.append("")
else:
for tlinepiece in tlinearr:
rebrokenstr.append(tlinepiece)
#print(rebrokenstr)
return '\n'.join(rebrokenstr) #(argparse._textwrap.wrap(text[2:], width))
# this is the RawTextHelpFormatter._split_lines
#return argparse.HelpFormatter._split_lines(self, text, width)
return argparse.RawDescriptionHelpFormatter._fill_text(self, text, width, indent)
parser = argparse.ArgumentParser(formatter_class=SmartDescriptionFormatter, description="""R|Blahbla bla blah blahh/blahbla (bla blah-blabla) a blahblah bl a blaha-blah .blah blah
Blah blah bla blahblah, bla blahblah blah blah bl blblah bl blahb; blah bl blah bl bl a blah, bla blahb bl:
blah blahblah blah bl blah blahblah""")
options = parser.parse_args()
Вот как это работает в версиях 2.7 и 3.4:
$ python test.py -h
usage: test.py [-h]
Blahbla bla blah blahh/blahbla (bla blah-blabla) a blahblah bl a blaha-blah
.blah blah
Blah blah bla blahblah, bla blahblah blah blah bl blblah bl blahb; blah bl
blah bl bl a blah, bla blahb bl:
blah blahblah blah bl blah blahblah
optional arguments:
-h, --help show this help message and exit
Начиная с описанного выше SmartFomatter, я остановился на этом решении:
class SmartFormatter(argparse.HelpFormatter):
'''
Custom Help Formatter used to split help text when '\n' was
inserted in it.
'''
def _split_lines(self, text, width):
r = []
for t in text.splitlines(): r.extend(argparse.HelpFormatter._split_lines(self, t, width))
return r
Обратите внимание, что странным образом аргумент formatter_class, передаваемый парсеру верхнего уровня, не наследуется sub_parsers, его необходимо передавать снова для каждого созданного sub_parser.