[PYTHON] Introducing how to use argparse for people who are laid back with as little effort as possible

Introduction

If you want to create some command (CLI), you use argparse. Here are some tips on how to use this argparse comfortably and conveniently with as little effort as possible.

No need to pass sys.argv

In some argparse usage introductions, I'm seriously passing sys.argv. You do not need. Calling parse_args () with no arguments will do just fine.

import argparse


parser = argparse.ArgumentParser()
parser.parse_args()  #This is OK

Let argparse handle the display of help messages

If you add -h or --help, argparse will automatically add the function to display the help message. On top of that, it is convenient to leave the behavior when you make a mistake in the usage to argparse.

You don't need to write this kind of code, for example, if you run it with no arguments.

import sys

#This code is unnecessary
if len(sys.argv) == 0:
    parser.parse_args(["-h"])

I just wanted to tell you that it's unnecessary because there were so many good things about this article.

-[Template when creating a command line application with Python --Qiita](http://qiita.com/Alice1017/items/0464a38ab335ac3b9336#python%E3%81%A7%E3%82%B3%E3%83%9E% E3% 83% B3% E3% 83% 89% E3% 83% A9% E3% 82% A4% E3% 83% B3% E3% 82% A2% E3% 83% 97% E3% 83% AA% E3% 82% B1% E3% 83% BC% E3% 82% B7% E3% 83% A7% E3% 83% B3% E3% 82% 92% E4% BD% 9C% E3% 82% 8B% E3% 81% A8% E3% 81% 8D% E3% 81% AE% E9% 9B% 9B% E5% BD% A2)

Postscript:

It seems that the intention of this code was to give all long help instead of short usage message on error. It's a bit hacky, but you can write it like this (although some people may prefer the original code, which clearly shows what's going on):

parser.print_usage = parser.print_help

For positional argument

If you specify even one positional argument, the lack of arguments is automatically checked, so you do not need to do anything.

import argparse

parser = argparse.ArgumentParser("<command name>")
parser.add_argument("file")  # positional argument
args = parser.parse_args()
$ python cmd.py
usage: <command name> [-h] file
<command name>: error: the following arguments are required: file

For option

If everything was optional, add required = True to what seems to be required (although there is talk of a positional argument if required).

import argparse

parser = argparse.ArgumentParser("<command name>")
parser.add_argument("--file", required=True)
args = parser.parse_args()
$ python cmd.py
usage: <command name> [-h] --file FILE
<command name>: error: the following arguments are required: file

Let's make it easier by specifying the default arguments

Another possible behavior is when it is executed without specifying any arguments. It is to process by embedding the default value. This can be specified with default.

For example, you may want to create a command that receives data from standard input if you don't specify a file.

For positional argument

If specified in a positional argument, use nargs ="? " To make it optional

import sys
import argparse


parser = argparse.ArgumentParser("hai")
parser.add_argument("file", nargs="?", type=argparse.FileType("r"), default=sys.stdin)
args = parser.parse_args()

print(args.file.read())

This will work.

$ cat hello.txt | python echo.py
$ python echo.py hello.txt

For option

For optional arguments, just specify default.

parser.add_argument("--file", type=argparse.FileType("r"), default=sys.stdin)

Let's make it easier with action

It is useful to remember the action received by the parser's add_argument. You don't have to remember everything, but it's easier to remember some actions.

store_true / store_false in option argument

For example, use store_true when you have flags like --with- <something> or options that take no arguments like --debug. default value will be False

parser.add_argument("--debug", action="store_true")

Conversely, use store_false if the flag is --without- <something>, or if default is set to True and the option is set to False.

parser.add_argument("--execute", action="store_false")  #default is dry-Situation like run

Note that if you want to provide both the with-foo and without-foo flags, you should specify the default values with set_defaults (). Otherwise, the default value will depend on the order in which you wrote it.

