python boolean fabric

python - Cómo pasar el argumento bool al comando fabric



boolean (10)

Como se menciona en los documentos de tejido , todos los argumentos terminan como cadenas. Lo más sencillo de hacer aquí sería verificar el argumento:

def myfunc(arg1, arg2): arg1 = (arg1 == ''True'')

Los paréntesis no son necesarios, pero ayudan con la legibilidad.

Edit : Aparentemente no probé mi respuesta anterior; actualizado. (Dos años después.)

Actualmente estoy usando fab -f check_remote.py func:"arg1","arg2"... para ejecutar el control remoto fab.

Ahora necesito enviar un argumento bool, pero True / False se convierte en una cadena arg, ¿cómo configurarlo como tipo bool?


En mis fabfiles acabo de hacer:

TRUTHY = [True, 1, ''1'', ''true'', ''t'', ''yes'', ''y''] @task def my_task(my_arg=True): if my_arg in TRUTHY: # do stuff else: # do other stuff

Por supuesto, esto significa que cualquier valor que no esté en la VERDAD es efectivamente False , pero hasta ahora no he necesitado nada más complicado.


Esta es una versión de trabajo basada en gist.github.com/mgedmin/f832eed2ac0f3ce31edf . A diferencia de la versión anterior, en realidad esto respeta todos los parámetros posibles de decorador y los alias de la tarea:

from functools import wraps from fabric import tasks def fix_boolean(f): true_values = ("yes", "true", "1") false_values = ("no", "false", "0") def fix_bool(value): if isinstance(value, basestring): if value.lower() in false_values: return False if value.lower() in true_values: return True return value @wraps(f) def wrapper(*args, **kwargs): args_ = [fix_bool(arg) for arg in args] kwargs_ = {k: fix_bool(v) for k,v in kwargs.iteritems()} return f(*args_, **kwargs_) return wrapper def task(*args, **kwargs): """ The fabric.decorators.task decorator which automatically converts command line task arguments to a boolean representation if applicable. :param args: :param kwargs: :return: wrapped """ invoked = bool(not args or kwargs) task_class = kwargs.pop("task_class", tasks.WrappedCallableTask) def wrapper(f): return task_class(fix_boolean(f), *args, **kwargs) return wrapper if invoked else wrapper(args[0])

Gist: https://gist.github.com/eltismerino/a8ec8584034c8a7d087e


Estoy usando esto:

from distutils.util import strtobool def func(arg1="default", arg2=False): if arg2: arg2 = bool(strtobool(arg2))

Hasta ahora funciona para mí. analizará los valores (ignorando el caso):

''y'', ''yes'', ''t'', ''true'', ''on'', ''1'' ''n'', ''no'', ''f'', ''false'', ''off'', ''0''

strtobool devuelve 0 o 1, por eso se necesita bool para convertir a True / False boolean.

Para completar, aquí está la strtobool de strtobool :

def strtobool (val): """Convert a string representation of truth to true (1) or false (0). True values are ''y'', ''yes'', ''t'', ''true'', ''on'', and ''1''; false values are ''n'', ''no'', ''f'', ''false'', ''off'', and ''0''. Raises ValueError if ''val'' is anything else. """ val = val.lower() if val in (''y'', ''yes'', ''t'', ''true'', ''on'', ''1''): return 1 elif val in (''n'', ''no'', ''f'', ''false'', ''off'', ''0''): return 0 else: raise ValueError("invalid truth value %r" % (val,))

Versión ligeramente mejor (gracias por los comentarios mVChr)

from distutils.util import strtobool def _prep_bool_arg(arg): return bool(strtobool(str(arg))) def func(arg1="default", arg2=False): arg2 = _prep_bool_arg(arg2)


He resuelto esto utilizando decoradores. Me gusta la flexibilidad y la experiencia que se obtiene al usar un decorador.

Aquí está la carne del código:

import ast from fabric import utils from fabric.api import task from functools import wraps def params(*types, **kwtypes): def decorator(function): @wraps(function) def wrapper(*args, **kwargs): new_args = () for index, arg in enumerate(args): new_args += __cast(arg, types[index]), for kwarg in kwargs: kwargs[kwarg] = __cast(kwargs[kwarg], kwtypes[kwarg]) return function(*new_args, **kwargs) return wrapper return decorator def __evaluate(arg): try: return ast.literal_eval(arg) except: return str(arg) def __cast(arg, arg_type): try: return arg_type(__evaluate(arg)) except: utils.abort("Unable to cast ''{}'' to {}".format(arg, arg_type))

Aquí está lo que parece usarlo en el código:

@task @params(int, bool, arg1=int, arg2=bool) def test(arg1, arg2): print type(arg1), arg1 print type(arg2), arg2

Esto es lo que parece llamarlo vía fab con buenos parámetros:

fab test:0.1,1 <type ''int''> 0 <type ''bool''> True fab test:5,arg2=False <type ''int''> 5 <type ''bool''> False fab test:arg1=0,arg2=false <type ''int''> 5 <type ''bool''> True

NOTA: En el último ejemplo, "falso" es Verdadero, este es el comportamiento esperado en Python, sin embargo, puede ser naturalmente contraintuitivo. Similar a pasar False como un int, se convertirá a 0 como int (False) == 0 en python

Esto es lo que parece llamarlo a través de fab con malos parámetros:

fab test:Test,False Fatal error: Unable to cast ''Test'' to <type ''int''> Aborting.


Las respuestas de Craig y Ari resultarán en un valor Verdadero si el usuario pasa "Falso" (la respuesta de Ari es más clara al respecto)

Si usa eval (), las cadenas "Verdadero" y "Falso" se evaluarán según sus valores booleanos correctos, pero si está usando valores predeterminados, deberá asegurarse de que sean cadenas y no booleanos.

def myfunc(arg1="True", arg2=False): arg1 = eval(arg1) arg2 = eval(arg2) #error



Si utiliza el patrón de forma coherente (''falso'', ''verdadero'' es booleano) en todas sus tareas, puede simplemente envolver la tarea de estructura y aplicarla en todos

Puede usar este paquete (escrito por mí): https://pypi.python.org/pypi/boolfab/

Aquí está (esencialmente) la fuente:

from fabric.api import task as _task def fix_boolean(f): def fix_bool(value): if isinstance(value, basestring): if value.lower() == ''false'': return False if value.lower() == ''true'': return True return value @wraps(f) def wrapper(*args, **kwargs): args_ = [fix_bool(arg) for arg in args] kwargs_ = {k: fix_bool(v) for k,v in kwargs.iteritems()} return f(*args_, **kwargs_) return wrapper def task(f): return _task(fix_boolean(f))

Para que se convierta en:

@task def my_task(flag_a, flag_b, flag_c) if flag_a: ....

sin contaminar cada tarea con args ''booleanizing''.


Una mejor manera sería usar ast.literal_eval :

from ast import literal_eval def my_task(flag): if isinstance(flag, basestring): # also supports calling from other tasks flag = literal_eval(flag)

Aunque esto no toma en cuenta valores como ''sí'' o ''no'', es un poco más limpio y seguro que eval ...


Yo usaría una función:

def booleanize(value): """Return value as a boolean.""" true_values = ("yes", "true", "1") false_values = ("no", "false", "0") if isinstance(value, bool): return value if value.lower() in true_values: return True elif value.lower() in false_values: return False raise TypeError("Cannot booleanize ambiguous value ''%s''" % value)

Luego en la tarea:

@task def mytask(arg): arg = booleanize(arg)