This is another post in the series lessons learned building machine learning systems.
Your argparse should not be the interface of your application. Instead, your argparse should be a specific implementation of it.
Consider the following example. I used to always structure my code like this
import argparse import sys if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("--foo", type=int) args, _ = parser.parse_known_args(sys.argv[1:]) foo = args.foo result = foo + 1
Instead what we should do is this
def run(args: argparse.Namespace): foo = args.foo result = foo + 1 if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("--foo", type=int) args, _ = parser.parse_known_args(sys.argv[1:]) run(args)
The difference is that the argparse becomes a specific implementation of the actual interface, which is the
Before: No separation between interface (the argparse) and implementation (also the argparse).
After: Clear separation between interface (
run function) and implementation (argparse).
This separation makes our code easier to test.
We now can write another testing implementation just using the
run function instead of having to rely on the argparse to test the full flow of the application.
In this trivial example it almost seems obvious, but for some reason I did manage to completely forgot this in a larger and more complex codebase.
The solution is simple, just wrap whatever is happening in your
__main__ into a single function called