2010-10-04 35 views
222

Tôi đang sử dụng argparse in Python 2.7 để phân tích cú pháp các tùy chọn nhập liệu. Một trong những lựa chọn của tôi là một lựa chọn đa dạng. Tôi muốn tạo một danh sách trong văn bản trợ giúp của nó, ví dụ:Python argparse: Làm thế nào để chèn dòng mới trong văn bản trợ giúp?

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() 

Tuy nhiên, argparse loại bỏ tất cả các dòng mới và khoảng trắng liên tiếp. Kết quả trông giống như

 
~/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 

Làm cách nào để chèn dòng mới vào văn bản trợ giúp?

+0

Tôi không có python 2.7 với tôi để tôi có thể kiểm tra ý tưởng của mình. Cách sử dụng văn bản trợ giúp trong dấu ngoặc kép ("" "" ""). Do các dòng mới tồn tại bằng cách sử dụng này? – pyfunc

+3

@pyfunc: Không. Tước được thực hiện trong thời gian chạy bởi 'argparse', không phải là trình thông dịch, vì vậy việc chuyển sang' "" "..." "" 'sẽ không giúp ích gì. – kennytm

Trả lời

255

Hãy thử sử dụng RawTextHelpFormatter:

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

Rất tốt, cảm ơn. Có thể áp dụng nó cho 1 tùy chọn không? – kennytm

+4

Tôi nghĩ là không. Bạn có thể phân loại nó, nhưng không may là 'Chỉ tên của lớp này mới được coi là API công khai. Vì vậy, có lẽ không phải là một ý tưởng tuyệt vời, mặc dù nó có thể không quan trọng, vì 2.7 có nghĩa là là con trăn 2.x cuối cùng và bạn sẽ được dự kiến ​​sẽ tái cấu trúc rất nhiều thứ cho 3.x anyway. Tôi thực sự chạy 2,6 với 'argparse' được cài đặt thông qua' easy_install' để tài liệu có thể bị lỗi thời. – intuited

+3

