ceskib
ceskib

Reputation: 140

Error: No such option yet I've clearly set the option up

I'm just starting out with a simple project and using the Click library and have hit a snag early on that I can't figure out. When I run this with the "--testmode" flag it shows as True however the subsequent function doesn't execute and I get an error that no such option is defined? What am I doing wrong here?

import click

@click.command()
@click.option('--user', prompt=True)
@click.option('--password', prompt=True, hide_input=True, confirmation_prompt=False)
def authenticate(user, password):
    pass

@click.command()
@click.option('--age')
@click.option('--testmode', is_flag=True)
def main(age, testmode):
    print('Age: ', age)
    print('Testmode: ', testmode)

    if testmode:
        authenticate()

if __name__ == "__main__":
    main()

Console output:

python .\dev.py --help
Usage: dev.py [OPTIONS]

Options:
  --age TEXT
  --testmode
  --help      Show this message and exit.


python .\dev.py --testmode
Age:  None
Testmode:  True
Usage: dev.py [OPTIONS]
Try 'dev.py --help' for help.

Error: no such option: --testmode

Upvotes: 0

Views: 3016

Answers (3)

Ed_
Ed_

Reputation: 354

I had same error, but with a different cause. Posting for others who may run into it.

I was running myscript.py -? and getting the message error: no such option: -o. Very confusing, I entered one option (-?) which exists, but it complained about a different one (-o). Checked my environment, imports, even thought optparse library may have been corrupted.

Turns out I (somehow, mistakenly) had a file named -o in current dir. So bash was turning -? into -o and passing it to my script. SMH. Always check your fileystem!

Upvotes: 0

afterburner
afterburner

Reputation: 2781

Iarsks answer is what you're looking for, but to elaborate on that further, the Click documentation has some information on invoking other commands. So if you really wanted authenticate to be setup as a command, you have 2 options.

  1. Abstract the logic from authenticate into a python method, and invoke that inside authenticate and the if testmode block.

  2. Look into invoking one command from another. Click commands have access to a context, which is a way for click to hold state referring to the current command, and other commands. More information can be found here.

For clarity, a click context ctx can invoke another command as such: ctx.invoke(authenticate, user=user_value, password=password_value).

If the current command that was invoke has the same options and parameters as the other one you'd like to invoke, click offers a shorthand for it: click.forward(authenticate), which will pass the same arguments to the authenticate command.

Upvotes: 1

larsks
larsks

Reputation: 311556

The problem is here:

    if testmode:
        authenticate()

You're calling authenticate() like a function, but you've defined it as another click.command. That means it's going to look at sys.argv for command line options, find --testmode, and compare that against the options you defined with @click.option.

The authenticate method doesn't have a --testmode option, hence the error you're seeing.

There are various ways to fix this. Does authenticate really need to be configured as a command? The way you've got your code set up right now there's no way to call it via the command line.

Upvotes: 3

Related Questions