Is there an idiomatic way, using the Python Click library, to create a command where one option depends on a value set by a previous option?
A concrete example (my use case) would be that a command takes an option of type click.File
as input, but also an encoding option which specifies the encoding of the input stream:
import click
@click.command()
@click.option("--encoding", type=str, default="utf-8")
@click.option("--input",
type=click.File("r", encoding="CAN I SET THIS DYNAMICALLY BASED ON --encoding?"))
def cli(encoding, input):
pass
I guess it would have to involve some kind of deferred evaluation using a callable, but I'm not sure if it's even possible given the current Click API.
I've figured out I can do something along the following lines:
import click
@click.command()
@click.pass_context
@click.option("--encoding", type=str, default="utf-8")
@click.option("--input", type=str, default="-")
def cli(ctx, encoding, input):
input = click.File("r", encoding=encoding)(input, ctx=ctx)
But it somehow feels less readable / maintainable to decouple the option decorator from the semantically correct type constraint that applies to it, and put str
in there instead as a dummy. So if there's a way to keep these two together, please enlighten me.
A proposed workaround:
I guess I could use the click.File
type twice, making it lazy in the decorator so that the file isn't actually left opened, the first time around:
@click.option("--input", type=click.File("r", lazy=True), default="-")
This feels semantically more satisfying, but also redundant.
encoding_option_name
as a parameter to__init__()
. I think it would look cleaner and more in line with how stock Click ParamTypes work to havetype=CustomFile("r")
rather thantype=encoded_file('encoding')("r")
. I'll submit an edit :) – Matsuyama