Search code examples
python-3.xstdinargparse

Automate python argparse script with pre-generated inputs


I have a program which takes folder paths and other inputs through the command line with argparse. I want this script to run automatically on a server, but I also want to keep its argparse functionality in case I want to run the script manually. Is there a way to have the script use pre-generated inputs from a file but also retain its flag based input system with argparse? Here is my current implementation:

parser = argparse.ArgumentParser(description='runs batch workflow on root directory')
parser.add_argument("--root", type=str, default='./', help="the path to the root directory 
                    to process")
parser.add_argument("--data", type=str, default='MS', help="The type of data to calculate ")
args = parser.parse_args()

root_dir = args.root
option = args.data

I'm pretty new to this stuff, and reading the argparse documentation and This stack overflow question is not really what I want, if possible I would like to keep the root and data flags, and not just replace them with an input file or stdin.


Solution

  • If using argparse, the default keyword argument is a good, standard way to approach the problem; embed the default behavior of the program in the script source, not an external configuration file. However, if you have multiple configuration files that you want to deploy differently, the approach you mentioned (pre-generated from an input) is desirable.

    argparse to dictionary

    The argparse namespace can be converted to a dictionary. This is convenient as we can make a function that accepts a dictionary, or keyword arguments, and have it process the program with a convenient function signature. Also, file parsers can just as easily load dictionaries and interact with the same function. The python json module is used as an example. Of course, others can be used.

    Example Python

    def main(arg1=None, arg2=None, arg3=None):
        print(f"{arg1}, {arg2}, {arg3}")
    
    if __name__ == "__main__":
        import sys
        import json
        import argparse
    
        # script called with nothing -- load default
        if len(sys.argv) == 1:
            with open("default.json", "r") as dfp:
                conf = json.load(dfp)
            main(**conf)
    
        else: # parse arguments
            parser = argparse.ArgumentParser()
            parser.add_argument('-a1', dest='arg1', metavar='arg1', type=str)
            parser.add_argument('-a2', dest='arg2', metavar='arg2', type=str)
            parser.add_argument('-a3', dest='arg3', metavar='arg3', type=str)
            args = parser.parse_args()
            conf = vars(args)
            main(**conf)
    

    default.json

    {
        "arg1" : "str1",
        "arg2" : "str2",
        "arg3" : "str3"
    }
    

    Using Fire

    The python Fire module can be used more conveniently as well. It has multiple modes that the file can be interacted with minimal effort. The github repo is available here.