Skip to content

Willie tutorial, Part 3

Tao Sauvage edited this page Aug 21, 2013 · 2 revisions

Willie tutorial, Part 3: The Config file, and the configure and setup functions

Willie has a config file, written in an INI-like format. It can provide configuration options not just for the bot itself, but for modules as well. Here, we're going to cover how you can leverage that configuration, as well as how to make your module configurable in the wizard like we showed back in Part 1.

Config Basics

The config file is made up of a number of sections, each of which has a number of keys or attributes. If you open up your config file, you'll see something like this.

[core]
nick = Willie
host = irc.dftba.net
use_ssl = False
port = 6667
owner = Embolalia
channels = #YourPants,#tech

[admin]
hold_ground = False

[bugzilla]
domains = bugzilla.redhat.com,bugzilla.gnome.org

Here, core and bugzilla are sections. As you may have guessed, core contains attributes relevant to the bot's core functionality - it's nick, the host to connect to, etc., and bugzilla and admin contain attributes relevant to two of the bot's modules.

In the context of your callable, the config file is available as an attribute of the bot parameter. Each section is an attribute of the config file, and each key in a section is an attribute of its respective section. For example, if we wanted to get the owner of the bot, we would use bot.config.core.owner.

The config object also has a number of methods. Some of these relate to making the wizard, which we'll discuss later. Others are helpers to make dealing with the config a bit easier. For example, instead of trying to split up those bugzilla domains ourselves, we can use bot.config.bugzilla.get_list('domains'). This takes care of splitting up that list for us.

Changing attributes is as easy as just assigning a value to them. You should probably avoid doing this in the core section from your module, unless you know what you're doing. But if, for example, you wanted to change hold_ground to True, you would simply do bot.config.admin.hold_ground = True. You can also do this with lists. If you wanted to add bugzilla.mozilla.org to the list of bugzilla domains, you could do bot.config.bugzilla.domains = ['bugzilla.redhat.com', 'bugzilla.gnome.org', 'bugzilla.mozilla.org'] and it would change it properly. If you do an assignement to a config attribute that doesn't exist, it will create it for you. However, changes aren't automatically written to the config file itself, so they'll disappear when you restart the bot unless you call bot.config.save().

The configure function

You may want to make a script that will help users in configuring your module. This is helpful for when new users are setting up your script for the first time. You can provide them with an easy way to set up the options, and even test to make sure they gave you options that make sense.

This is done through a special function in your module, called configure. It is different from the callables you made in the previous sections. When it's called, the bot isn't actually running, you're just interfacing with the user in the terminal. The function is passed just one argument, config, which is the same as the bot.config you would get in one of your callables.

What you'll probably want to do first in here is ask whether the user actually wants to configure your module. They may just want to ignore it for now, and configure it later (especially if the setting of these config values isn't critical to making your module work.) You can do this with config.option(question, default). This asks the given question (which you should give it without the question mark; it adds one on its own). If the user just hits enter without giving an answer, it defaults to the given default. If you just give it the question, with no default, the default will be False. The choice the user makes will be returned as a boolean; either True or False.

Next, you'll probably want to create a section in the config file for your module by doing config.add_section('yourmodulename'). The name should probably be the same as your module's name. From there, there are four functions that you'll probably rely on most:

  • interactive_add(section, option, prompt, default=None) will add a new key to the section you specify, with the name you specify with "option". It will give the user the prompt you specify. You don't have to pass default, but if you do, it will use that as the default answer. You can also use that as an example value, as long as it won't cause you problems later on. If the value has already been configured, that will always be the default used here whether you provide one or not.

  • add_list(section, option, message, prompt) is like interactive_add, but it makes a list. If there are already values there, it will ask if the user wants to keep them before proceeding.

  • add_option(section, option, question, default=False) This is like the option function above, but it saves the value to the given section and value.

You don't need to worry about saving at the end of this function; the wizard will do that for you. It's a good idea to check the values to make sure they're valid. If it's a file the bot should write to, for example, make sure you have permissions to do so. It's better to find a problem here, since you can immediately get the user to fix it.

The setup function

Another special function is setup. Like configure, it's a bit special. This function is run when the module is loaded. You should use this to make sure everything is properly set up for your module to function properly. It is passed one argument, bot, but it's a bit different from the one you get in your callables. Like normal, it has access to the config file, the database, and most of the rest. However, since this is run before the bot has completely finished booting up, it's not guaranteed that it has finished connecting to the server yet. As such, functions that send messages to the server, like msg, might not work as expected in here. Additionally, since it's not triggered from a message but from within the bot itself, say and reply don't work at all (they wouldn't know where they're replying to).

It's a good idea that you check that things like config options you rely on later are here and valid. We'll talk about memory keys and the database later on, and setting those up is often done in this function.

If you find a problem with something here - a vital config option is missing or something like that - which you can't recover from on your own, you may decide to throw some sort of exception, which will prevent the rest of the module from loading. (You can import willie.config.ConfigurationError and raise it for this, if it's a problem with the config file.) This way, you can assume in the rest of your module that everything you check here is in order.