Відображати довідкове повідомлення з аргументом python, коли скрипт викликається без аргументів


226

Це може бути простим. Припустимо, у мене є програма, яка використовує argparse для обробки аргументів / параметрів командного рядка. Далі буде надруковано повідомлення "довідки":

./myprogram -h

або:

./myprogram --help

Але якщо я запускаю скрипт без будь-яких аргументів, він нічого не робить. Я хочу це зробити - це відображення повідомлення про використання, коли воно викликане без аргументів. Як це робиться?

Відповіді:


273

Ця відповідь приходить від Стівена Бетхарда в групах Google . Я репостую тут, щоб полегшити доступ людям без облікового запису Google.

Ви можете змінити поведінку errorметоду за замовчуванням :

import argparse
import sys

class MyParser(argparse.ArgumentParser):
    def error(self, message):
        sys.stderr.write('error: %s\n' % message)
        self.print_help()
        sys.exit(2)

parser = MyParser()
parser.add_argument('foo', nargs='+')
args = parser.parse_args()

Зауважте, що вищевказане рішення надрукує довідкове повідомлення щоразу, коли error метод запускається. Наприклад, також test.py --blahбуде надруковано довідкове повідомлення, якщо --blahце недійсна опція.

Якщо ви хочете роздрукувати довідкове повідомлення лише в тому випадку, якщо в командному рядку не вказано жодних аргументів, можливо, це все-таки найпростіший спосіб:

import argparse
import sys

parser=argparse.ArgumentParser()
parser.add_argument('foo', nargs='+')
if len(sys.argv)==1:
    parser.print_help(sys.stderr)
    sys.exit(1)
args=parser.parse_args()

Зверніть увагу, що parser.print_help()за замовчуванням друкується для stdout. Як пропонує init_js , використовуйте parser.print_help(sys.stderr)для друку на stderr.


Так ... саме про це мені було цікаво, чи існував спосіб аргументації впоратися з цим сценарієм. Дякую!
musashiXXX

6
У другому рішенні, яке я використовую parser.print_usage()замість, parser.print_help()- довідкове повідомлення включає використання, але воно є більш багатослівним.
user2314737

5
Я би проголосував за другу частину відповіді, але error()це переконання здається мені жахливою ідеєю. Він виконує інше призначення, він не розроблений для друку дружнього використання чи допомоги.
Петерино

@ Петерино - переосмислення відбувається в дитячому класі, тому це не повинно бути проблемою. Це явно.
Марсель Вілсон

1
@unutbu ЧУДОВО! Саме те, що мені було потрібно. Одне питання, чи можна це застосувати і до підкоманд? Зазвичай я просто отримую `` Простір імен (output = None) ''. Як я можу легко викликати помилку на ВСІХ підкомандах? Я хотів би викликати помилку там.
Джонатан Комар

56

Замість того, щоб писати клас, замість нього можна використовувати спробу / за винятком

try:
    options = parser.parse_args()
except:
    parser.print_help()
    sys.exit(0)

Перевага полягає в тому, що робочий процес чіткіший і вам не потрібен клас заглушки. Мінусом є те, що перший рядок "використання" друкується двічі.

Для цього знадобиться хоча б один обов’язковий аргумент. Без обов'язкових аргументів, надання нульових аргументів у командному рядку є дійсним.


я теж віддаю перевагу цьому прийнятій відповіді. Додавання класу завищено для довідки щодо друку, коли аргументи несподівані. Нехай чудовий аргументарний модуль обробляє випадки помилок для вас.
Ніколь Фінні

7
Цей друк коду допомагає 2 рази, якщо -hвикористовується прапор, а непотрібні відбитки допомагають, якщо --versionвикористовується прапор. Щоб пом'якшити ці проблеми, ви можете перевірити тип помилки:except SystemExit as err: if err.code == 2: parser.print_help()
pkowalczyk

25

З аргументом ви можете зробити:

parser.argparse.ArgumentParser()
#parser.add_args here

#sys.argv includes a list of elements starting with the program
if len(sys.argv) < 2:
    parser.print_usage()
    sys.exit(1)

5
Це має відбутися перед закликом доparser.parse_args()
Боб Штейн

18

Якщо у вас є аргументи, які необхідно вказати для запуску сценарію - використовуйте необхідний параметр для ArgumentParser, як показано нижче: -

parser.add_argument('--foo', required=True)

parse_args () повідомить про помилку, якщо сценарій запускається без аргументів.


2
Це найпростіше рішення, яке також буде працювати з вказаними недійсними параметрами.
Стів Шерер

1
Домовились. Я думаю, що завжди краще використовувати вбудовані здібності аналізатора аргументів, а потім написати якийсь додатковий обробник.
Крістофер Хантер

18

