Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Support Capturing Unspecified Options with **kwargs #163

Closed
n2cholas opened this issue Sep 6, 2020 · 6 comments
Closed

[FEATURE] Support Capturing Unspecified Options with **kwargs #163

n2cholas opened this issue Sep 6, 2020 · 6 comments
Labels
feature New feature, enhancement or request

Comments

@n2cholas
Copy link

n2cholas commented Sep 6, 2020

Is your feature request related to a problem

I would like to capture arbitrary options passed by the user that are not specified in the function siguature. When using argparse, I could do args, unknown_args = parser.parse_known_args() and unknown_args would contain the unspecified options.

The solution you would like

To me, it makes sense to capture unspecified options in the **kwargs dict. For example,

# main.py
import typer

def main(name: str, **kwargs):
    print(kwargs)

if __name__ == "__main__":
    typer.run(main)

Here's how you use it:

python main.py Bob
> {}

python main.py Bob --height 170
> {'height': '170'}

python main.py Bob --last-name Foo --age 25
> {'last-name': 'Foo', 'age': '25'}

Since we don't specify the type of any of the **kwargs, they are captured as strings.

Describe alternatives you've considered

  1. Currently, unspecified options will raise an error. Instead, you could give users the ability to ignore these errors, so they can access the rest of the arguments via sys.argv. This is inelegant, though.
  2. You could also allow users to use *args to capture unspecified options. However, I don't know how to implement this robustly, especially when it's possible for existing options to be a list.
  3. There is a hacky workaround that is currently possible to capture unspecified options:
# main.py
import typer
from typing import List

def main(name: str, kwargs: List[str], color: str = 'blue'):
    print(kwargs)

if __name__ == "__main__":
    typer.run(main)
python main.py Bob height 170
> ('height', '170')

python test.py Bob last-name Foo age 25 --color pink
> ('last-name', 'Foo', 'age', '25')

This has some drawbacks:

  • different syntax for specified and unspecified args
  • can't support sequences for options
  • must always have at least one unspecified argument (otherwise you get an error)

Additional context

The release notes for 0.3.0 talk about functionality that seems relevant to this, but I was not able to find documentation for it (says it was merged in #120 by @teymour-aldridge ).

Thanks in advance!

@n2cholas n2cholas added the feature New feature, enhancement or request label Sep 6, 2020
@jessekrubin
Copy link

This would be super super nice.

@PetrochukM
Copy link

PetrochukM commented Oct 1, 2020

Actually, I found support in typer for extra args:
https://typer.tiangolo.com/tutorial/commands/context/#configuring-the-context

@n2cholas
Copy link
Author

n2cholas commented Oct 2, 2020

That's perfect, thanks!

@n2cholas n2cholas closed this as completed Oct 2, 2020
@tiangolo
Copy link
Member

tiangolo commented Nov 9, 2022

Thanks for the help @PetrochukM ! 🍰

And thanks for closing the issue @n2cholas

Sorry for the long delay! 🙈 I wanted to personally address each issue/PR and they piled up through time, but now I'm checking each one in order.

@mgamble
Copy link

mgamble commented Jan 24, 2024

As nice as this is, the solution pointed to by @PetrochukM is not quite perfect for my hopes and dreams. The drawback is the required use of typer.Context. I'm trying to write a typer application where the underlying functions are still usable within python. Needing to have the first argument be ctx: typer.Context in order to accept unspecified arguments is a big stumbling block toward that goal. Support for something like **kwargs: Annotated[dict[str,str], typer.Option()] = {} would be ideal. Baring that, I'll need to wrap the functions that use **kwargs into other functions that can use the ctx trick. That is a lot of copy/paste for complicated functions with many arguments, which seems a shame.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature, enhancement or request
Projects
None yet
Development

No branches or pull requests

5 participants