Motivation
Replicability—the ability for someone else to do exactly what you did at some point in the past, on the same or an equivalent machine, using the same tooling you used, and achieve the same results—is a complex problem. When someone has a problem running a script, there’s often a good deal of time wasted iterating back and forth between the person having the problem and those who might be able to help them solve it. Questions such as the following arise:
What kind of machine are you using?
What’s your environment look like?
What did you run at the command line?
Can you provide all the output?
And in our asynchronous work environment, there’s often quite a bit of time spent waiting for the person on the other end of the conversation to come back to it, think about a response, and then move the conversation forward. Frustration can build throughout, especially when you run into, “I just ran the same thing you did, and it worked fine for me.”
While tackling the issue of rock-solid replicability is far beyond the scope of
a single package, reverse_argparse
aims to make life a little bit easier
when it comes to this last issue.
What Exactly Did You Run?
When your Python script requires input from the user, the go-to solution is the
argparse
module in the standard library, which makes it easy to write
user-friendly command-line interfaces. As scripts grow in complexity, it’s
common for the number of command-line arguments to grow, but then, for
simplicity’s sake, it’s recommended to use default values wisely such that the
user isn’t required to specify dozens of arguments each time they run the
script.
In such a scenario, asking someone what they ran in the terminal may be insufficient, because
python3 my_script.py --foo bar
for one person, in one environment, in one location, on one machine, may be different from the same line executed by a different person, in a different environment, in a different location, on a different machine.
What Might Go Wrong?
The differences that may occur generally fall into three categories.
When default values change
Say you’re using one version of the script, and your collaborator is using a different one (perhaps they’re working on another branch). In your version
python3 my_script.py --foo bar
translates to
python3 my_script.py --foo bar --baz
but in their version it translates to
python3 my_script.py --foo bar --no-baz
# ^^^
because someone updated a default value. You’ll probably spend a good deal of time playing around with the debugger or print statements before you figure out the switch.
When using relative references
Changes in default values hopefully occur infrequently. Perhaps a more common occurrence is when using relative references. Say a script requires some file as input, so you run
python3 my_script.py --foo bar.txt
and this translates to
python3 my_script.py --foo /path/to/some-dir/bar.txt
However, your colleague, not having all the information needed to replicate your error, runs the exact same thing, but it translates to
python3 my_script.py --foo /path/to/some-other-dir/bar.txt
# ^^^^^^^^^^^^^^
There’s no telling how long you two will go back and forth before realizing that your relative references resolved to different files.
When arguments are post-processed
A final potential source of confusion is when arguments go through some amount
of post-processing after they’re read in via
argparse.ArgumentParser.parse_args()
. For instance, perhaps the input is
normalized in some way, as in the case where
python3 my_script.py --start-time '30 minutes ago'
translates to
python3 my_script.py --start-time '2023-07-01T12:34:56Z'
but when your colleague gets around to running your script a few days later, the exact same line translates to
python3 my_script.py --start-time '2023-07-05T05:43:21Z'
Who knows how long it’ll take you two to figure out you’re actually looking at different data sets under the hood?
What’s the Solution?
The reverse_argparse
module aims to solve these problems for you. It takes
as input two things:
The
argparse.Namespace
of parsed arguments, which already accounts for any default values applied, and any post-processing you might’ve done with them.The
argparse.ArgumentParser
that parsed the arguments.
These two are then used to undo the parsing such that you can generate a string of the complete, effective command line invocation of the script. When someone asks what you ran in the terminal, you can give them this string and avoid a good deal of wasted time, confusion, and frustration, which will hopefully help you solve your problems more quickly.