Examples

The following examples illustrate both the usage and the utility of reverse_argparse. They build on each other in complexity, so it will make the most sense to start here at the top and work your way down through each in turn.

The Basics

When using a bare-bones argparse.ArgumentParser, reverse_argparse doesn’t really provide much benefit, but it’s instructive to see how straightforward it is to get up and running with it.

example/basic.py
 1#!/usr/bin/env python3
 2"""Basic ``reverse_argparse`` functionality."""
 3
 4# © 2024 National Technology & Engineering Solutions of Sandia, LLC
 5# (NTESS).  Under the terms of Contract DE-NA0003525 with NTESS, the
 6# U.S. Government retains certain rights in this software.
 7
 8# SPDX-License-Identifier: BSD-3-Clause
 9
10from argparse import ArgumentParser
11
12from reverse_argparse import ReverseArgumentParser
13
14# Construct the `ArgumentParser`.
15parser = ArgumentParser()
16parser.add_argument("--foo")
17
18# Parse the command line arguments.
19args = parser.parse_args()
20
21# Insert the body of your script here.
22
23# Unparse the arguments to tell the user what they ran.
24print("The effective command line invocation was:")
25unparser = ReverseArgumentParser(parser, args)
26print(unparser.get_effective_command_line_invocation())

Note

The only thing you’re adding to your script to take advantage of reverse_argparse is lines 7 and 19–22.

Running the script, and passing an argument to it, yields the following:

$ python3 ../../example/basic.py --foo bar
The effective command line invocation was:
basic.py --foo bar

Default Values

Let’s now take the prior example and add some complexity to it by adding more arguments, but this time with default values.

example/default_values.py
 1#!/usr/bin/env python3
 2"""How ``reverse_argparse`` handles default values."""
 3
 4# © 2024 National Technology & Engineering Solutions of Sandia, LLC
 5# (NTESS).  Under the terms of Contract DE-NA0003525 with NTESS, the
 6# U.S. Government retains certain rights in this software.
 7
 8# SPDX-License-Identifier: BSD-3-Clause
 9
10from argparse import ArgumentParser
11
12from reverse_argparse import ReverseArgumentParser
13
14# Construct the `ArgumentParser`.
15parser = ArgumentParser()
16parser.add_argument("--foo")
17parser.add_argument("--bar", default="spam")
18parser.add_argument("--baz", type=int, default=42)
19
20# Parse the command line arguments.
21args = parser.parse_args()
22
23# Insert the body of your script here.
24
25# Unparse the arguments to tell the user what they ran.
26print("The effective command line invocation was:")
27unparser = ReverseArgumentParser(parser, args)
28print(unparser.get_effective_command_line_invocation())

Now running the script with the same command line arguments yields:

$ python3 ../../example/default_values.py --foo bar
The effective command line invocation was:
default_values.py --foo bar --bar spam --baz 42

Relative References

We can complicate things further by adding an argument representing a path. Though the user is free to specify a relative path on the command line, this will be translated to an absolute path behind the scenes.

example/relative_references.py
 1#!/usr/bin/env python3
 2"""How ``reverse_argparse`` handles relative references."""
 3
 4# © 2024 National Technology & Engineering Solutions of Sandia, LLC
 5# (NTESS).  Under the terms of Contract DE-NA0003525 with NTESS, the
 6# U.S. Government retains certain rights in this software.
 7
 8# SPDX-License-Identifier: BSD-3-Clause
 9
10import os
11from argparse import ArgumentParser
12
13from reverse_argparse import ReverseArgumentParser
14
15# Construct the `ArgumentParser`.
16parser = ArgumentParser()
17parser.add_argument("--foo")
18parser.add_argument("--bar", default="spam")
19parser.add_argument("--baz", type=int, default=42)
20parser.add_argument("--src", type=os.path.abspath)  # type: ignore[arg-type]
21
22# Parse the command line arguments.
23args = parser.parse_args()
24
25# Insert the body of your script here.
26
27# Unparse the arguments to tell the user what they ran.
28print("The effective command line invocation was:")
29unparser = ReverseArgumentParser(parser, args)
30print(unparser.get_effective_command_line_invocation())

Now running the script and pointing to a file in your current working directory yields:

$ python3 ../../example/relative_references.py --src bar.txt
The effective command line invocation was:
relative_references.py --bar spam --baz 42 --src /home/docs/checkouts/readthedocs.org/user_builds/reverse-argparse/checkouts/latest/doc/source/bar.txt

Argument Post-Processing

The example above is actually a special case of any general post-processing of arguments that you might like to do after they are initially parsed. Consider an example of normalizing a date/time from whatever the user specifies to a standard format.

example/post_processing.py
 1#!/usr/bin/env python3
 2"""How ``reverse_argparse`` handles post-processing of arguments."""
 3
 4# © 2024 National Technology & Engineering Solutions of Sandia, LLC
 5# (NTESS).  Under the terms of Contract DE-NA0003525 with NTESS, the
 6# U.S. Government retains certain rights in this software.
 7
 8# SPDX-License-Identifier: BSD-3-Clause
 9
