[QUESTION] How to handle mutually exclusive options

See original GitHub issue

First check

  • I used the GitHub search to find a similar issue and didn’t find it.
  • I searched the Typer documentation, with the integrated search.
  • I already searched in Google “How to X in Typer” and didn’t find any information.
  • I already searched in Google “How to X in Click” and didn’t find any information.

Description

I often find myself making mutually exclusive options. I’m used to argparse, which has nice support for that. What is the best way to do this in Typer?

I.e. how to (best) achieve something like this argparse code:

parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument("--opt-A, action="store_true")
group.add_argument("--opt-B, action="store_true")

I found several mentions of ways to do it with Click, but none that were “built-in”, nor I’m I clear on how I’d use that with Typer.

Any help would be much appreciated. I really like the feel of Typer!

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:33
  • Comments:17 (3 by maintainers)

github_iconTop GitHub Comments

12reactions
OdinTech3commented, Aug 14, 2021

Hey my fellow Pythonistas, I often comeback to this issue from time to time because it’s still a problem for me so I took @daddycocoaman answer and came up with this:

import typer

app = typer.Typer()

def MutuallyExclusiveGroup(size=2):
    group = set()
    def callback(ctx: typer.Context, param: typer.CallbackParam, value: str):
        # Add cli option to group if it was called with a value
        if value is not None and param.name not in group:
            group.add(param.name)
        if len(group) > size-1:
            raise typer.BadParameter(f"{param.name} is mutually exclusive with {group.pop()}")
        return value
    return callback

exclusivity_callback = MutuallyExclusiveGroup()

@app.command()
def main(
        optA: str = typer.Option(None, callback=exclusivity_callback),
        optB: int = typer.Option(None, callback=exclusivity_callback)
    ):
    typer.echo(f"Option A is {optA} and Option B is {optB}")


if __name__ == "__main__":
    app()

Using the function MutuallyExclusiveGroup I return another function within a closure where there is state, a set called group as typer invokes the callbacks the logic will check if more than one option I have added the exclusivity_callback was called in the command line and raises an exception.

$ python cli.py --optb 3 --opta wow
Usage: cli.py [OPTIONS]

Error: Invalid value for '--opta': optA is mutually exclusive with optA

$ python cli.py --optb 3
Option A is None and Option B is 3

$ python cli.py --opta 3 --optb wow
Usage: cli.py [OPTIONS]
Try 'cli.py --help' for help.

Error: Invalid value for '--optb': wow is not a valid integer

$ python cli.py --opta wow --optb 3
Usage: cli.py [OPTIONS]

Error: Invalid value for '--optb': optB is mutually exclusive with optA

$ python cli.py --opta wow
Option A is wow and Option B is None

If you need to ensure at least one of the options are passed to the command line then manually check it in the body of your function for the command like so

@app.command()
def main(
        optA: str = typer.Option(None, callback=exclusivity_callback),
        optB: int = typer.Option(None, callback=exclusivity_callback)
    ):

    if not any([optA, optB]):
        raise typer.BadParameter("At least optA or optB is required.")
        
    typer.echo(f"Option A is {optA} and Option B is {optB}")
5reactions
robinbowescommented, Mar 17, 2022

Just adding another “I’d like to see this too” comment.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Mutually Exclusive & Collectively Exhaustive Categories - Cvent
First, the categories (response options) must be mutually exclusive, which means they do not overlap with one another.
Read more >
Mutually Exclusive: What It Means, With Examples
If considering mutually exclusive options, a company must weigh the opportunity cost, or what it would be giving up by choosing each option....
Read more >
mutually exclusive options with argp in C - Stack Overflow
Options -a and -b are mutually exclusive because one cannot specify them together, i.e. specifying -a excludes the use of -b . The...
Read more >
Should I use mutually exclusive options on my command line ...
POSIX just says (regarding mutually exclusive command line options in POSIX utilities):. The use of conflicting mutually-exclusive arguments ...
Read more >
Solved Question 5 (15 Marks) Two mutually exclusive options
Question : Question 5 (15 Marks) Two mutually exclusive options are considered for a bus terminal undertaken by the city government. Option A...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found