Якщо ви пов'язуєте функції за замовчуванням для (під) парсерів, як це було зазначено нижче add_subparsers, ви можете просто додати їх як дію за замовчуванням:

parser = argparse.ArgumentParser()
parser.set_defaults(func=lambda x: parser.print_usage())
args = parser.parse_args()
args.func(args)

Додайте спробу, за винятком випадків, коли ви збільшуєте винятки через відсутні аргументи позиції.


1
Ця відповідь настільки занижена. Простий і дуже добре працює з підпарасерами.
інструбхен

Чудова відповідь! Єдина зміна, яку я вніс, - це використання лямбда без параметра.
boh717

12

Найчистішим рішенням буде вручну передавати аргумент за замовчуванням, якщо жоден не був вказаний у командному рядку:

parser.parse_args(args=None if sys.argv[1:] else ['--help'])

Повний приклад:

import argparse, sys

parser = argparse.ArgumentParser()
parser.add_argument('--host', default='localhost', help='Host to connect to')
# parse arguments
args = parser.parse_args(args=None if sys.argv[1:] else ['--help'])

# use your args
print("connecting to {}".format(args.host))

Це дозволить надрукувати повну довідку (не коротке використання), якщо викликати без аргументів.


2
sys.argv[1:]- дуже поширена ідіома. Я бачу parser.parse_args(None if sys.argv[1:] else ['-h'])більш ідіоматичним і чистішим.
Нуно Андре

1
@ NunoAndré спасибі - оновив відповідь. Насправді відчувається більш пітонічно.
Євген Попович

10

Скинувши сюди мою версію:

import argparse

parser = argparse.ArgumentParser()
args = parser.parse_args()
if not vars(args):
    parser.print_help()
    parser.exit(1)

Ви можете помітити parser.exit- я в основному це роблю так, оскільки це зберігає рядок імпорту, якщо це була єдина причина sysу файлі ...


parser.exit (1) приємно! Гарне доповнення.
cgseller

4
На жаль, parser.parse_args () вийде, якщо позиційний аргумент відсутній. Отже, це працює лише при використанні необов'язкових аргументів.
Марсель Вілсон

1
@MarcelWilson, це справді - хороший улов! Я подумаю, як це змінити.
pauricthelodger

not vars(args)може не працювати, коли аргументи мають defaultметод.
funid

5

Існує пара одноланцюжків sys.argv[1:](дуже поширена ідіома Python для посилання на аргументи командного рядка, що sys.argv[0]є ім'ям сценарію), яка може виконати цю роботу.

Перший - це роз'яснення, чисте та пітонічне:

args = parser.parse_args(None if sys.argv[1:] else ['-h'])

Другий - трохи хакітніший. Поєднання раніше оцінений факт , що порожній список Falseз True == 1і False == 0еквівалентності ви отримаєте це:

args = parser.parse_args([None, ['-h']][not sys.argv[1:]])

Можливо, занадто багато дужок, але досить зрозуміло, якщо було зроблено попередній вибір аргументів.

_, *av = sys.argv
args = parser.parse_args([None, ['-h']][not av])

1
parser.print_help()
parser.exit()

parser.exitМетод також може прийняти status( код повернення), а messageзначення (включити кінцеву рядок самостійно!).

переконливий приклад, :)

#!/usr/bin/env python3

""" Example argparser based python file
"""

import argparse

ARGP = argparse.ArgumentParser(
    description=__doc__,
    formatter_class=argparse.RawTextHelpFormatter,
)
ARGP.add_argument('--example', action='store_true', help='Example Argument')


def main(argp=None):
    if argp is None:
        argp = ARGP.parse_args()  # pragma: no cover

    if 'soemthing_went_wrong' and not argp.example:
        ARGP.print_help()
        ARGP.exit(status=128, message="\nI just don't know what went wrong, maybe missing --example condition?\n")


if __name__ == '__main__':
    main()  # pragma: no cover

Приклад дзвінків:

$ python3 ~ / helloworld.py; ехо $?
використання: helloworld.py [-h] [--приклад]

 Приклад файлу python на основі argparser

необов'язкові аргументи:
  -h, --допоможіть показати це довідкове повідомлення та вийти
  --приклад аргументу прикладу

Я просто не знаю, що пішло не так, можливо, відсутні - приклад умови?
128
$ python3 ~ / helloworld.py - приклад; ехо $?
0

0

Встановіть свої позиційні аргументи з наргами та перевірте, чи позиційні аргументи порожні.

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('file', nargs='?')
args = parser.parse_args()
if not args.file:
    parser.print_help()

Довідкові нарцини Python


0

Ось ще один спосіб зробити це, якщо вам потрібно щось гнучке, де ви хочете відобразити допомогу, якщо передані конкретні параметри, взагалі жодні або більше ніж 1 суперечливий аргумент:

