es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Cómo invocar click.command con argumentos excluidos

Tengo un comando envoltorio que invoca cierto comando en un bucle con período (valor entero, en minutos).

El comando envoltorio no quiere describir los argumentos del comando que se va a envolver.

@click.group(name="wrapper-example")
def wrapper_cli():
    pass

@wrapper_cli.command("command")
@click.option("--path", type=str, help="ejemplo de argumento del comando")
def command(path):
    click.echo(path)

@wrapper_cli.command(
    "run",
    context_settings=dict(
        ignore_unknown_options=True,
        allow_extra_args=True,
    ),
)
@click.option("--period", type=int, help="minutos")
@click.pass_context
def run(ctx: click.Context, period):
    # no se implementa el bucle para un ejemplo claro
    ctx.forward(command)

En este ejemplo con forward() obtendré un error, porque command() no conoce el argumento period.

Con el método invoke(), tengo que analizar manualmente los argumentos de click.Context.args del envoltorio, que es una lista que contiene argumentos sin procesar y no reconocidos. [“–path”, “path/”]

click.Context.args: List[str]

y pasarla de la siguiente manera:

ctx.invoke(command, **kwargs)

¿Cómo podría excluir algunas variables del contexto para reenviar el comando sin el argumento de período?
¿O cómo podría analizar “click.Context.args: List[str]” de manera clara, que solo contiene valores de argumentos adicionales no definidos para el envoltorio, y luego usar Context.invoke()?

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Desafortunadamente, no hay una forma incorporada de excluir variables específicas del objeto click.Context. Sin embargo, puedes crear manualmente un nuevo diccionario de argumentos para pasar al comando filtrando los argumentos que no deseas pasar.

    Aquí tienes un ejemplo de cómo podrías modificar el comando run para excluir el argumento period y crear un nuevo diccionario de argumentos para pasar a la función command:

    @wrapper_cli.command(
        "run",
        context_settings=dict(
            ignore_unknown_options=True,
            allow_extra_args=True,
        ),
    )
    @click.option("--period", type=int, help="minutes")
    @click.pass_context
    def run(ctx: click.Context, period):
        # excluir el argumento period del diccionario de args
        args_dict = {k:v for k,v in ctx.params.items() if k != "period"}
    
        # crear una nueva lista de argumentos para pasar al comando
        command_args = [arg for arg in ctx.args if arg != f"--period={period}"]
    
        # invocar el comando con los nuevos argumentos
        ctx.invoke(command, *command_args, **args_dict)
    

    Alternativamente, puedes analizar manualmente la lista Context.args y crear un nuevo diccionario de argumentos para pasar al comando. Aquí tienes un ejemplo de cómo podrías modificar el comando run para hacer esto:

    @wrapper_cli.command(
        "run",
        context_settings=dict(
            ignore_unknown_options=True,
            allow_extra_args=True,
        ),
    )
    @click.option("--period", type=int, help="minutes")
    @click.pass_context
    def run(ctx: click.Context, period):
        # filtrar los argumentos reconocidos de la lista args
        extra_args = [arg for arg in ctx.args if arg.startswith("--") and not arg.startswith("--period")]
    
        # parsear los argumentos no reconocidos en un diccionario
        extra_args_dict = {}
        for arg in extra_args:
            key, value = arg.split("=")
            extra_args_dict[key[2:]] = value
    
        # invocar el comando con los nuevos argumentos
        ctx.invoke(command, **extra_args_dict)
    

Comments are closed.