La plus belle manière de parser les arguments de script en python
lundi 3 mars 2014 à 15:06On peut parser sys.argv
à la main, mais c’est fragile.
On peut utiliser getopt ou optpase, mais c’est déprécié.
On peut adopter le nouveau module de la stdlib, vers argparse, mais c’est compliqué.
Alors j’installais toujours clize.
Mais depuis que j’ai rencontré docopt, j’ai largué clize (c’est pas moi chérie, c’est toi) et on vit en amoureux tous les deux en élevant des scripts dans une ferme dans les Alpes.
pip install docopt
Docopt fonctionne à l’envers de la plupart des libs de ce genre : vous écrivez le message d’aide de votre script, et ça génère le parsing des arguments. La syntaxe de l’aide est de type posix, donc si vous avez utilisez un -h
ou la commande man
un jour, vous la connaissez déjà.
Voici comment ça marche :
help = """Le nom de mon programme trop cool Usage: nom_du_script.py <argument_positionel> [<argument_positionel_optionel>] [--flag-optionel] Options: -h --help C'est généré automatiquement. --option=<valeur> Description de l'option. Woot, un footer ! """ from docopt import docopt arguments = docopt(help) print(arguments)
Si on passe rien de valide au script, l’usage est affiché automatiquement :
$ python nom_du_script.py Usage: nom_du_script.py <argument_positionel> [<argument_positionel_optionel>] [--flag-optionel]
Si on demande l’aide, en option, ben, l’aide quoi :
$ python nom_du_script.py -h Le nom de mon programme trop cool Usage: nom_du_script.py <argument_positionel> [<argument_positionel_optionel>] [--flag-optionel] Options: -h --help C'est généré automatiquement. --option=<valeur> Description de l'option. Woot, un footer !
Et si on passe des arguments, on les récupère dans un simple dictionnaire :
$ python nom_du_script.py yo {'--flag-optionel': False, '<argument_positionel>': 'yo', '<argument_positionel_optionel>': None} $ python nom_du_script.py yo man {'--flag-optionel': False, '<argument_positionel>': 'yo', '<argument_positionel_optionel>': 'man'} $ python nom_du_script.py yo --flag-optionel {'--flag-optionel': True, '<argument_positionel>': 'yo', '<argument_positionel_optionel>': None}
Ça peut générer des choses complexes avec des tas de combinaisons d’options, des sous-commandes et tout le bordel.
Généralement on en profite pour faire ça proprement, en mettant l’usage en docstring du script, en calant une version et en rajoutant un if __main__
:
"""Uber script. Usage: schnell.py scheisse schnell.py bier Options: -h --help _o/ --version \o_ --blitz=krieg \o/ """ from docopt import docopt if __name__ == '__main__': # __doc__ contient automatiquement la docstring du module # en cours arguments = docopt(__doc__, version='0.1') print(arguments)
$ python schnell.py --version 0.1 $ python schnell.py bier {'bier': True, 'scheisse': False}