HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Simplifying parsing command-line arguments

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
argumentslineparsingsimplifyingcommand

Problem

I'm currently working on a command-line "database migration" utility. Here are some of the requirements regarding reading the command-line arguments part:

  • It should accept regular database connection parameters: host, database name, port, user and password (do not allow to specify password as a command-line argument, ask for password separately)



  • It works in two modes - "validate" and "apply" - one of them has to be specified explicitly, both cannot be specified



  • There should be an integer "batch size" argument specified



  • There can be an optional range of integer ids specified via --id-begin and --id-end (the beginning of the range defaults to 1 if not specified)



  • Instead of a range, there can also be a --name argument specified



  • Both name and id range cannot be present



  • There should be a "verbose" flag



My Solution

Here is what I came up with:

I'm using argparse module and extracted the parsing command-line arguments into a separate .parse_args() function which returns the parsed arguments (which is argparse.Namespace instance):

```
import argparse
import getpass

def parse_arguments(args):
"""Parses command-line arguments."""
parser = argparse.ArgumentParser()

# general database connection settings
parser.add_argument('-H', '--host', help="Database host IP address", required=True)
parser.add_argument('-D', '--database', help="Database name", required=True)
parser.add_argument('-P', '--port', help="Database port", required=True, type=int)

parser.add_argument('-u', '--user', help='Database user name', required=True)

# modes
parser.add_argument('--validate', help='Enables "validate only" mode', action='store_true')
parser.add_argument('--apply', help='Enables "apply" mode', action='store_true')

# extra settings
parser.add_argument('-b', '--batch-size', help='Batch size - determines how many cases are processed at a time',
type=int, default=5000)
parser.add

Solution

Your function should have args=None as default. This way you can use it to parse the command-line arguments as well as pass in a list of arguments to parse.

For your mutual exclusive options you should use...mutual exclusive groups. However, this only works properly for your mode, because adding a group of not mutually exclusive options (your --id-begin and --id-end) to a mutually exclusive group seems to no be supported at the moment, even though there was some activity on that a few years back: http://bugs.python.org/issue10984

# modes
action = parser.add_mutually_exclusive_group(required=True)
action.add_argument(
    '--validate', help='Enables "validate only" mode', action='store_true')
action.add_argument(
    '--apply', help='Enables "apply" mode', action='store_true')


With the above code, you can remove all checking you currently do on the modes. It requires that exactly one of the modes is activated.

Also note that the default behavior of action='store_true' is to have default=False, so you can just do:

parser.add_argument('--verbose', help='Enables "verbose" reporting mode',
                    action='store_true')

Code Snippets

# modes
action = parser.add_mutually_exclusive_group(required=True)
action.add_argument(
    '--validate', help='Enables "validate only" mode', action='store_true')
action.add_argument(
    '--apply', help='Enables "apply" mode', action='store_true')
parser.add_argument('--verbose', help='Enables "verbose" reporting mode',
                    action='store_true')

Context

StackExchange Code Review Q#157747, answer score: 4

Revisions (0)

No revisions yet.