2009-08-28 11 views
5

Estoy desarrollando un script de gestión que realiza una gran cantidad de trabajo a través de una gran cantidad de opciones de línea de comandos. Las primeras iteraciones del script han usado optparse para recopilar información del usuario y luego simplemente ejecutar la página, probar el valor de cada opción en el orden apropiado y realizar la acción si es necesario. Esto ha resultado en una jungla de código que es muy difícil de leer y mantener.línea de comandos análisis arg a través de la introspección

Estoy buscando algo mejor.

Mi esperanza es tener un sistema donde pueda escribir funciones de manera más o menos normal de python, y luego cuando se ejecute el script, tener opciones (y texto de ayuda) generadas desde mis funciones, analizadas y ejecutadas en el orden apropiado Además, realmente me gustaría ser capaz de construir interfaces de sub-órdenes al estilo de Django, donde myscript.py install obras completamente separado de myscript.py remove (opciones separadas, ayuda, etc.)

he encontrado simon willison's optfunc y lo hace mucho de esto, pero parece pasar por alto la marca: quiero escribir cada OPCIÓN como una función, en lugar de tratar de comprimir toda la opción configurada en una enorme cadena de opciones.

Imagino una arquitectura que implica un conjunto de clases para funciones principales, y cada método definido de la clase correspondiente a una opción particular en la línea de comando. Esta estructura proporciona la ventaja de que cada opción resida cerca del código funcional que modifica, facilitando el mantenimiento. Lo que no sé exactamente es cómo ordenar los comandos, ya que el orden de los métodos de clase no es determinista.

Antes de reinventar la rueda: ¿Hay otros bits de código que se comporten de manera similar? ¿Otras cosas que serían fáciles de modificar? Hacer la pregunta ha aclarado mi propio pensamiento sobre lo que sería agradable, pero la retroalimentación sobre por qué esta es una idea terrible, o cómo debería funcionar, sería bienvenida.

Respuesta

4

No pierda el tiempo en "introspección".

Cada "Comando" u "Opción" es un objeto con dos conjuntos de funciones de método o atributos.

  1. Proporcione la información de configuración para optparse.

  2. En realidad, hacer el trabajo.

Aquí es la superclase de todos los comandos

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 

usted crea sublcasses para Install y Remove y todos los demás comandos que necesita.

Su aplicación general se parece a esto.

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

Gracias, parece un buen consejo. –

+0

¡Esto es excelente! –

0

La biblioteca WSGI werkzeug proporciona Management Script Utilities que puede hacer lo que quiere, o al menos a dar una pista de cómo hacer la introspección mismo.

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() 

que generará el siguiente mensaje de ayuda:

$ 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 

Una acción es una función en el mismo módulo que comienza con "action_", que tiene una serie de argumentos donde cada argumento tiene un defecto. El tipo del valor predeterminado especifica el tipo del argumento.

Los argumentos se pueden pasar por posición o utilizando --name = value desde el shell.

Cuestiones relacionadas