[python] Python 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모든 줄 바꿈과 연속 공백을 제거합니다. 결과는 다음과 같습니다

~ / 다운로드 : 52 $ python2.7 x.py -h
사용법 : x.py [-h] [-g {a, b, g, d, e}]

테스트

선택적 인수 :
  -h, --help이 도움말 메시지를 표시하고 종료
  -g {a, b, g, d, e} a = 알파 b = 베타 g = 감마 d = 델타 e
                  = 엡실�

도움말 텍스트에 줄 바꿈을 삽입하는 방법은 무엇입니까?



답변

사용해보십시오 RawTextHelpFormatter:

from argparse import RawTextHelpFormatter
parser = ArgumentParser(description='test', formatter_class=RawTextHelpFormatter)


답변

하나의 옵션 만 무시하려면을 사용하지 않아야합니다 RawTextHelpFormatter. 대신 하위 클래스를 만들고 HelpFormatter"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 개선의 일부입니다 . 전체 Smar든 옵션에 기본값을 추가하고 유틸리티 설명의 원시 입력을 지원합니다. 정식 버전에는 자체 _split_lines방법이 있으므로 버전 문자열과 같은 형식은 그대로 유지됩니다.

parser.add_argument('--version', '-v', action="version",
                    version="version...\n   42!")


답변

또 다른 쉬운 방법은 을 포함하는

예를 들어

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./p>

parser = ArgumentParser(description="""First paragraph

                                       Second paragraph

                                       Third paragraph""",
                                       usage='%(prog)s [OPTIONS]',
                                       formatter_class=RawTextHelpFormatter)

options = parser.parse_args()

그리고 얻었다 :

사용법 : play-with-argparse.py [옵션]

첫 번째 단락

                        두 번째 단락

                        세 번째 단락

선택적 인수 :
  -h, --help이 도움말 메시지를 표시하고 종료

