Du code, du communisme

La plus belle manière de parser les arguments de script en python

On 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  [] [--flag-optionel]
Options:
  -h --help          C'est généré automatiquement.
  --option=  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  [] [--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  [] [--flag-optionel]
Options:
  -h --help          C'est généré automatiquement.
  --option=  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,
 '': 'yo',
 '': None}
$ python nom_du_script.py yo man
{'--flag-optionel': False,
 '': 'yo',
 '': 'man'}
 $ python nom_du_script.py yo --flag-optionel
{'--flag-optionel': True,
 '': 'yo',
 '': 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}