it-swarm.com.de

So übergeben Sie mehrere Argumentlisten an @ click.option

Ich möchte mit dieser Art von Parametern ein Python-Skript über die Befehlszeile aufrufen (Liste kann eine beliebige Größe haben, z. B. mit 3):

python test.py --option1 ["o11", "o12", "o13"] --option2 ["o21", "o22", "o23"]

mit klick. In den Dokumenten wird nirgendwo angegeben, dass wir eine Liste als Parameter für @ click.option verwenden können.

Und wenn ich das versuche:

#!/usr/bin/env python
import click

@click.command(context_settings=dict(help_option_names=['-h', '--help']))
@click.option('--option', default=[])
def do_stuff(option):

    return

# do stuff
if __== '__main__':
    do_stuff()

in meinem test.py, indem Sie es von der Kommandozeile aus aufrufen:

python test.py --option ["some option", "some option 2"]

Ich bekomme einen Fehler:

Fehler: unerwartetes zusätzliches Argument erhalten (einige Option 2])

Ich kann variadische Argumente nicht wirklich verwenden, da nur 1 variadische Argumente pro Befehl zulässig sind ( http://click.pocoo.org/5/arguments/#variadic-arguments ).

Wenn also jemand auf die richtige Richtung weist (vorzugsweise mit Klick), wäre das sehr zu begrüßen.

7
downstroy

Sie können einen Klick dazu zwingen, mehrere Listenargumente zu übernehmen, wenn die Listen als String-Literale von Python-Listen formatiert werden, indem Sie eine benutzerdefinierte Optionsklasse wie folgt verwenden:

Benutzerdefinierte Klasse:

import click
import ast

class PythonLiteralOption(click.Option):

    def type_cast_value(self, ctx, value):
        try:
            return ast.literal_eval(value)
        except:
            raise click.BadParameter(value)

Diese Klasse verwendet das Python-Modul Abstract Syntax Tree , um den Parameter als Python-Literal zu analysieren.

Benutzerdefinierte Klassenverwendung:

Um die benutzerdefinierte Klasse zu verwenden, übergeben Sie den Parameter cls an @click.option() decorator wie folgt:

@click.option('--option1', cls=PythonLiteralOption, default=[])

Wie funktioniert das?

Dies funktioniert, weil click ein gut gestaltetes OO Framework ist. Der Dekorator @click.option() instanziiert normalerweise ein click.Option-Objekt, lässt dieses Verhalten jedoch mit dem Parameter cls außer Kraft. Es ist also relativ einfach, von click.Option in unserer eigenen Klasse zu erben und die gewünschten Methoden zu überfahren.

In diesem Fall überfahren Sie click.Option.type_cast_value() und rufen dann ast.literal_eval() auf, um die Liste zu analysieren.

Testcode:

@click.command(context_settings=dict(help_option_names=['-h', '--help']))
@click.option('--option1', cls=PythonLiteralOption, default=[])
@click.option('--option2', cls=PythonLiteralOption, default=[])
def cli(option1, option2):
    click.echo("Option 1, type: {}  value: {}".format(
        type(option1), option1))
    click.echo("Option 2, type: {}  value: {}".format(
        type(option2), option2))

# do stuff
if __== '__main__':
    import shlex
    cli(shlex.split(
        '''--option1 '["o11", "o12", "o13"]' 
        --option2 '["o21", "o22", "o23"]' '''))

Testergebnisse:

Option 1, type: <type 'list'>  value: ['o11', 'o12', 'o13']
Option 2, type: <type 'list'>  value: ['o21', 'o22', 'o23']
7
Stephen Rauch

Folgendes kann ein einfacheres Hack-Update sein:

#!/usr/bin/env python
import click
import json

@click.command(context_settings=dict(help_option_names=['-h', '--help']))
@click.option('--option', help='Whatever')
def do_stuff(option):
    try:
        option = json.loads(option)    
    except ValueError:
        pass

# do stuff
if __== '__main__':
    do_stuff()

Dies kann Ihnen helfen, 'option' als list oder str zu verwenden.

1
Murphy

@ Murphys "easy hack" hat fast für mich funktioniert, aber die Sache ist, dass option eine string sein wird, es sei denn, Sie zitieren die Optionen einzeln.

#!/usr/bin/env python
import click
import json

@click.command(context_settings=dict(help_option_names=['-h', '--help']))
@click.option('--option', help='Whatever')
def do_stuff(option):
    try:
        option = json.loads(option)
        # option = str(option)  # this also works
    except ValueError:
        pass

    option = option[1:-1]  # trim '[' and ']'

    options = option.split(',')

    for i, value in enumerate(options):
        # catch integers
        try:
            int(value)
        except ValueError:
            options[i] = value
        else:
            options[i] = int(value)

    # Here use options as you need

# do stuff
if __== '__main__':
    do_stuff()

Sie könnten andere Typen fangen

Um es zu verwenden, schließen Sie die Liste in Anführungszeichen ein:

python test.py --option "[o11, o12, o13]"

Oder Sie können Anführungszeichen vermeiden, indem Sie keine Leerzeichen eingeben:

python test.py --option [o11,o12,o13]
0