title:      Un template python pour parser des arguments
slug:       un-template-python-pour-parser-des-arguments
date:       2006-02-18 17:56:10
type:       post
vignette:   images/logos/python_nouveau.png
contextual_title1:  Bonnes pratiques et astuces Python
contextual_url1:    20080511-bonnes-pratiques-et-astuces-python
contextual_title2:  Benchmarks map, filter vs. list-comprehensions
contextual_url2:    20061025-benchmarks-map-filter-vs-list-comprehensions
contextual_title3:  Python : lisibilité vs simplicité
contextual_url3:    20060425-python-et-underscore

<p>En réaction au billet de <a href="http://blog.virgule.info/2006/02/17/137-convertisseur-em-vers-pixels">mat qui a codé un convertisseur em vers pixels</a>. Je me demande souvent si la méthode que j'emploie est la plus pertinente pour parser des arguments en ligne de commande lorsque je crée des petits scripts en python. Voici le template que j'utilise souvent, toutes les remarques en commentaire sont les bienvenues&nbsp;!</p>

<pre>#!/usr/bin/python
# -*- coding: iso-8859-1 -*-

"""
Explain what program do.
"""

import os
import sys
from textwrap import wrap
from getopt import getopt

# Global default settings, had to be get/set with appopriate functions
settings = {
    "verbose" : False,          # -v  option
    "other_option" : ""         # -o: option
}
def set_settings(key, value): settings[key] = value
def get_settings(key): return settings[key]

def verify_arguments_existence():
    """ For each command line argument, check existence if necessary """
    if get_settings("other_option") == "":
        set_settings("other_option", "default")

def parse_arguments():
    shortopts = "".join([opt[0] for opt in options])
    longopts = [opt[1] for opt in options]
    opts, args = getopt(sys.argv[1:], shortopts, longopts)
    for opt, optarg in opts:
        for tuple in options:
            short = "-" + tuple[0][:1]
            long = "--" + tuple[1]
            if long.endswith("="):
                long = long[:-1]
            if opt in [short, long]:
                tuple[2](optarg)
                break

def print_help(*args):
    print "USAGE:
   %s [options]
" % sys.argv[0]
    print "OPTIONS:"
    for short, long, func, doc in options:
        print
        if short[-1] == ":":
            print "  -%s filename, --%sfilename" % (short[:1], long)
        else:
            print "  -%s, --%s" % (short[:1], long)
        for line in wrap(doc):
            print "    %s" % line
    print "
EXAMPLE:"
    print "   %s -v -o:argument
" % sys.argv[0]
    sys.exit(0)

# Syntax : short option, long option, action, help
options = [
    ("h", "help", print_help,
     "Print out this usage summary."),

    ("v", "verbose", lambda optarg: set_settings("verbose", True),
     "Write output informations (not only errors)."),

    ("o:", "other-option=", lambda optarg: set_settings("other_option", optarg),
     "Another option for the template.")
]

def main():
    """ Main function, deals with arguments and launch program"""
    # Usual verifications and warnings
    if not sys.argv[1:]:
        sys.stdout.write("Sorry: you must specify at least an argument
")
        sys.stdout.write("More help avalaible with -h or --help option
")
        sys.exit(0)
    parse_arguments()
    verify_arguments_existence()

    # THE program :-)
    if get_settings("verbose"):
        print "Hello verbose Word !"
    else:
        print "Hello Word !"

if __name__ == '__main__':
    main()</pre>


<p>Et la même chose en <a href="http://vrac.biologeek.com/template_python.txt">fichier texte</a> si vous souhaitez l'utiliser.</p>


<p><strong>[edit]</strong>&nbsp;: <del>J'ai encore perdu une occasion de me taire</del> Je suis heureux d'avoir appris l'existence d'un nouveau module, effectivement <strong>optparse</strong> permet de parser les arguments en ligne de commande très facilement du coup mon template ne sert plus à rien ;-)</p>


<p>Voila ce que ce même template donnerait avec l'utilisation de ce module&nbsp;:</p>


<pre>#!/usr/bin/python
# -*- coding: iso-8859-1 -*-

"""
Explain what program do.
"""

import os
import sys
from optparse import OptionParser

def main():
    """ Main function, deals with arguments and launch program"""
    # Usual verifications and warnings
    if not sys.argv[1:]:
        sys.stdout.write("Sorry: you must specify at least an argument
")
        sys.stdout.write("More help avalaible with -h or --help option
")
        sys.exit(0)
    
    parser = OptionParser()
    parser.add_option("-v", "--verbose", action="store_true",
        help="Write output informations (not only errors).",
        default=False)
    
    parser.add_option("-f", "--file", help="Create a xxx file.")
    
    (options, args) = parser.parse_args() 
    
    # THE program :-)
    if options.verbose:
        print "Hello verbose Word !"
    else:
        print "Hello Word !"

if __name__ == '__main__':
    main()</pre>


<p>Simple, concis, bref à utiliser. <a href="http://www.la-grange.net/2003/10/29.html#python">Karl en parlait déjà</a> il y a plus de deux ans...</p>