Một số liên kết: cho [python 2.7] (http://docs.python.org/library/argparse.html#formatter-class) và [python 3. *] (http://docs.python.org/dev /library/argparse.html#formatter-class). Gói 2.6, theo [wiki của nó] (http://code.google.com/p/argparse/), tuân theo 2.7 chính thức. Từ doc: "Truyền RawDescriptionHelpFormatter dưới dạng formatter_class = cho biết mô tả và epilog đã được định dạng đúng và không được xếp hàng" – Stefano

53

Nếu bạn chỉ muốn ghi đè lên một lựa chọn, bạn không nên sử dụng RawTextHelpFormatter. Thay vì phân lớp các HelpFormatter và cung cấp một giới thiệu đặc biệt dành cho các tùy chọn mà phải được xử lý "thô" (Tôi sử dụng "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) 

Và sử dụng nó:

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() 

Bất kỳ cuộc gọi khác đến .add_argument() nơi giúp đỡ không bắt đầu với R| sẽ được bao bọc như bình thường.

Đây là một phần của my improvements on argparse. SmartFormatter đầy đủ cũng hỗ trợ thêm các giá trị mặc định cho tất cả các tùy chọn và đầu vào thô của mô tả tiện ích. Phiên bản đầy đủ có phương thức _split_lines riêng để mọi định dạng được thực hiện, ví dụ: chuỗi phiên bản được giữ nguyên:

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

Tôi muốn làm điều này cho một tin nhắn phiên bản, nhưng SmartFormatter này chỉ có vẻ làm việc với văn bản trợ giúp, không phải là văn bản phiên bản đặc biệt. 'parser.add_argument ('- v', '--version', action = 'version', version = get_version_str())' Có thể mở rộng nó cho trường hợp đó không? –

+0

@mc_electron phiên bản đầy đủ của SmartFormatter cũng có '_split_lines' của riêng nó và duy trì ngắt dòng (không cần chỉ định" R | "ở đầu, nếu bạn muốn tùy chọn đó, hãy vá phương thức' _VersionAction .__ call__' – Anthon

+0

I ' m không hoàn toàn grokking phần đầu tiên của bình luận của bạn, mặc dù tôi có thể nhìn thấy trong '_VersionAction .__ call__' mà tôi có lẽ sẽ muốn nó chỉ' parser.exit (message = version) 'thay vì sử dụng phiên bản được định dạng. để làm điều đó mà không phát hành một bản vá của argparse mặc dù? –

7

Tôi đã gặp sự cố tương tự (Python 2.7.6). Tôi đã cố gắng để phá vỡ mô tả phần thành nhiều dòng sử dụng RawTextHelpFormatter:

parser = ArgumentParser(description="""First paragraph 

             Second paragraph 

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

options = parser.parse_args() 

Và có:

 
usage: play-with-argparse.py [OPTIONS] 

First paragraph 

         Second paragraph 

         Third paragraph 

optional arguments: 
    -h, --help show this help message and exit 

Vì vậy RawTextHelpFormatter không phải là một giải pháp. Bởi vì nó in mô tả khi nó xuất hiện trong mã nguồn, bảo toàn tất cả các ký tự khoảng trắng (tôi muốn giữ các tab phụ trong mã nguồn của tôi để dễ đọc nhưng tôi không muốn in tất cả. Ngoài ra định dạng thô không bọc dòng khi nó được quá dài, hơn 80 ký tự chẳng hạn).

Nhờ @Anton đã truyền cảm hứng đúng hướng above. Nhưng giải pháp đó cần sửa đổi nhỏ để định dạng mô tả phần.

Dù sao, định dạng tùy chỉnh là cần thiết. Tôi mở rộng HelpFormatter lớp hiện có và gạt _fill_text phương pháp như thế này:

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 

Hãy so sánh với mã nguồn gốc đến từ argparse mô-đun:

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) 

Trong đoạn mã gốc toàn bộ mô tả đang được bao bọc.Trong trình định dạng tùy chỉnh phía trên toàn bộ văn bản được chia thành nhiều phần và mỗi phần được định dạng độc lập.

Vì vậy, với trợ giúp của định dạng tùy chỉnh:

parser = ArgumentParser(description= """First paragraph 
             |n        
             Second paragraph 
             |n 
             Third paragraph""", 
       usage='%(prog)s [OPTIONS]', 
       formatter_class=MultilineFormatter) 

options = parser.parse_args() 

đầu ra là:

 
usage: play-with-argparse.py [OPTIONS] 

First paragraph 

Second paragraph 

Third paragraph 

optional arguments: 
    -h, --help show this help message and exit 
+1

Điều này thật tuyệt vời --- đã xảy ra với điều này sau khi gần như từ bỏ và suy ngẫm chỉ cần thực hiện lại lập luận giúp đỡ ... cứu tôi một số rắc rối. –

+2

phân lớp 'HelpFormatter' là vấn đề vì các nhà phát triển argparse chỉ đảm bảo rằng tên lớp sẽ tồn tại trong các phiên bản tương lai của argparse. Về cơ bản, họ đã tự viết một tờ séc trắng để họ có thể thay đổi tên phương thức nếu nó thuận tiện cho họ làm như vậy. Tôi thấy bực bội này; ít nhất họ có thể đã làm được tiếp xúc với một vài phương pháp trong API. – MrMas

20

Một cách dễ dàng để làm điều đó là bao gồm textwrap.

Ví dụ,

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 ... ''')) 

Bằng cách này, chúng ta có thể tránh được những khoảng trống dài ở phía trước mỗi dòng đầu ra.

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 ... 
-1

Tôi muốn có cả ngắt dòng thủ công trong văn bản mô tả và tự động bao gồm; nhưng không có gợi ý nào ở đây làm việc cho tôi - vì vậy tôi đã kết thúc việc sửa đổi lớp SmartFormatter được đưa ra trong các câu trả lời ở đây; các vấn đề với các tên phương pháp argparse không phải là một API công cộng mặc dù, đây là những gì tôi có (như là một tập tin gọi là 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() 

Đây là cách nó hoạt động trong 2,7 và 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 
Các vấn đề liên quan