J'ai cette ligne de code qui devrait récupérer tous les noms de fichiers passés à mon script Python:
@click.argument("logs", nargs=-1, type=click.File('r'), required=1, default="-")
Lorsqu'aucun nom de fichier n'est passé, je veux par défaut -
, c'est-à-dire l'entrée standard. Donc, si j'essaye:
@click.argument("logs", nargs=-1, type=click.File('r'), required=1)
le clic devient malheureux et génère cette erreur:
TypeError: nargs = -1 en combinaison avec une valeur par défaut n'est pas pris en charge.
Y a-t-il une solution de contournement pour cela? J'ai essayé de définir nargs = 0
mais cela génère une erreur différente:
IndexError: index de tuple hors de portée
3 Réponses :
Le code suivant:
$ myhello -l foo.log -l bar.log -l baz.log foo.log bar.log baz.log $ myhello -
Produira ce qui suit:
import click @click.command() @click.option('--logs', '-l', multiple=True, default='-') def cli(logs): click.echo('\n'.join(logs))
Donc, si vous pouviez simplement appeler votre programme différemment avec des paramètres répétés à la place, ce serait la solution de contournement que vous recherchez.
Cela change la sémantique de ce que l'OP voulait, donc oui, ce serait juste une solution de contournement qui ne résout pas le problème réel.
dans ce cas, je voudrais simplement ajouter un simple wrapper autour de ce qui précède dans bash.
Puisque click
avait explicitement déclaré avoir désactivé cette fonctionnalité particulière requise par la question, comme indiqué sur ce problème sur leur projet, une solution de contournement sera nécessaire et qui peut être facilement implémentée dans le cadre de la fonction Python (au lieu d'une pile supplémentaire sur le code bash comme suggéré par le commentaire sur le
La solution de contournement consiste simplement à supprimer l'argument requis et à gérer les journaux manquants à l'aide d'une instruction (similaire à ce que ce commit a fait qui faisait référence au problème lié):
$ python fail.py (<_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8'>,) $ python fail.py - (<_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8'>,) $ python fail.py foo bar (<_io.TextIOWrapper name='foo' mode='r' encoding='UTF-8'>, <_io.TextIOWrapper name='bar' mode='r' encoding='UTF-8'>)
Exemple d'exécution
import sys import click @click.command() @click.argument("logs", nargs=-1, type=click.File('r')) def main(logs): if not logs: logs = (sys.stdin,) print(logs) # do stuff with logs if __name__ == '__main__': main()
p>
Pour définir par défaut stdin
pour une liste de fichiers potentiellement vide, vous pouvez définir une classe d'arguments personnalisée telle que:
@click.command() @click.argument("logs", cls=FilesDefaultToStdin) def main(logs): ...
Définir ce comportement en tant que classe permet une réutilisation facile.
class FilesDefaultToStdin(click.Argument): def __init__(self, *args, **kwargs): kwargs['nargs'] = -1 kwargs['type'] = click.File('r') super().__init__(*args, **kwargs) def full_process_value(self, ctx, value): return super().process_value(ctx, value or ('-', ))
Cela fonctionne car Click est un framework OO bien conçu. Le décorateur @ click.argument ()
instancie généralement un objet click.Argument
mais permet à ce comportement d'être remplacé par le paramètre cls
. Il est donc relativement facile d'hériter de click.Argument
dans notre propre classe et de remplacer les méthodes souhaitées.
Dans ce cas, nous remplaçons click. Argument.full_process_value ()
. Dans notre full_process_value ()
, nous recherchons une liste d'arguments vide, et si elle est vide, nous ajoutons l'argument -
(stdin) à la liste.
De plus, nous attribuons automatiquement les arguments nargs = -1
et type = click.File ('r')
.
Pour ce que ça vaut, problème sur github (c'est-à-dire qu'ils ne l'ont pas résolu, ils l'ont interdit explicitement).