#default is debug=False
parser.add_argument("--without-debug", action="store_false", dest="debug")
parser.add_argument("--with-debug", action="store_true", dest="debug")
parser.set_defaults(debug=False)

Append if you want to pass multiple values for the same option

If you want to take multiple values, specify append for action.

import argparse


parser = argparse.ArgumentParser()
parser.add_argument("--target", action="append")
args = parser.parse_args()
print(args)

It works as follows.

$ python cmd.py --target x --target y --target z
Namespace(target=['x', 'y', 'z'])

Use choices if you want to limit the range of possible values

If you want to limit the range of possible values, it is convenient to use choices. For example, the part that specifies the logging level should be written as follows.

import argparse
import logging

parser = argparse.ArgumentParser()
loglevels = list(logging._nameToLevel.keys())  # _It ’s a prefix, so it ’s not well-behaved.
parser.add_argument("--loglevel", choices=loglevels, default="INFO")

args = parser.parse_args()
logging.basicConfig(level=args.loglevel)
logger = logging.getLogger("log")

logger.debug("hmm..")
logger.info("hmm")

I feel that info is good for default.

$ python cmd.py
INFO:log:hmm
$ python cmd.py -h
usage: cmd.py [-h]
                    [--loglevel {WARN,INFO,NOTSET,DEBUG,CRITICAL,WARNING,ERROR}]

optional arguments:
  -h, --help            show this help message and exit
  --loglevel {WARN,INFO,NOTSET,DEBUG,CRITICAL,WARNING,ERROR}
$ python cmd.py --loglevel=DEBUG
DEBUG:log:hmm..
INFO:log:hmm

Read the argparse documentation

It is more useful to look at the official document than to read this article because the explanation of the official document is useful in detail. See the official documentation.

bonus

Subcommand

If you want to create a subcommand, give up argparse early and use click.

Convert from function definition to command

After that, it is useful to remember one package that can be executed as a command from the function definition (I made it myself).

For example, it is as follows.

# greeting.py
from handofcats import as_command

@as_command
def greeting(message, is_surprised=False, name="foo"):
    suffix = "!" if is_surprised else ""
    print("{name}: {message}{suffix}".format(name=name, message=message, suffix=suffix))
$ pip install handofcats
$ python greeting.py -h
python greeting.py -h
usage: greeting.py [-h] [--is-surprised] [--name NAME] [-v] [-q] message

positional arguments:
  message

optional arguments:
  -h, --help      show this help message and exit
  --is-surprised
  --name NAME
  -v, --verbose   (default option: increment logging level(default is
                  WARNING))
  -q, --quiet     (default option: decrement logging level(default is
                  WARNING))
$ python greeting.py
foo: hello
$ python greeting.py --is-surprised --name me hello
me: hello!

Recommended Posts

Introducing how to use argparse for people who are laid back with as little effort as possible
Tips for those who are wondering how to use is and == in Python
For those who want to display images side by side as soon as possible with Python's matplotlib
How to use Python argparse
People who are accustomed to Android programs try multithreading with Python
Links to people who are just starting data analysis with python
How to use an external editor for Python development with Grasshopper
Python: How to use async with
How to use virtualenv with PowerShell
How to use FTP with Python
Let's get started with Python 3. ~ For kittens who are wondering what to choose as their main language ~
How to make Selenium as light as possible
How to use ManyToManyField with Django's Admin
How to use OpenVPN with Ubuntu 18.04.3 LTS
How to use Cmder with PyCharm (Windows)
How to use Ass / Alembic with HtoA
How to use Japanese with NLTK plot
[Python] Organizing how to use for statements
How to use jupyter notebook with ABCI
How to use Pylint for PyQt5 apps
How to use CUT command (with sample)
How to use "deque" for Python data
How to use fingerprint authentication for KDE
How to use SQLAlchemy / Connect with aiomysql
How to use JDBC driver with Redash
How to use Service Account OAuth and API with Google API Client for python