argparse Python
| Введение | |
| Пример | |
| version | |
| Необязательный аргумент | |
| Значения по умолчанию | |
| Похожие статьи |
Введение
Это статья про библиотеку
argparse
для работы с агрументами, которые передаются в скрипт извне. Например, из терминала.
Передача аргументов в скрипт это распространённая практика для CI/CD.
Про обычные аргументы, то есть такие, которые передаются в функцию внутри модуля, читайте статью
*args, **kwargs
Про применение
sys.argv[]
без обёрток читайте
здесь
Здесь будут использованы приёмы, которые можно изучить в следующих статьях:
Exceptions
,
Менеджер контекста
,
Списки
,
Строки
,
Работа с файлами
Пример
import argparse parser = argparse.ArgumentParser() parser.add_argument("filename", help="file to read") args = parser.parse_args() print(args)
python argparse_demo.py site.txt
Namespace(filename='site.txt')
filename попал в Namespace, так как по умолчанию над всеми аргументами совершается действие (action="store")
Можно было явно указать это слеюущим образом:
import argparse parser = argparse.ArgumentParser() parser.add_argument("filename", action="store", help="file to read") …
Если не передать ни одного аргумента
python argparse_demo.py
usage: argparse_demo.py [-h] filename argparse_demo.py: error: the following arguments are required: filename
Если передать лишний аргумент
python argparse_demo.py site.txt demo.txt
usage: argparse_demo.py [-h] filename argparse_demo.py: error: unrecognized arguments: demo.txt
Получить справку по аргументу можно с помощью опции -h
python argparse_demo.py -h filename
usage: argparse_demo.py [-h] filename positional arguments: filename file to read options: -h, --help show this help message and exit
version
У метода add_argument() есть несколько ключевых аргументов.
version это один из них.
Обычно это действие action="version" используется вместе с флагом
--version
Скрипт, вызванный с флагом, у которого стоит action="version" не будет выполняться по стандартному сценарию.
Вместо этого будет выведено значение aргумента version,
которые можно сформировать определённым образом.
Слово version здесь очень перегружено. Чтобы не запутаться ещё раз отметим:
--version - это флаг, который используется при вызове скрипта.
action="version" - указывает, что действие, которое выполняет этот флаг это уже не store а version
version="%(prog)s 2.0" - указывает на то как именно выводить версию.
# argparse_version.py import argparse parser = argparse.ArgumentParser(description="version action demo", prog="PROG") parser.add_argument("--version", "-v", action="version", version="%(prog)s 2.0") args = parser.parse_args() print(args)
Если не задать prog= будет использовано имя файла.
python argparse_version.py --version
PROG 2.0
Видим, что после вывода версии не был напечатан Namespace(), так как скрипт не отработал дефолтный сценарий.
В следующей главе разберём необязательные аргументы с дефолтным action="store"
Необязательный аргумент
Чтобы показать, что аргумент является необязательным перед его именем добавляют два дефиса --.
Такой аргумент часто называют флагом. Обычно после длинной версии
с двумя дефисами, через запятую добавляют короткую версию из одной буквы с одним дефисом -.
Это стандартная практика, которая не ограничивается скриптами на Python, а используется почти везде.
Типичный пример такого аргумента во многих скриптах это --version, -v
Добавим два необязательных аргумента: --limit и --version
# reverse_file.py import argparse parser = argparse.ArgumentParser(description='Reverse a file') parser.add_argument( "filename", action="store", help="the file to read") parser.add_argument( "--limit", "-l", action="store", type=int, help="the number of lines to read" ) parser.add_argument( "--version", "-v", action="version", version="%(prog)s 1.0" ) args = parser.parse_args() print(args)
Этот скрипт нельзя выполнить без обязательного аргумента filename
Помимо случая, когда вызов идёт с флагом --version
python reverse_file.py --version
reverse_file.py 1.0
Но можно спокойно выполнить скрипт не передав --limit
python reverse_file.py sites.txt
Namespace(filename='sites.txt', limit=None)
По умолчанию --limit получил None.
Про --version в Namespace нет упоминаний.
--version это не обычный аргумент, потому что имеет опцию action="version" а не action="store" как у .
Передать необязательный аргумент --limit можно следующим оригинальным образом:
python reverse_file.py sites.txt -l 10
Namespace(filename='sites.txt', limit=10)
Можно передать --limit строкой, если она конвертируема в int
python reverse_file.py sites.txt -l "5"
Namespace(filename='sites.txt', limit=5)
Если аргумент не конвертируем в int получим ошибку
python reverse_file.py sites.txt -l "a"
usage: reverse_file.py [-h] [--limit LIMIT] [--version] filename reverse_file.py: error: argument --limit/-l: invalid int value: 'a'
Добавим в скрипт функционал перезаписывающий файл задом-наперёд.
import argparse parser = argparse.ArgumentParser(description='Reverse a file') parser.add_argument("filename", help="file to read") parser.add_argument("--limit", "-l", type=int, help="number of lines to read" ) parser.add_argument( "--version", "-v", action="version", version="%(prog)s 1.0" ) args = parser.parse_args() with open(args.filename) as f: lines = f.readlines() lines.reverse() if args.limit: lines = lines[:args.limit] for line in lines: print(line.strip()[::-1])
Обратите внимание, на то, что переданные аргументы после парсинга доступны как атрибуты объекта args
Применим скрипт к файлу sites.txt
andreyolegovich.ru aredel.com devhops.ru heihei.ru testsetup.ru topbicycle.ru
python reverse_file.py sites.txt
ur.elcycibpot ur.putestset ur.iehieh ur.spohved moc.ledera ur.hcivogeloyerdna
Применим флаг --limit
python reverse_file.py sites.txt --limit 3
ur.elcycibpot ur.putestset ur.iehieh
Теперь, когда мы хотим прочитать настоящий файл, можно столкнуться с его отсутствием
python reverse_file.py none.txt
Traceback (most recent call last): File "C:\python\reverse_file_form.py", line 14, in <module> with open(args.filename) as f: ^^^^^^^^^^^^^^^^^^^ FileNotFoundError: [Errno 2] No such file or directory: 'none.txt'
Желательно заранее подготовиться к этому с помощью явной
проверки существования файла
или
try
Про
менеджер контекста (with)
можете прочитать
здесь
import argparse parser = argparse.ArgumentParser(description='Reverse a file') parser.add_argument("filename", help="file to read") parser.add_argument("--limit", "-l", type=int, help="number of lines to read" ) parser.add_argument( "--version", "-v", action="version", version="%(prog)s 1.0" ) args = parser.parse_args() try: f = open(args.filename) except FileNotFoundError as e: print(e) else: with f: lines = f.readlines() lines.reverse() if args.limit: lines = lines[:args.limit] for line in lines: print(line.strip()[::-1])
python reverse_file.py none.txt
[Errno 2] No such file or directory: 'none.txt'
Exit Statuses
В предыдущей главе мы обрабатывали ошибку с отсутствующим файлом с помощью try
python reverse_file.py none.txt
[Errno 2] No such file or directory: 'none.txt'
Файл не найден, но скрипт выполнился корректно. Если мы сейчас проверим статус он будет успешным.
Например, в
PowerShell
:
echo $?
True
В Bash
echo $?
0
Нас может не устраивать такой результат. Например, нужно чтобы CI скрипт вызвавший наш модуль получил явный статус об ошибке и сделал соответствующие действия.
Для решения этой задачи используют sys.exit
import argparse import sys parser = argparse.ArgumentParser(description='Reverse a file') parser.add_argument("filename", help="file to read") parser.add_argument("--limit", "-l", type=int, help="number of lines to read" ) parser.add_argument( "--version", "-v", action="version", version="%(prog)s 1.0" ) args = parser.parse_args() try: f = open(args.filename) except FileNotFoundError as e: print(e) sys.exit(2) else: with f: lines = f.readlines() lines.reverse() if args.limit: lines = lines[:args.limit] for line in lines: print(line.strip()[::-1])
python reverse_file.py none.txt
[Errno 2] No such file or directory: 'none.txt'
echo $?
False
echo $?
2
Значения по умолчанию
Чтобы задать значения по умолчанию используется аргумент default.
Пример скрипта, который получает IP адрес и порт для выполнения запроса, но также имеет дефолтные значения.
import requests import argparse parser = argparse.ArgumentParser() parser.add_argument("--ip", nargs="?", default="10.8.1.101", type=str) parser.add_argument("--port", nargs="?", default="5000", type=str) args = parser.parse_args() r = requests.get(f"http://{args.ip}:{args.port}/health") print(r.status_code)
Автор статьи: Андрей Олегович
| Command Line Interface | |
| sys.argv[] |
РЕКЛАМА от Яндекса. Может быть недоступна в вашем регионе
Конец рекламы. Если там пусто считайте это рекламой моей телеги