1

I'm looking to provide flexible input into my parser. My use case is I have a python script to run some queries that are date range based. How I want the arg parser to operate is if only one date is supplied, use that date as both the start and end dates, but if two dates are used, use those.

So at least one date needs to be supplied, but no more than two dates. Is that possible?

def main(args):
    parser = argparse.ArgumentParser(description="Run ETL for script")
    
    parser.add_argument('-j', '--job_name', action='store', default=os.path.basename(__file__), type=str, help="Job name that gets used as part of the metadata for the job run.")
    parser.add_argument("-d", "--date-range", nargs=2, metavar=('start_date', 'end_date'), default=['2021-01-01', '2021-01-01'], action='store', help="Operating range for script and data sources (as applicable)")
    parser.add_argument('-e', '--env', action='store', choices=['dev', 'stage', 'prod'], default='dev', help="Environment to execute.")
    parser.add_argument('-c', '--config', action='store', choices=['small', 'medium', 'large'], default='small', help="Resource request.  See configs for each.") 
    
    args = parser.parse_args()
    
    if args.date_range[0] <= args.date_range[1]:
        job_meta = {
            "script" : args.job_name,
            "start_date" : args.date_range[0],
            "end_date" : args.date_range[1],
            "environment" : args.env,
            "resource" : args.config
        }
        run_job(job_meta)
    else:
        print('Invalid date range.  Start date as inputted may be following the end date.')
        sys.exit(0)

if __name__ == "__main__":
    main(sys.argv[1:])

Jammy
  • 413
  • 1
  • 6
  • 12
  • With `nargs='+'` you get part way there. It won't limit it to 2, but your post parsing testing can complain if there are more. – hpaulj Sep 16 '21 at 23:20
  • I would just use two flags, `start_date` and `end_date`. Make `start_date` required. If `end_date` does not exist, then set it to the value of `start_date`. – SpaceKatt Sep 16 '21 at 23:25

1 Answers1

1

In order to achieve that you can create a new action that check the number of argument given to the nargs.

import argparse

class LimitedAppend(argparse._AppendAction):
    def __call__(self, parser, namespace, values, option_string=None):
        if not (1 <= len(values) <= 2):
            raise argparse.ArgumentError(self, "%s takes 1 or 2 values, %d given" % (option_string, len(values)))
        super().__call__(parser, namespace, values, option_string)


parser.add_argument("-d", "--date-range", ..., nargs='+', action=LimitedAppend)

Then you can check the length of this argument and do what you wanted to do

CyDevos
  • 395
  • 4
  • 11