Dirk
Dirk

Reputation: 10111

Save a command line option's value in an object with Python's Click library

I want to parse some command line arguments with Python's Click library and save the provided values in an object.

My first guess would be to do it like this:

import click

class Configuration(object):

    def __init__(self):

        # configuration variables
        self.MyOption = None

        # method call
        self.parseCommandlineArguments()

    @click.command()
    @click.option('--myoption', type=click.INT, default=5)
    def parseCommandlineArguments(self, myoption):

        # save option's value in the object
        self.MyOption = myoption

# create an instance
configuration = Configuration()
print(configuration.MyOption)

However, this does not work, instead I get:

TypeError: parseCommandlineArguments() takes exactly 2 arguments (1 given)

Apparently, passing self to the decorated function is not the correct way to do it. If I remove self from the method arguments then I can e.g. do print(myoption) and it will print 5 on the screen but the value will not be known to any instances of my Configuration() class.

What is the correct way to handle this? I assume it has something to do with context handling in Click but I cannot get it working based on the provided examples.

Upvotes: 2

Views: 3540

Answers (1)

m79lkm
m79lkm

Reputation: 3070

If I'm understanding you correctly, you want a command line tool that will take configuration options and then do something with those options. If this is your objective then have a look at the example I posted. This example uses command groups and passes a context object through each command. Click has awesome documentation, be sure to read it.

import click
import json


class Configuration(object):
    """
    Having a custom context class is usually not needed.
    See the complex application documentation:
        http://click.pocoo.org/5/complex/
    """
    my_option = None
    number = None
    is_awesome = False
    uber_var = 900

    def make_conf(self):
        self.uber_var = self.my_option * self.number

pass_context = click.make_pass_decorator(Configuration, ensure=True)


@click.group(chain=True)
@click.option('-m', '--myoption', type=click.INT, default=5)
@click.option('-n', '--number', type=click.INT, default=0)
@click.option('-a', '--is-awesome', is_flag=True)
@pass_context
def cli(ctx, myoption, number, is_awesome):
    """
    this is where I will save the configuration
    and do whatever processing that is required
    """
    ctx.my_option = myoption
    ctx.number = number
    ctx.is_awesome = is_awesome
    ctx.make_conf()
    pass


@click.command('save')
@click.argument('output', type=click.File('wb'))
@pass_context
def save(ctx, output):
    """save the configuration to a file"""
    json.dump(ctx.__dict__, output, indent=4, sort_keys=True)
    return click.secho('configuration saved', fg='green')


@click.command('show')
@pass_context
def show(ctx):
    """print the configuration to stdout"""
    return click.echo(json.dumps(ctx.__dict__, indent=4, sort_keys=True))

cli.add_command(save)
cli.add_command(show)

After this is installed your can run commands like this:

mycli -m 30 -n 40 -a show
mycli -m 30 -n 40 -a save foo.json
mycli -m 30 -n 40 -a show save foo.json

The complex example is an excellent demo for developing a highly configurable multi chaining command line tool.

Upvotes: 9

Related Questions