Spécifiez le format des arguments d'entrée argparse python

111

J'ai un script python qui nécessite des entrées de ligne de commande et j'utilise argparse pour les analyser. J'ai trouvé la documentation un peu déroutante et je n'ai pas trouvé de moyen de vérifier un format dans les paramètres d'entrée. Ce que je veux dire par vérification du format est expliqué dans cet exemple de 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__)))

Je dois vérifier l'option -set -eque l'entrée de l'utilisateur est au format YYYY-MM-DD. Y a-t-il une option dans argparse que je ne sais pas qui accomplit cela.

Sohaib
la source

Réponses:

235

Selon la documentation :

L' typeargument mot-clé de add_argument()permet d' effectuer toutes les vérifications de type et conversions de type nécessaires ... type=peut prendre tout appelable qui prend un seul argument de chaîne et renvoie la valeur convertie

Vous pouvez faire quelque chose comme:

def valid_date(s):
    try:
        return datetime.strptime(s, "%Y-%m-%d")
    except ValueError:
        msg = "Not a valid date: '{0}'.".format(s)
        raise argparse.ArgumentTypeError(msg)

Ensuite, utilisez-le comme type:

parser.add_argument("-s", 
                    "--startdate", 
                    help="The Start Date - format YYYY-MM-DD", 
                    required=True, 
                    type=valid_date)
Jonrsharpe
la source
À propos de l'autre question que vous avez supprimée, pouvez-vous m'indiquer la documentation (le cas échéant) pour cela?
Sohaib
Suppose-t-il valid_date()que l'argument donné est une chaîne?
Stevoisiak
1
@StevenVascellaro oui, mais c'est ce que définit l'API; "prend un seul argument de chaîne" selon la citation de la documentation.
jonrsharpe
71

Juste pour ajouter à la réponse ci-dessus, vous pouvez utiliser une fonction lambda si vous souhaitez la conserver sur une seule ligne. Par exemple:

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

Vieux fil mais la question était toujours d'actualité pour moi au moins!

Evan V
la source
6
C'est une belle astuce, bien que si vous transmettez quelque chose d'invalide, le message d'erreur sera simplementinvalid <lambda> value
Brad Solomon
38

Pour les autres qui utilisent les moteurs de recherche: en Python 3.7, vous pouvez utiliser la .fromisoformatméthode de classe standard au lieu de réinventer la roue pour les dates conformes à la norme ISO-8601, par exemple:

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)
Michał Górny
la source
5
De plus, dateutill' analyseur ISO prend un certain nombre de fmts supplémentaires qui sont toujours conformes à la norme ISO 8601-2004. Vous pouvez utiliser import dateutil.parser-> type=dateutil.parser.isoparseoutype=dateutil.parser.parse
Brad Solomon
@BradSolomon En effet une bonne suggestion (d'où mon +1), mais dateutilc'est un package tiers. Il faudrait juger ses avantages par rapport au (petit) tracas de l'installer en plus. YMMV.
Laryx Decidua le