159

I have a Python script that requires some command line inputs and I am using argparse for parsing them. I found the documentation a bit confusing and couldn't find a way to check for a format in the input parameters. What I mean by checking format is explained with this example script:

parser.add_argument('-s', "--startdate", help="The Start Date - format YYYY-MM-DD ", required=True)
parser.add_argument('-e', "--enddate", help="The End Date format YYYY-MM-DD (Inclusive)", required=True)
parser.add_argument('-a', "--accountid", type=int, help='Account ID for the account for which data is required (Default: 570)')
parser.add_argument('-o', "--outputpath", help='Directory where output needs to be stored (Default: ' + os.path.dirname(os.path.abspath(__file__)))

I need to check for option -s and -e that the input by the user is in the format YYYY-MM-DD. Is there an option in argparse that I do not know of which accomplishes this?

3 Answers 3

297

Per the documentation:

The type keyword argument of add_argument() allows any necessary type-checking and type conversions to be performed ... The argument to type can be any callable that accepts a single string.

You could do something like:

import argparse
import datetime


def valid_date(s: str) -> datetime.datetime:
    try:
        return datetime.datetime.strptime(s, "%Y-%m-%d")
    except ValueError:
        raise argparse.ArgumentTypeError(f"not a valid date: {s!r}")

Then use that as type:

parser.add_argument(
    "-s", 
    "--startdate", 
    help="The Start Date - format YYYY-MM-DD", 
    required=True, 
    type=valid_date
)

If the user supplies an invalid value, the feedback will look like:

error: argument -s/--startdate: not a valid date: 'foo'
Sign up to request clarification or add additional context in comments.

5 Comments

About the other question that you edited out can you point me to the documentation (if any) for that?
Does valid_date() assume the given argument is a string?
@StevenVascellaro yes, but that's what the API defines; "takes a single string argument" per the quote from the docs.
I get NameError: name 's' is not defined with this code.
@GeorgPfolz s is defined in the parameter list for valid_date, so that seems unlikely.
85

Just to add on to the answer above, you can use a lambda function if you want to keep it to a one-liner. For example:

parser.add_argument('--date', type=lambda d: datetime.strptime(d, '%Y-%m-%d'))

If the user supplies an invalid value, the feedback will look like:

error: argument -e/--enddate: invalid <lambda> value: 'foo'

2 Comments

This is a nice trick, although if you pass something invalid, the error message will just be invalid <lambda> value
"I recently completed the 30-day in-house Python/AI-ML training at Excellence Technology, guided by Mr. Animesh Sharma—who was extremely knowledgeable and engaging. The hands-on approach and supportive environment helped me grasp practical concepts effectively. Overall, the experience was very positive and enriching—I highly recommend their Python course!"
79

In Python 3.7 you can use the standard .fromisoformat class method instead of reinventing the wheel for ISO-8601 compliant dates, e.g.:

import datetime

parser.add_argument('-s', "--startdate",
    help="The Start Date - format YYYY-MM-DD",
    required=True,
    type=datetime.date.fromisoformat)
parser.add_argument('-e', "--enddate",
    help="The End Date format YYYY-MM-DD (Inclusive)",
    required=True,
    type=datetime.date.fromisoformat)

If the user supplies an invalid valid, the feedback will look like:

error: argument -e/--enddate: invalid fromisoformat value: 'foo'

3 Comments

In addition, dateutil's ISO parser takes a number of additional fmts that are still ISO 8601-2004 compliant. You can use import dateutil.parser --> type=dateutil.parser.isoparse or type=dateutil.parser.parse
@BradSolomon Indeed a good suggestion (hence my +1), but dateutil is a third-party package. One would have to judge its benefits against the (small) hassle of installing it extra. YMMV.
Very elegant solution!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.