10import os
11from argparse import ArgumentParser
12
13import dateparser
14
15from reverse_argparse import ReverseArgumentParser
16
17# Construct the `ArgumentParser`.
18parser = ArgumentParser()
19parser.add_argument("--foo")
20parser.add_argument("--bar", default="spam")
21parser.add_argument("--baz", type=int, default=42)
22parser.add_argument("--src", type=os.path.abspath)  # type: ignore[arg-type]
23parser.add_argument("--before")
24
25# Parse the command line arguments.
26args = parser.parse_args()
27if args.before is not None:
28    args.before = dateparser.parse(args.before)
29
30# Insert the body of your script here.
31
32# Unparse the arguments to tell the user what they ran.
33print("The effective command line invocation was:")
34unparser = ReverseArgumentParser(parser, args)
35print(unparser.get_effective_command_line_invocation())

Now running the script and specifying a relative date/time yields:

$ python3 ../../example/post_processing.py --before '30 minutes ago'
The effective command line invocation was:
post_processing.py --bar spam --baz 42 --before '2024-05-13 19:00:31.026047'

Pretty-Printing the Effective Command

In all of the above, the effective command line invocation will be printed on a single line. Often this is what you want, as it facilitates easy copying and pasting. However, when your script grows in complexity, you may want to pretty-print the output such that it’s easier to see at a glance what all the different flags and corresponding values are.

example/pretty_printing.py
 1#!/usr/bin/env python3
 2"""``reverse_argparse`` pretty-printing functionality."""
 3
 4# © 2024 National Technology & Engineering Solutions of Sandia, LLC
 5# (NTESS).  Under the terms of Contract DE-NA0003525 with NTESS, the
 6# U.S. Government retains certain rights in this software.
 7
 8# SPDX-License-Identifier: BSD-3-Clause
 9
10import os
11from argparse import ArgumentParser
12
13import dateparser
14
15from reverse_argparse import ReverseArgumentParser
16
17# Construct the `ArgumentParser`.
18parser = ArgumentParser()
19parser.add_argument("--foo")
20parser.add_argument("--bar", default="spam")
21parser.add_argument("--baz", type=int, default=42)
22parser.add_argument("--src", type=os.path.abspath)  # type: ignore[arg-type]
23parser.add_argument("--before")
24
25# Parse the command line arguments.
26args = parser.parse_args()
27if args.before is not None:
28    args.before = dateparser.parse(args.before)
29
30# Insert the body of your script here.
31
32# Unparse the arguments to tell the user what they ran.
33print("The effective command line invocation was:")
34unparser = ReverseArgumentParser(parser, args)
35print(unparser.get_pretty_command_line_invocation())

Now running the script and specifying a relative date/time yields:

$ python3 ../../example/pretty_printing.py --foo eggs --src file.txt --before 'today'
The effective command line invocation was:
pretty_printing.py \
    --foo eggs \
    --bar spam \
    --baz 42 \
    --src /home/docs/checkouts/readthedocs.org/user_builds/reverse-argparse/checkouts/latest/doc/source/file.txt \
    --before '2024-05-13 19:30:31.523538'

Subparsers

A special case you might be concerned with is that of an argparse.ArgumentParser with multiple subparsers or sub-commands, each of which will have its own arguments, and even potentially nested subparsers. When using get_effective_command_line_invocation(), you won’t notice anything different, but get_pretty_command_line_invocation() shows the subtle difference.

example/subparsers.py
 1#!/usr/bin/env python3
 2"""How ``reverse_argparse`` handles subparsers."""
 3
 4# © 2024 National Technology & Engineering Solutions of Sandia, LLC
 5# (NTESS).  Under the terms of Contract DE-NA0003525 with NTESS, the
 6# U.S. Government retains certain rights in this software.
 7
 8# SPDX-License-Identifier: BSD-3-Clause
 9
10import os
11from argparse import ArgumentParser
12
13import dateparser
14
15from reverse_argparse import ReverseArgumentParser
16
17parser = ArgumentParser()
18subparsers = parser.add_subparsers(title="Subcommands")
19foo_parser = subparsers.add_parser("foo")
20foo_parser.add_argument("--one")
21foo_parser.add_argument("--two", default="spam")
22foo_parser.add_argument("--three", type=int, default=42)
23bar_parser = subparsers.add_parser("bar")
24bar_parser.add_argument(
25    "--four",
26    type=os.path.abspath,  # type: ignore[arg-type]
27)
28bar_parser.add_argument("--five")
29
30# Parse the command line arguments.
31args = parser.parse_args()
32if getattr(args, "five", None) is not None:
33    args.five = dateparser.parse(args.five)
34
35# Insert the body of your script here.
36
37# Unparse the arguments to tell the user what they ran.
38print("The effective command line invocation was:")
39unparser = ReverseArgumentParser(parser, args)
40print(unparser.get_pretty_command_line_invocation())

Running this script and using the foo subcommand yields:

$ python3 ../../example/subparsers.py foo --one eggs
The effective command line invocation was:
subparsers.py \
    foo \
        --one eggs \
        --two spam \
        --three 42

Note

The arguments associated with the subparser have been indented by an extra level. If there are subparsers within subparsers, reverse_argparse keeps track of the indentation level while unparsing, so the user can easily see which arguments correspond to which subparser.