따라서 RawTextHelpFormatter해결책이 아닙니다. 모든 공백 문자를 유지하면서 소스 코드에 나타나는 설명을 인쇄하기 때문에 (가독성을 위해 소스 바꿈을하지 않습니다. 예를 들어 너무 길면 80 자 이상이어야합니다.

의 올바른 방향에 영감을 준 @Anton에게 감솔루션은 설명 섹션의 형식을 지정하기 위해 약간의 수정이 필요 합니다.

어쨌든, 사용자 정의 포맷터가 필요합니다. 기존 HelpFormatter클래스를 확장하고 다음 과 _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()

출력은 다음과 같습니다

사용법 : play-with-argparse.py [옵션]

첫 번째 단락

두 번째 단락

세 번째 단락

선택적 인수 :
  -h, --help이 도움말 메시지를 표시하고 종료


답변

설명 텍스트에 수동 줄 바꿈과 자동 줄 바꿈을 모두 원했습니다. 그러나 여기에 제안 된 어느 것도 나를 위해 일하지 않았습니다. 그래서 나는ormatter 클래스를 수정했습니다. 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에 대해 다시 전달해야합니다.


답변

머리말

이 질문에 argparse.RawTextHelpFormatter도움이됩니다.

이제을 사용하는 방법을 공유하고 싶습니다 argparse.

질문과 관련이 없을 수도 있음을 알고 있습니다.

그러나 이러한 질문들은 잠시 동안 귀찮게되었습니다.

내 경험을 공유하고 싶습니다. 누군가에게 도움이되기를 바랍니다.

여기 있습니다

타사 모듈

colorama : 텍스트 색상 변경 :pip install colorde>

MS Windows에서 ANSI 이스케이프 문자 시퀀스 (컬러 터미널 텍스트 및 커서 위치 지정)가 작동하도록합니다.

import colorama
from colorama import Fore, Back
from pathlib import Path
from os import startfile, system

SCRIPT_DIR = Path(__file__).resolve().parent
TEMPLATE_DIR = SCRIPT_DIR.joinpath('.')


def main(args):
    ...


if __name__ == '__main__':
    colorama.init(autoreset=True)

    from argparse import ArgumentParser, RawTextHelpFormatter

    format_text = FormatText([(20, '<'), (60, '<')])
    yellow_dc = format_text.new_dc(fore_color=Fore.YELLOW)
    green_dc = format_text.new_dc(fore_color=Fore.GREEN)
    red_dc = format_text.new_dc(fore_color=Fore.RED, back_color=Back.LIGHTYELLOW_EX)

    script_description = \
        '\n'.join([desc for desc in
                   [f'\n{green_dc(f"python {Path(__file__).name} [REFERENCE TEMPLATE] [OUTPUT FILE NAME]")} to create template.',
                    f'{green_dc(f"python {Path(__file__).name} -l *")} to get all available template',
                    f'{green_dc(f"python {Path(__file__).name} -o open")} open template directory so that you can put your template file there.',
                    # <- add your own description
                    ]])
    arg_parser = ArgumentParser(description=yellow_dc('CREATE TEMPLATE TOOL'),
                                # conflict_handler='resolve',
                                usage=script_description, formatter_class=RawTextHelpFormatter)

    arg_parser.add_argument("ref", help="reference template", nargs='?')
    arg_parser.add_argument("outfile", help="output file name", nargs='?')
    arg_parser.add_argument("action_number", help="action number", nargs='?', type=int)
    arg_parser.add_argument('--list', "-l", dest='list',
                            help=f"example: {green_dc('-l *')} \n"
                                 "description: list current available template. (accept regex)")

    arg_parser.add_argument('--option', "-o", dest='option',
                            help='\n'.join([format_text(msg_data_list) for msg_data_list in [
                                ['example', 'description'],
                                [green_dc('-o open'), 'open template directory so that you can put your template file there.'],
                                [green_dc('-o run'), '...'],
                                [green_dc('-o ...'), '...'],
                                # <- add your own description
                            ]]))

    g_args = arg_parser.parse_args()
    task_run_list = [[False, lambda: startfile('.')] if g_args.option == 'open' else None,
                     [False, lambda: [print(template_file_path.stem) for template_file_path in TEMPLATE_DIR.glob(f'{g_args.list}.py')]] if g_args.list else None,
                     # <- add your own function
                     ]
    for leave_flag, func in [task_list for task_list in task_run_list if task_list]:
        func()
        if leave_flag:
            exit(0)

    # CHECK POSITIONAL ARGUMENTS
    for attr_name, value in vars(g_args).items():
        if attr_name.startswith('-') or value is not None:
            continue
        system('cls')
        print(f'error required values of {red_dc(attr_name)} is None')
        print(f"if you need help, please use help command to help you: {red_dc(f'python {__file__} -h')}")
        exit(-1)
    main(g_args)

의 클래스 FormatText는 다음과 같습니다

class FormatText:
    __slots__ = ['align_list']

    def __init__(self, align_list: list, autoreset=True):
        """
        USAGE::

            format_text = FormatText([(20, '<'), (60, '<')])
            red_dc = format_text.new_dc(fore_color=Fore.RED)
            print(red_dc(['column 1', 'column 2']))
            print(red_dc('good morning'))
        :param align_list:
        :param autoreset:
        """
        self.align_list = align_list
        colorama.init(autoreset=autoreset)

    def __call__(self, text_list: list):
        if len(text_list) != len(self.align_list):
            if isinstance(text_list, str):
                return text_list
            raise AttributeError
        return ' '.join(f'{txt:{flag}{int_align}}' for txt, (int_align, flag) in zip(text_list, self.align_list))

    def new_dc(self, fore_color: Fore = Fore.GREEN, back_color: Back = ""):  # DECORATOR
        """create a device context"""
        def wrap(msgs):
            return back_color + fore_color + self(msgs) + Fore.RESET
        return wrap

여기에 이미지 설명을 입력하십시오