2009-12-10 2 views
14

J'utilise optparse depuis un moment et j'aimerais ajouter la possibilité de charger les arguments à partir d'un fichier de configuration. Jusqu'à présent, le meilleur que je puisse penser est un script batch wrapper avec les arguments codés en dur ... semble maladroit.Utilisation d'un fichier pour stocker les arguments d'optparse

Quelle est la manière la plus élégante de faire ceci?

Répondre

22

Je suis d'accord avec l'idée de S. Lott d'utiliser un fichier de configuration, mais je vous recommande d'utiliser le module intégré ConfigParser (ConfigParser dans la version 3.0) pour l'analyser, plutôt qu'une solution brassée maison.

Voici un bref script qui illustre ConfigParser et optparse en action.

import ConfigParser 
from optparse import OptionParser 

CONFIG_FILENAME = 'defaults.cfg' 

def main(): 
    config = ConfigParser.ConfigParser() 
    config.read(CONFIG_FILENAME) 

    parser = OptionParser() 
    parser.add_option("-l", 
         "--language", 
         dest="language", 
         help="The UI language", 
         default=config.get("Localization", "language")) 
    parser.add_option("-f", 
         "--flag", 
         dest="flag", 
         help="The country flag", 
         default=config.get("Localization", "flag")) 

    print parser.parse_args() 

if __name__ == "__main__": 
    main() 

Sortie:

(<Values at 0x2182c88: {'flag': 'japan.png', 'language': 'Japanese'}>, []) 

Run avec "parser.py --language=French "

(<Values at 0x2215c60: {'flag': 'japan.png', 'language': 'French'}>, []) 

Aide est construit en Run avec" parser.py --help":

Usage: parser.py [options] 

Options: 
    -h, --help   show this help message and exit 
    -l LANGUAGE, --language=LANGUAGE 
         The UI language 
    -f FLAG, --flag=FLAG The country flag 

Le fichier de configuration:

[Localization] 
language=Japanese 
flag=japan.png 
3

Voilà à quoi sert la fonction set_defaults. http://docs.python.org/library/optparse.html#optparse.OptionParser.set_defaults

Créez un fichier qui est le dictionnaire des valeurs par défaut.

{ 'arg1': 'this', 
'arg2': 'that' 
} 

ensuite lire ce fichier, eval pour convertir le texte à un dictionnaire, et fournir ce dictionnaire que les arguments à set_defaults.

Si vous êtes vraiment inquiet au sujet de eval, alors utilisez la notation JSON (ou YAML) pour ce fichier. Ou vous pouvez même en faire un fichier .INI et utiliser configparser pour obtenir vos valeurs par défaut.

Ou vous pouvez utiliser une simple liste d'instructions d'affectation et exec.

Fichier de configuration.

arg1 = 'this' 
arg2 = 'that' 

Lecture du fichier de configuration.

defaults= {} 
with open('defaults.py','r') as config 
    exec config in {}, defaults 
+0

Il n'y a aucune raison d'utiliser eval ici - vous pouvez simplement utiliser le maréchal. –

+1

@Nick Bastin: Eval is not Evil, seulement les utilisateurs finaux sociopathes qui essayent toujours de pirater l'application en exploitant l'utilisation d'eval. –

+0

Wagging votre doigt à un attaquant en profitant d'une faille dans votre armure ni élimine la fente ou arrête l'attaque ... :) –

7

Vous pouvez utiliser le module argparse pour que:

>>> open('args.txt', 'w').write('-f\nbar') 
>>> parser = argparse.ArgumentParser(fromfile_prefix_chars='@') 
>>> parser.add_argument('-f') 
>>> parser.parse_args(['-f', 'foo', '@args.txt']) 
Namespace(f='bar') 

Il pourrait être inclus dans stdlib, voir pep 389.

+4

PEP 389 a été approuvé et 'argparse' fait déjà partie de Python 2.7 – sorin

4

J'ai eu un problème similaire, mais je voulais également spécifier le fichier de configuration en tant qu'argument. Inspiré par la réponse de S. Lott, j'ai trouvé le code suivant.

Exemple session de terminal:

$ python defaultconf.py # use hard-coded defaults 
False 
$ python defaultconf.py --verbose # verbose on command line 
True 
$ python defaultconf.py --loadconfig blah # load config with 'verbose':True 
True 
$ python defaultconf.py --loadconfig blah --quiet # Override configured value 
False

code:

#!/usr/bin/env python2.6 
import optparse 

def getParser(defaults): 
    """Create and return an OptionParser instance, with supplied defaults 
    """ 
    o = optparse.OptionParser() 
    o.set_defaults(**defaults) 
    o.add_option("--verbose", dest = "verbose", action="store_true") 
    o.add_option("--quiet", dest = "verbose", action="store_false") 

    o.add_option("--loadconfig", dest = "loadconfig") 

    return o 


def main(): 
    # Hard coded defaults (including non-command-line-argument options) 
    my_defaults = {'verbose': False, 'config_only_variable': 42} 

    # Initially parse arguments 
    opts, args = getParser(my_defaults).parse_args() 

    if opts.loadconfig is not None: 
     # Load config from disk, update the defaults dictionary, and reparse 
     # Could use ConfigParser, simplejson, yaml etc. 

     config_file_values = {'verbose': True} # the dict loaded from disk 

     my_defaults.update(config_file_values) 
     opts, args = getParser(my_defaults).parse_args() 

    print opts.verbose 

if __name__ == '__main__': 
    main() 

Une mise en œuvre pratique se trouve sur Github: The defaults dictionary, the argument parser et the main function

+0

C'est génial. Je l'ai étendu pour montrer également les valeurs par défaut du fichier de configuration dans --help: –

2

Lire les arguments dans le même format de ligne de commande à partir d'un fichier par exemple @ commandes, puis utilisez votre analyseur d'origine pour les analyser.

options, args = parser.parse_args() 

if args[0][0] == '@': # script.py @optfile 
    with open(args[0][1:]) as f: 
     fa = [l.strip() for l in f] 
    fa = fa + args[1:] # put back any other positional arguments 
    # Use your original parser to parse the new options 
    options, args = parser.parse_args(args=fa, values=options) 
0

J'ai construit beaucoup de scripts avec des drapeaux et des options ces derniers temps, et je suis venu avec la solution décrite here. Fondamentalement, j'exemple un optionparser avec un drapeau spécial qui dit d'essayer de charger les options d'un fichier, donc vous pouvez utiliser normalement votre script en spécifiant des options depuis la ligne de commande ou les fournir (ou un ensemble) depuis un fichier.

Mise à jour: j'ai code partagé sur GitHub

Questions connexes