2009-08-28 12 views
5

Sto sviluppando uno script di gestione che esegue una grande quantità di lavoro tramite una pletora di opzioni della riga di comando. Le prime iterazioni dello script hanno utilizzato optparse per raccogliere l'input dell'utente, quindi basta scorrere la pagina, testare il valore di ciascuna opzione nell'ordine appropriato e, se necessario, eseguire l'azione. Ciò ha portato a una giungla di codice che è davvero difficile da leggere e mantenere.riga di comando arg parsing attraverso l'introspezione

Sto cercando qualcosa di meglio.

La mia speranza è di avere un sistema in cui posso scrivere le funzioni in modo python più o meno normale, e poi quando lo script viene eseguito, ho le opzioni (e il testo di aiuto) generate dalle mie funzioni, analizzate ed eseguite nel ordine appropriato. Inoltre, mi piacerebbe davvero essere in grado di costruire interfacce sub-comando django-stile, dove myscript.py install opere nettamente distinto dagli myscript.py remove (opzioni separate, aiuto, ecc)

ho trovato simon willison's optfunc e lo fa molto di questo, ma sembra mancare il segno: voglio scrivere ciascuna OPZIONE come una funzione, piuttosto che provare a comprimere l'intera serie di opzioni in una vasta serie di opzioni.

Immagino un'architettura che comprende un insieme di classi per le funzioni principali e ogni metodo definito della classe corrispondente a una particolare opzione nella riga di comando. Questa struttura offre il vantaggio di avere ciascuna opzione vicino al codice funzionale che modifica, facilitando la manutenzione. La cosa che non so proprio come trattare è l'ordinamento dei comandi, poiché l'ordinamento dei metodi di classe non è deterministico.

Prima di reinventare la ruota: ci sono altri bit di codice esistenti che si comportano in modo simile? Altre cose che sarebbero facili da modificare? Chiedere la domanda ha chiarito il mio modo di pensare su cosa sarebbe bello, ma il feedback sul perché questa è una pessima idea, o su come dovrebbe funzionare sarebbe il benvenuto.

risposta

4

Non perdere tempo con "introspezione".

Ogni "Comando" o "Opzione" è un oggetto con due serie di funzioni o attributi di metodo.

  1. Fornire informazioni di configurazione a optparse.

  2. Effettivamente il lavoro.

Ecco la superclasse per tutti i comandi

class Command(object): 
    name= "name" 
    def setup_opts(self, parser): 
     """Add any options to the parser that this command needs.""" 
     pass 
    def execute(self, context, options, args): 
     """Execute the command in some application context with some options and args.""" 
     raise NotImplemented 

Si crea sublcasses per Install e Remove ed ogni altro comando che vi serve.

L'applicazione complessiva è simile a questa.

commands = [ 
    Install(), 
    Remove(), 
] 
def main(): 
    parser= optparse.OptionParser() 
    for c in commands: 
     c.setup_opts(parser) 
    options, args = parser.parse() 
    command= None 
    for c in commands: 
     if c.name.startswith(args[0].lower()): 
      command= c 
      break 
    if command: 
     status= command.execute(context, options, args[1:]) 
    else: 
     logger.error("Command %r is unknown", args[0]) 
     status= 2 
    sys.exit(status) 
+0

Grazie, questo sembra un buon consiglio. –

+0

Questo è eccellente! –

0

La biblioteca WSGI werkzeug fornisce Management Script Utilities che può fare quello che vuoi, o almeno dare un suggerimento come fare l'introspezione da soli.

from werkzeug import script 

# actions go here 
def action_test(): 
    "sample with no args" 
    pass 

def action_foo(name=2, value="test"): 
    "do some foo" 
    pass 

if __name__ == '__main__': 
    script.run() 

che genererà il seguente messaggio di aiuto:

$ python /tmp/test.py --help 
usage: test.py <action> [<options>] 
     test.py --help 

actions: 
    foo: 
    do some foo 

    --name      integer 2 
    --value      string test 

    test: 
    sample with no args 

un'azione è una funzione nello stesso modulo che inizia con "action_", che prende un certo numero di argomenti in cui ogni argomento è un default. Il tipo del valore predefinito specifica il tipo dell'argomento.

Gli argomenti possono quindi essere passati per posizione o utilizzando --name = valore dalla shell.

Problemi correlati