Open robinbowes opened 1 year ago
Hi @robinbowes we're just trying to combine typer
and merge_args
too, and I'm not sure I understand your implementation. My test common_opts()
function is just simple like this:
def base_function(
arg2: int,
arg3: str = typer.Option("default arg3"),
version: Optional[bool] = typer.Option(
None, "--version"
)
):
if version:
print("version")
print("arg2:", arg2)
print("arg3:", arg3)
and then this works fine, with --version
working as you would expect as a switch:
@app.command()
@merge_args(base_function)
def test_three(arg1: str, *args, **kwargs):
print("arg1:", arg1)
return base_function(*args, **kwargs)
@joanise I'm not sure I understand it now, after so much hacking around 🤪
I've currently reverted to defining all the common options separately and simply adding the options explicitly to every command, eg:
options = SimpleNamespace(
log_level=typer.Option("ERROR", callback=set_log_level, is_eager=True),
sender=typer.Option(None),
stuff=typer.Option(()),
version=typer.Option(None,"--version",callback=show_version, is_eager=True),
)
@app.command()
def create(
ctx: typer.Context,
log_level: LogLevel = common.options.log_level,
sender: str = common.options.sender,
stuff: Optional[List[str]] = common.options.target,
version: Optional[bool] = common.options.version,
):
print("create stuff here")
@app.command()
def delete(
ctx: typer.Context,
log_level: LogLevel = common.options.log_level,
sender: str = common.options.sender,
stuff: Optional[List[str]] = common.options.target,
version: Optional[bool] = common.options.version,
):
print("delete stuff here")
I'm afraid I don't know much about typer and its internals, so I might not be able to help.
If you compare inspect.signature() of a hand-written function, and then of a function merge_args
with the same meaning, are there any differences? Perhaps the default values or annotations are somewhere typer
doesn’t expect them?
@robinbowes This is how my colleague ended up solving it, defining both a base_function()
and a dummy base_function_interface()
for the purpose of using with merge_args. It works like a charm.
def base_function(arg1, arg2, arg3):
print("arg1", arg1)
print("arg2:", arg2)
print("arg3:", arg3)
def base_function_interface(arg2: int = typer.Option(1), arg3: str = typer.Option("str")):
"""Base Function
Args:
arg2 (int, optional): _description_. Defaults to typer.Option(1).
arg3 (str, optional): _description_. Defaults to typer.Option("str").
"""
pass
@app.command()
@merge_args(base_function_interface)
def test_three(arg1: str = typer.Option("arg3 default value"), *args, **kwargs):
"""Test Three
Args:
arg1 (str, optional): _description_. Defaults to typer.Option("arg3 default value").
Returns:
_type_: _description_
"""
return base_function(arg1, kwargs['arg2'], kwargs['arg3'])
@Kwpolska Well, even if you don't know much about typer, you did us an awesome service with this merge_args
decorator. I was doing research into merging two signatures and it's really quite complex! typer builds the CLI by inspecting the signature of the function, so by giving us a tool to merge signature, you're effectively giving us a tool to provide base options in one function, and additional options in the command function.
So thank you very much for this module!
Thanks both. I shall review your suggestions and see if I can figure things out.
R.
Hi,
You might also want to have a look here: https://github.com/tiangolo/typer/issues/153#issuecomment-1922568794
I do not use merge_args
but inspiration came by looking at merge_args
's source code (needed a helper function to merge signatures, done differently though).
Regards.
Hi,
I'm using merge_args to add common options to several Typer commands. It seems to work OK for options with an argument (eg.
--author Kwpolska
) but when I try to add options with no argument (eg.--version
) the merged option gets converted to require an argument.I've created this gist showing what I mean: https://gist.github.com/robinbowes/fa815f2c0576fc6c76409ff3ba31b407
Any idea why the the version arg gets mangled when merged?