2012-09-03 18 views
6

Estoy usando la biblioteca de Python, Fabric, para realizar tareas de mantenimiento remoto del servidor. Fabric automáticamente emite todas las respuestas a comandos remotos y locales a menos que ajuste el comando en un par con instrucciones. Como tal, en una máquina local,¿Cuál es la forma pitónica de ajustar varias funciones de la misma manera con las declaraciones

with settings(warn_only='true'): 
    with hide('running', 'stdout', 'stderr', 'warnings'): 
     output = local("uname -a", True) 

o como esto en una máquina remota:

with settings(warn_only='true'): 
    with hide('running', 'stdout', 'stderr', 'warnings'): 
     output = run("uname -a") 

Estoy escribiendo una tarea larga y compleja y me encuentro repitiendo los dos con declaraciones una y otra vez . Quiero escribir una función llamada _mute() para evitar esa repetición. Se me dejaría hacer algo como esto:

def _mute(fabric_cmd, args): 
    with settings(warn_only='true'): 
     with hide('running', 'stdout', 'stderr', 'warnings'): 
      output = fabric_cmd(args) 
    return output 

def some_remote_task(): 
    # Run a remote task silently 
    _mute(remote, 'uname -a') 

def some_local_task(): 
    # Run a local task silently 
    _mute(local, 'uname -a', True) 

He mirado en algunas soluciones y saber que "eval" podría hacer esto por mí. Pero cada página que leo sobre eval sugiere que casi siempre es una mala idea debido a problemas de seguridad. Analicé parciales, pero no pude encontrar la manera de presentar un argumento en mi función de silencio. Supongo que hay un concepto de Python de nivel superior que me falta aquí. ¿Cuál es la manera pitónica de hacer esto? Gracias por cualquier dirección que pueda proporcionar.

Respuesta

11

La mejor solución sería que usted construya su propio administrador de contexto; con mucho, la forma más fácil sería utilizar el contextlib.contextmanager decorator:

from contextlib import contextmanager 

@contextmanager 
def _mute(): 
    with settings(warn_only='true'): 
     with hide('running', 'stdout', 'stderr', 'warnings'): 
      yield 

A continuación, utilice _mute como un gestor de contexto:

def some_remote_task(): 
    # Run a remote task silently 
    with _mute(): 
     output = remote("uname -a") 

Esto es mucho más compacto y fácil de leer que tener que volver a escribir el contexto de dos grandes líneas de administrador y tiene la ventaja añadida que ahora puede ejecutar múltiples comandos en ese mismo contexto.

En cuanto a su pregunta; se puede aplicar fácilmente argumentos arbitrarios a una función dada mediante la sintaxis *args:

def _mute(fabric_cmd, *args): 
    with settings(warn_only='true'): 
     with hide('running', 'stdout', 'stderr', 'warnings'): 
      return fabric_cmd(*args) 

def some_remote_task(): 
    # Run a remote task silently 
    output = _mute(remote, 'uname -a') 

Ver *args and **kwargs? para más información sobre el argumento arbitrario *args listas de trucos.

+0

Gracias @contextmanager decorator funcionó a la perfección. Aprecio que me guíes hacia los documentos para aquellos, así como la sintaxis * args. –

Cuestiones relacionadas