Is there a way to hand the command line parsing to python-click but then have click hand execution back over to my code?

Question:

When I run the code below, nothing below the domains() call is processed. The gibberish doesn’t even throw an exception. It seems like to use click you have to do everything the click way, which as best I can tell is to move all of my code into the decorator functions?

Is there a way to hand the command line parsing to click but then have click hand execution back over to my code?

import click
my_cfg = { 'domains': [], 'def_domains': ['stackoverflow.com', 'google.com'] } 

@click.command()
@click.option('--domain', '-d', multiple=True, type=str, nargs=1, default=my_cfg['def_domains'])
def domains(domain):
    click.echo('n'.join(domain))
    my_cfg['domains'].append(domain)
domains()

fgddtruhygtuit5r # No exception thrown!! Once domains() is called my code never runs

### Bunch of code here that I cannot easily move into domains() ###

Running python 3.10.x on Windows from within PyCharm.

Asked By: argel1200

||

Answers:

Short version is pass in standalone_mode=False when calling your click commands.

Found the answer in Program stops when running @click.command. And I learned about it in Using the Python ‘click’ library’s parser as a simple function.

Here’s an example:

import click
my_cfg = {
    'domains':     [],
    'def_domains': ['stackoverflow.com', 'google.com'],
    }

@click.command()
@click.option('--domain', '-d', multiple=True, type=str, nargs=1, default=my_cfg['def_domains'])
def domains(domain):
    my_cfg['domains'].append(domain)

domains(standalone_mode=False)

print(f"my_cfg: {my_cfg}")

for_testing.py

my_cfg: {'domains': [('stackoverflow.com', 'google.com')], 'def_domains': ['stackoverflow.com', 'google.com']}

for_testing.py -d duckduckgo.com

my_cfg: {'domains': [('duckduckgo.com',)], 'def_domains': ['stackoverflow.com', 'google.com']}

for_testing.py -d duckduckgo.com -d google.com -d bing.com

my_cfg: {'domains': [('duckduckgo.com', 'google.com', 'bing.com')], 'def_domains': ['stackoverflow.com', 'google.com']}

Edit: You’ll need to handle exceptions and even exiting for –version, -h, and -help yourself. Here’s some code I kludged together:

def process_cli_using_click(my_cli):
    #param my_cli: The function you defined via click to process the command line arguments
    click_invoke_rc = None

    try:
        click_invoke_rc = my_cli(standalone_mode=False)
    except click.exceptions.NoSuchOption as err:
        print(f"{err}")
        print(f"Try running the program with -h or --help.")
        exit(3)
    except click.exceptions.UsageError as err:
        print(f"{err}")
        print(f"Try running the program with -h or --help.")
        exit(5)
    except:
        err = sys.exc_info()[0]
        print(f"An unexpected command line processing error occurred:")
        print(f"{err}")
        print(f"Try running the program with -h or --help.")
        exit(10)

    if click_invoke_rc == 0:  # Catch if -h, --help, --version, or something unknown was specified
        exit(1)
Answered By: argel1200
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.