2

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.

1 Answer 1

9

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Hey @m79lkm, I am trying to do something similar here - stackoverflow.com/questions/57930553/… I can't quite get it to work, even with this example, can you help out if you know what to do.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.