import argparse
import sys

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-d', '--days', required=False,  help="Check mapped inventory that is x days old", default=None)
    parser.add_argument('-e', '--event', required=False, action="store", dest="event_id",
                        help="Check mapped inventory for a specific event", default=None)
    parser.add_argument('-b', '--broker', required=False, action="store", dest="broker_id",
                        help="Check mapped inventory for a broker", default=None)
    parser.add_argument('-k', '--keyword', required=False, action="store", dest="event_keyword",
                        help="Check mapped inventory for a specific event keyword", default=None)
    parser.add_argument('-p', '--product', required=False, action="store", dest="product_id",
                        help="Check mapped inventory for a specific product", default=None)
    parser.add_argument('-m', '--metadata', required=False, action="store", dest="metadata",
                        help="Check mapped inventory for specific metadata, good for debugging past tix", default=None)
    parser.add_argument('-u', '--update', required=False, action="store_true", dest="make_updates",
                        help="Update the event for a product if there is a difference, default No", default=False)
    args = parser.parse_args()

    days = args.days
    event_id = args.event_id
    broker_id = args.broker_id
    event_keyword = args.event_keyword
    product_id = args.product_id
    metadata = args.metadata
    make_updates = args.make_updates

    no_change_counter = 0
    change_counter = 0

    req_arg = bool(days) + bool(event_id) + bool(broker_id) + bool(product_id) + bool(event_keyword) + bool(metadata)
    if not req_arg:
        print("Need to specify days, broker id, event id, event keyword or past tickets full metadata")
        parser.print_help()
        sys.exit()
    elif req_arg != 1:
        print("More than one option specified. Need to specify only one required option")
        parser.print_help()
        sys.exit()

    # Processing logic here ...

Ура!


Я думаю, вам буде набагато простіше використовувати підрозділи або взаємно-ексклюзивні_групи
Тім Брей

0

Якщо ваша команда - це те, де користувачеві потрібно вибрати якусь дію, тоді використовуйте взаємовиключну групу з обов'язковим = True .

Це свого роду розширення до відповіді, яку дає pd321.

import argparse

parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("--batch", action='store', type=int,  metavar='pay_id')
group.add_argument("--list", action='store_true')
group.add_argument("--all", action='store_true', help='check all payments')

args=parser.parse_args()

if args.batch:
    print('batch {}'.format(args.batch))

if args.list:
    print('list')

if args.all:
    print('all')

Вихід:

$ python3 a_test.py
використання: a_test.py [-h] (--batch pay_id | --list | --all)
a_test.py: помилка: один з аргументів --batch --list - всі необхідні

Це дає лише основну допомогу. А деякі інші відповіді нададуть вам повну допомогу. Але принаймні ваші користувачі знають, що вміють робити -h


0

Це не добре (також, тому що перехоплює всі помилки), але:

def _error(parser):
    def wrapper(interceptor):
        parser.print_help()

        sys.exit(-1)

    return wrapper

def _args_get(args=sys.argv[1:]):
    parser = argparser.ArgumentParser()

    parser.error = _error(parser)

    parser.add_argument(...)
    ...

Ось визначення errorфункції ArgumentParserкласу:

https://github.com/python/cpython/blob/276eb67c29d05a93fbc22eea5470282e73700d20/Lib/argparse.py#L2374

. Як бачите, після підпису він бере два аргументи. Однак, функції поза класом нічого не знають про перший аргумент:, selfтому що, грубо кажучи, це параметр для класу. (Я знаю, що ви знаєте ...) Таким чином, просто проходять самостійно selfі messageв _error(...)не можу (

def _error(self, message):
    self.print_help()

    sys.exit(-1)

def _args_get(args=sys.argv[1:]):
    parser = argparser.ArgumentParser()

    parser.error = _error
    ...
...

виведе:

...
"AttributeError: 'str' object has no attribute 'print_help'"

). Ви можете передати parser( self) _errorфункцію, зателефонувавши їй:

def _error(self, message):
    self.print_help()

    sys.exit(-1)

def _args_get(args=sys.argv[1:]):
    parser = argparser.ArgumentParser()

    parser.error = _error(parser)
    ...
...

, але ви не хочете вийти з програми прямо зараз. Потім поверніть його:

def _error(parser):
    def wrapper():
        parser.print_help()

        sys.exit(-1)

    return wrapper
...

. Тим parserне менш, не знає, що вона була змінена, тому, коли виникає помилка, вона надішле причину її (до речі, її локалізований переклад). Ну, тоді перехопите це:

def _error(parser):
    def wrapper(interceptor):
        parser.print_help()

        sys.exit(-1)

    return wrapper
...

. Тепер, коли станеться помилка і parserвикличе її причину, ви її перехопите, подивіться на це і ... викиньте.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.