Introduction

This package contains a framework for an easily set-up, multi-purpose IRC bot. The intent with this package is not that it be included with other packages, but rather be run as a standalone program. However, it is intended (and encouraged) that users write new “modules” for it. This documentation is intended to serve that goal.

Due to the high level of customization encouraged by this bot, there are a few different versions of it floating around. This documentation focuses on Willie, but some parts may be applicable to older versions. The original “phenny” is, for the purpose of this documentation, called version 1.x, and the “jenni” fork thereof considered version 2.x. Willie versions start at 3.0 and follow semantic versioning.

Getting started: Your functions, willie, and trigger

At its most basic, writing a Willie module involves creating a Python file with some number of functions in it. Each of these functions will be passed a Willie object (Phenny in 1.x and Jenni in 2.x) and a Trigger object (CommandInput in 1.x and 2.x). By convention, these are named phenny and input in 1.x, jenni and input in 2.x, willie and trigger in 3.x, and bot and trigger from version 4.0 onward. For the purposes of this guide, the 4.0 names will be used.

Your modules

A Willie module contains one or more callables. It may optionally contain configure, setup, and shutdown functions. callables are given a number of attributes, which determine when they will be executed. This is done with decorators, imported from willie.module. It may also be done by adding the attributes directly, at the same indentation level as the function’s def line, following the last line of the function; this is the only option in versions prior to 4.0.

callable(bot, trigger)

This is the general function format, called by Willie when a command is used, a rule is matched, or an event is seen, as determined by the attributes of the function. The details of what this function does are entirely up to the module writer - the only hard requirement from the bot is that it be callable with a Willie object and a Trigger object, as noted above. Usually, methods of the Willie object will be used in reply to the trigger, but this isn’t a requirement.

The return value of a callable will usually be None. This doesn’t need to be explicit; if the function has no return statement (or simply uses return with no arguments), None will be returned. In 3.2+, the return value can be a constant; in prior versions return values were ignored. Returning a constant instructs the bot to perform some action after the callable‘s execution. For example, returning NOLIMIT will suspend rate limiting on that call. These constants are defined in willie.module, except in version 3.2 in which they are defined as attributes of the Willie class.

Note that the name can, and should, be anything - it doesn’t need to be called callable.

commands

See also: willie.module.commands()

A list of commands which will trigger the function. If the Willie instance is in a channel, or sent a PRIVMSG, where one of these strings is said, preceeded only by the configured prefix (a period, by default), the function will execute.

rule

See also: willie.module.rule()

A regular expression which will trigger the function. If the Willie instance is in a channel, or sent a PRIVMSG, where a string matching this expression is said, the function will execute. Note that captured groups here will be retrievable through the Trigger object later.

Inside the regular expression, some special directives can be used. $nick will be replaced with the nick of the bot and , or :, and $nickname will be replaced with the nick of the bot.

Prior to 3.1, rules could also be made one of three formats of tuple. The values would be joined together to form a singular regular expression. However, these kinds of rules add no functionality over simple regular expressions, and are considered deprecated in 3.1.

event

See also: willie.module.event()

This is one of a number of events, such as 'JOIN', 'PART', 'QUIT', etc. (More details can be found in RFC 1459.) When the Willie bot is sent one of these events, the function will execute. Note that functions with an event must also be given a rule to match (though it may be '.*', which will always match) or they will not be triggered.

rate

Availability: 2+

See also: willie.module.rate()

This limits the frequency with which a single user may use the function. If a function is given a rate of 20, a single user may only use that function once every 20 seconds. This limit applies to each user individually. Users on the admin list in Willie’s configuration are exempted from rate limits.

priority

See also: willie.module.priority()

Priority can be one of high, medium, low. It allows you to control the order of callable execution, if your module needs it. Defaults to medium

setup(willie)

This is an optional function of a module, which will be called while the module is being loaded. The purpose of this function is to perform whatever actions are needed to allow a module to function properly (e.g, ensuring that the appropriate configuration variables exist and are set). Note that this normally occurs prior to connection to the server, so the behavior of the Willie object’s messaging functions is undefined.

Throwing an exception from this function (such as a ConfigurationError) will prevent any callables in the module from being registered, and provide an error message to the user. This is useful when requiring the presence of configuration values or making other environmental requirements.

The bot will not continue loading modules or connecting during the execution of this function. As such, an infinite loop (such as an unthreaded polling loop) will cause the bot to hang.

shutdown(willie)

Availability: 4.1+

This is an optional function of a module, which will be called while the Willie is quitting. Note that this normally occurs after closing connection to the server, so the behavior of the Willie object’s messaging functions is undefined. The purpose of this function is to perform whatever actions are needed to allow a module to properly clean up (e.g, ensuring that any temporary cache files are deleted).

The bot will not continue notifying other modules or continue quitting during the execution of this function. As such, an infinite loop (such as an unthreaded polling loop) will cause the bot to hang.

configure(config)

Availability: 3+

This is an optional function of a module, which will be called during the user’s setup of the bot. It’s intended purpose is to use the methods of the passed Config object in order to create the configuration variables it needs to function properly.

In 3.1+, the docstring of this function can be used to document the configuration variables that the module uses. This is not currently used by the bot itself; it is merely convention.

The Willie class

class willie.bot.Willie(config)
class Job(interval, func)

Job is a simple structure that hold information about when a function should be called next. They can be put in a priority queue, in which case the Job that should be executed next is returned.

Calling the method next modifies the Job object for the next time it should be executed. Current time is used to decide when the job should be executed next so it should only be called right after the function was called.

max_catchup = 5

This governs how much the scheduling of jobs is allowed to get behind before they are simply thrown out to avoid calling the same function too many times at once.

next()

Update self.next_time with the assumption func was just called.

Returns: A modified job object.

class Willie.JobScheduler(bot)

Calls jobs assigned to it in steady intervals.

JobScheduler is a thread that keeps track of Jobs and calls them every X seconds, where X is a property of the Job. It maintains jobs in a priority queue, where the next job to be called is always the first item. Thread safety is maintained with a mutex that is released during long operations, so methods add_job and clear_jobs can be safely called from the main thread.

add_job(job)

Add a Job to the current job queue.

clear_jobs()

Clear current Job queue and start fresh.

min_reaction_time = 30.0

How often should scheduler checks for changes in the job list.

run()

Run forever.

Willie.cap_req(module_name, capability, failure_callback)

Tell Willie to request a capability when it starts.

By prefixing the capability with -, it will be ensured that the capability is not enabled. Simmilarly, by prefixing the capability with =, it will be ensured that the capability is enabled. Requiring and disabling is “first come, first served”; if one module requires a capability, and another prohibits it, this function will raise an exception in whichever module loads second. An exception will also be raised if the module is being loaded after the bot has already started, and the request would change the set of enabled capabilities.

If the capability is not prefixed, and no other module prohibits it, it will be requested. Otherwise, it will not be requested. Since capability requests that are not mandatory may be rejected by the server, as well as by other modules, a module which makes such a request should account for that possibility.

The actual capability request to the server is handled after the completion of this function. In the event that the server denies a request, the failure_callback function will be called, if provided. The arguments will be a Willie object, and the capability which was rejected. This can be used to disable callables which rely on the capability.

Willie.config = None

The Config for the current Willie instance.

Willie.debug(tag, text, level)

Sends an error to Willie’s configured debug_target.

Args:
tag - What the msg will be tagged as. It is recommended to pass
__file__ as the tag. If the file exists, a relative path is used as the file. Otherwise the tag is used as it is.

text - Body of the message.

level - Either verbose, warning or always. Configuration option
config.verbose which levels are ignored.

Returns: True if message was sent.

Willie.doc = None

A dictionary of command names to their docstring and example, if declared. The first item in a callable’s commands list is used as the key in version 3.2 onward. Prior to 3.2, the name of the function as declared in the source code was used.

Willie.enabled_capabilities = None

A set containing the IRCv3 capabilities that the bot has enabled.

static Willie.is_callable(obj)

Return true if object is a willie callable.

Object must be both be callable and have hashable. Furthermore, it must have either “commands”, “rule” or “interval” as attributes to mark it as a willie callable.

static Willie.is_shutdown(obj)

Return true if object is a willie shutdown method.

Object must be both be callable and named shutdown.

Willie.memory = None

A thread-safe dict for storage of runtime data to be shared between modules. See WillieMemory

Willie.privileges = None

A dictionary of channels to their users and privilege levels

The value associated with each channel is a dictionary of Nicks to a bitwise integer value, determined by combining the appropriate constants from module.

Willie.register(variables)

With the __dict__ attribute from a Willie module, update or add the trigger commands and rules, to allow the function to be triggered, and shutdown methods, to allow the modules to be notified when willie is quitting.

Willie.server_capabilities = None

A set containing the IRCv3 capabilities that the server supports.

For servers that do not support IRCv3, this will be an empty set.

Willie.stats = None

A dictionary which maps a tuple of a function name and where it was used to the nuber of times it was used there.

Willie.times = None

A dictionary mapping lower-case’d nicks to dictionaries which map funtion names to the time which they were last used by that nick.

Willie.unregister(variables)

Unregister all willie callables in variables, and their bindings.

When unloading a module, this ensures that the unloaded modules will not get called and that the objects can be garbage collected. Objects that have not been registered are ignored.

Args: variables – A list of callable objects from a willie module.

reply(text)

In a module function, send text to the channel in which the function was triggered, preceeded by the nick of the user who triggered it.

This function is not available outside of module functions. It can not be used, for example, in a module’s setup or shutdown function.

The same behavior regarding loop detection and length restrictions apply to reply as to msg, though reply does not offer automatic message splitting.

say(text, max_messages=1)

In a module function, send text to the channel in which the function was triggered.

This function is not available outside of module functions. It can not be used, for example, in a module’s configure function.

The same behavior regarding loop detection and length restrictions, as well as message splitting, apply to say as to msg.

action(text)

In a module function, send text to the channel in which the function was triggered preceeded by CTCP ACTION directive (result identical to using /me in most clients).

This function is not available outside of module functions. It can not be used, for example, in a module’s configure function.

The same behavior regarding loop detection and length restrictions apply to action as to msg and say, though like reply there is no facility for message splitting.

quit(message)

Gracefully quit and shutdown, using message as the quit message.

Willie will notify modules that it is quitting should the modules have a shutdown method.

part(channel)

Part channel

join(channel, password = None)

Join a channel named channel.

nick

Willie’s current nick. Changing this while Willie is running is unsupported.

name

Willie’s “real name”, as used for whois.

password

Willie’s NickServ password

channels

A list of Willie’s initial channels. This list will initially be the same as the one given in the config file, but is not guaranteed to be kept up-to-date.

ops
halfplus

Availability: 3+

Dictionary mapping channels to a list of their ops, and half-ops and ops respectively.

write(args, text=None)

Send a command to the server

args is an iterable of strings, which are joined by spaces. text is treated as though it were the final item in args, but is preceeded by a :. This is a special case which means that text, unlike the items in args may contain spaces (though this constraint is not checked by write).

In other words, both willie.write(('PRIVMSG',), 'Hello, world!') and willie.write(('PRIVMSG', ':Hello, world!')) will send PRIVMSG :Hello, world! to the server.

Newlines and carriage returns (‘\n’ and ‘\r’) are removed before sending. Additionally, if the message (after joining) is longer than than 510 characters, any remaining characters will not be sent.

msg(recipient, text, max_messages=1)

Send a PRIVMSG of text to recipient. If the same text was the message in 5 or more of the last 8 calls to msg, '...' will be sent instead. If this condition is met, and '...' is more than 3 of the last 8 calls, no message will be sent. This is intended to prevent Willie from being caught in an infinite loop with another bot, or being used to spam.

If max_messages argument is optional, and defaults to 1. The message will be split into that number of segments. Each segment will be 400 bytes long or less (bearing in mind that messages are UTF-8 encoded). The message will be split at the last space before the 400th byte, or at the 400th byte if no such space exists. The remainder will be split in the same manner until either the given number of segments is reached or the remainder is less than 400 bytes.

If the message is too long to fit into the given number of segments (or if no number is given), the bot will send as many bytes to the server as it can. The server, due to the structure of the protocol, will likely truncate the message further, to a length that is not determinable by Willie (though you can generally rely on 400 bytes making it through).

Note that when a message is split not on a space but on a byte number, no attention is given to Unicode character boundaries, and no other word boundaries besides space will be split upon. This will not cause problems in the vast majority of cases.

debug(tag, text, level)

Availability: 3+

Send text to Willie’s configured debug_target. This can be either an IRC channel (starting with #) or stdio. Suppress the message if the given level is lower than Willie’s configured verbose setting. Acceptable values for level are 'verbose' (only send if Willie is in verbose mode), 'warning' (send if Willie is in verbose or warning mode), always (send debug message regardless of the configured debug level). Returns True if the message is sent or printed, and False if it is not.

If debug_target is a channel, the same behavior regarding loop detection and length restrictions apply to debug as to msg.

add_op(channel, name)
add_halfop(channel, name)

Availability: 3+, deprecated in 4.1.0

Add name to channel‘s entry in the ops or halfplus dictionaries, respectively.

del_op(channel, name)
del_halfop(channel, name)

Availability: 3+, deprecated in 4.1.0

Remove name from channel‘s entry in the ops or halfplus dictionaries, respectively.

flush_ops(channel)

Availability: 3+, deprecated in 4.1.0

Re-initialize and empty the ops and halfops entry for channel.

init_ops_list(self, channel)

Availability: 3+, deprecated in 4.1.0

Create an empty entry in ops and halfops for channel. This will not damage existing entries, but must be done before users can be added to either dictionary.

The Trigger class

class Trigger
sender

The channel (or nick, in a private message) from which the message was sent.

nick

The nick of the person who sent the message.

event

The event which triggered the message.

bytes

The line which triggered the message.

match

The regular expression MatchObject for the triggering line.

group

The group function of the match attribute.

See Python re documentation for details.

groups

The groups function of the match attribute.

See Python re documentation for details.

args

The arguments given to a command.

admin

True if the nick which triggered the command is in Willie’s admin list as defined in the config file.

owner

True if the nick which triggered the command is the owner stated in the config file.

host

The host which sent the triggering message.

isop

Availability: 3+, deprecated in 4.1.0

True if the nick which triggered the command is an op on the channel it was triggered in. Will always be False if the command was triggered by a private message

isvoice

Availability: 3+, deprecated in 4.1.0

True if the nick which triggered the command is voiced on the channel it was triggered in. Will always be False if the command was triggered by a private message Will be True if user is an op or half-op, even if they don’t have +v

More advanced: db and config

The willie object has, among others, the attributes db and config. These can be used for a number of functions and features.

The WillieDB class

Availability: 3.1+

Note: This supersedes the SettingsDB object of 3.0. Within Willie modules, simmilar functionallity can be found using db.preferences.

This class defines an interface for a semi-arbitrary database type. It is meant to allow module writers to operate without regard to how the end user has decided to set up the database.

class willie.db.Table(db, name, columns, key)

Return an object which represents a table in the given WillieDB, with the given attributes. This will not check if db already has a table with the given name; the db‘s add_table provides that functionality.

key must be a string, which is in the list of strings columns, or an Exception will be thrown.

add_columns(columns)

Insert a new column into the table, and add it to the column cache. This is the preferred way to add new columns to the database.

channels()

Returns the number of users (entries starting with # or &) in the table’s key column.

contains(row, key=None)

Return True if this table has a row where the key value is equal to key, else False.

key in db will also work, where db is your SettingsDB object.

delete(row, key=None)

Deletes the row for row in the database, removing its values in all columns.

get(row, columns, key=None)

Retrieve the value(s) in one or more columns in the row where the key column(s) match the value(s) given in row. This is basically equivalent to executing SELECT <columns> FROM <self> WHERE <key> = <row>.

The key can be either the name of one column as a string, or a tuple of the names of multiple columns. row is the value or values of this column or columns for which data will be retrieved. If multiple columns are being used, the order in which the columns are presented should match between row and key. A KeyError will be raised if no have values matching row in key. If key is not passed, it will default to the table’s primary key.

columns can either be a single column name, or a tuple of column names. If one name is passed, a single string will be returned. If a tuple of names is passed, the return value will be a tuple in the same order.

has_columns(column)

Each Table contains a cached list of its columns. hascolumn(column) checks this list, and returns True if it contains column. If column is an iterable, this returns true if all of the values in column are in the column cache. Note that this will not check the database itself; it’s meant for speed, not accuracy. However, unless you have multiple bots using the same database, or are adding columns while the bot is running, you are unlikely to encounter errors.

keys(key=None)

Return an iterator over the keys and values in the table.

In a for each loop, you can use for key in table:, where key will be the value of the key column(s), which defaults to the primary key, and table is the Table. This may be deprecated in future versions.

size()

Returns the total number of rows in the table.

update(row, values, key=None)

Update the row where the values in row match the key columns. If the row does not exist, it will be created. The same rules regarding the type and length of key and row apply for update as for get.

The given values must be a dict of column name to new value.

users()

Returns the number of users (entries not starting with # or &) in the table’s key column.

class willie.db.WillieDB(config)

Return a WillieDB object configured with the options in the given Config object. The exact settgins used vary depending on the type of database chosen to back the SettingsDB, as determined by the userdb_type attribute of config.

Currently, two values for userdb_type are supported: sqlite and mysql. The sqlite type requires that userdb_file be set in the db section of config (that is, under the [db] heading in the config file), and refer to a writeable sqlite database. The mysql type requires userdb_host, userdb_user, userdb_pass, and userdb_name to be set, and provide the host and name of a MySQL database, as well as a username and password for a user able to write to said database.

Upon creation of the object, the tables currently existing in the given database will be registered, as though added through add_table.

add_table(name, columns, key)

Add a column with the given name and key, which has the given columns. Each element in columns may be either a string giving the name of the column, or a tuple containing the name of the column and its type (using SQL type names). If the former, the type will be assumed as string.

This will attempt to create the table within the database. If an error is encountered while adding the table, it will not be added to the WillieDB object. If a table with the same name and key already exists, the given columns will be added (if they don’t already exist).

The given name can not be the same as any function or attribute (with the exception of other tables) of the WillieDB object, nor may it start with '_'. If it does not meet this requirement, or if the name matches that of an existing table with a different key, a ValueError will be thrown.

When a table is created, the column key will be declared as the primary key of the table. If it is desired that there be no primary key, this can be achieved by creating the table manually, or with a custom query, and then creating the WillieDB object.

check_table(name, columns, key)

Return True if the WillieDB contains a table with the same name and key, and which contains a column with the same name as each element in the given list columns.

connect()

Create a database connection object. This functions essentially the same as the connect function of the appropriate database type, allowing for custom queries to be executed.

willie.db.configure(config)

Interactively create configuration options and add the attributes to the Config object config.

The Config class

Availability: 3+ for all functions; attributes may vary.

The config class is an abstraction class for accessing the active Willie configuration file.

The Willie config file is divided to sections, and each section contains keys and values. A section is an attribute of the config class, and is of type ConfigSection. Each section contains the keys as attributes. For example, if you want to access key example from section test, use config.test.example. Note that the key names are made lower-case by the parser, regardless of whether they are upper-case in the file.

The core section will always be present, and contains configuration used by the Willie core. Modules are allowed to read those, but must not change them.

The config file can store strings, booleans and lists. If you need to store a number, cast it to int() when reading.

For backwards compatibility, every key in the core section is an attribute of the config class as well as of config.core. For new code, always specify the name of the section, because this behavior might be removed in the future.

Running the config.py file directly will give the user an interactive series of dialogs to create the configuration file. This will guide the user through creating settings for the Willie core, the settings database, and any modules which have a configuration function.

The configuration function, if used, must be declared with the signature configure(config). To add options, use interactive_add, add_list and add_option.

class willie.config.Config(filename, load=True, ignore_errors=False)
class ConfigSection(name, items, parent)

Represents a section of the config file, contains all keys in the section as attributes.

get_list(name)
Config.add_list(section, option, message, prompt)

Ask user in terminal for a list to assign to option. If option is already defined under section, show the user the current values and ask if the user would like to keep them. If so, additional values can be entered.

Config.add_option(section, option, question, default=False)

Show user in terminal a “y/n” prompt, and set option to True or False based on the response. If default is passed as true, the default will be shown as [y], else it will be [n]. question should be phrased as a question, but without a question mark at the end. If option is already defined, it will be used instead of default, regardless of wheather default is passed.

Config.add_section(name)

Add a section to the config file, returns False if already exists.

Config.enumerate_modules(show_all=False)

Availability: 4.0+

Return a dict mapping the names of modules to the location of their file. This searches the regular modules directory and all directories specified in the core.extra attribute of the config object. If two modules have the same name, the last one to be found will be returned and the rest will be ignored. Modules are found starting in the regular directory, followed by ~/.willie/modules, and then through the extra directories in the order that the are specified.

If show_all is given as True, the enable and exclude configuration options will be ignored, and all modules will be shown (though duplicates will still be ignored as above).

Config.filename = None

The config object’s associated file, as noted above.

Config.has_option(section, name)

Check if option name exists under section section

Config.has_section(name)

Check if section name exists

Config.interactive_add(section, option, prompt, default=None, ispass=False)

Ask user in terminal for the value to assign to option under section. If default is passed, it will be shown as the default value in the prompt. If option is already defined in section, it will be used instead of default, regardless of wheather default is passed.

Config.option(question, default=False)

Show user in terminal a “y/n” prompt, and return true or false based on the response. If default is passed as true, the default will be shown as [y], else it will be [n]. question should be phrased as a question, but without a question mark at the end.

Config.save()

Save all changes to the config file

exception willie.config.ConfigurationError(value)

Exception type for configuration errors

willie.config.check_dir(create=True)
willie.config.create_config(configpath)
willie.config.wizard(section, config=None)

Miscellaneous: web, tools, module

These provide a number of useful shortcuts for common tasks.

willie.web

Availability: 3+

The web class contains essential web-related functions for interaction with web applications or websites in your modules. It supports HTTP GET, HTTP POST and HTTP HEAD.

willie.web.get(uri, timeout=20, headers=None, return_headers=False, limit_bytes=None)

Execute an HTTP GET query on uri, and return the result. timeout is an optional argument, which represents how much time we should wait before throwing a timeout exception. It defualts to 20, but can be set to higher values if you are communicating with a slow web application. headers is a dict of HTTP headers to send with the request. If return_headers is True, return a tuple of (bytes, headers)

If limit_bytes is provided, only read that many bytes from the URL. This may be a good idea when reading from unknown sites, to prevent excessively large files from being downloaded.

willie.web.get_urllib_object(uri, timeout, headers=None)

Return a urllib2 object for uri and timeout and headers. This is better than using urrlib2 directly, for it handles redirects, makes sure URI is utf8, and is shorter and easier to use. Modules may use this if they need a urllib2 object to execute .read() on. For more information, refer to the urllib2 documentation.

willie.web.head(uri, timeout=20, headers=None)

Execute an HTTP GET query on uri, and return the headers. timeout is an optional argument, which represents how much time we should wait before throwing a timeout exception. It defualts to 20, but can be set to higher values if you are communicating with a slow web application.

willie.web.post(uri, query, limit_bytes=None)

Execute an HTTP POST query. uri is the target URI, and query is the POST data. headers is a dict of HTTP headers to send with the request.

If limit_bytes is provided, only read that many bytes from the URL. This may be a good idea when reading from unknown sites, to prevent excessively large files from being downloaded.

willie.web.quote(string)

Like urllib2.quote but handles unicode properly

willie.web.urlencode(data)

Identical to urllib.urlencode. Use this if you already importing web in your module and don’t want to import urllib just to use the urlencode function.

willie.tools

Availability: 3+ tools contains a number of useful miscellaneous tools and shortcuts for use in Willie modules.

tools.py - Willie misc tools Copyright 2008, Sean B. Palmer, inamidst.com Copyright © 2012, Elad Alfassa <elad@fedoraproject.org> Copyright 2012, Edward Powell, embolalia.net Licensed under the Eiffel Forum License 2.

https://willie.dftba.net

class willie.tools.Ddict(default=None)

A simple helper class to ease the creation of multi-dimensional dicts.

class willie.tools.ExpressionEvaluator(bin_ops=None, unary_ops=None)

A generic class for evaluating limited forms of Python expressions.

Instances can overwrite binary_ops and unary_ops attributes with dicts of the form {ast.Node, function}. When the ast.Node being used as key is found, it will be evaluated using the given function.

class willie.tools.Nick

A unicode subclass which acts appropriately for an IRC nickname. When used as normal unicode objects, case will be preserved. However, when comparing two Nick objects, or comparing a Nick object with a unicode object, the comparison will be case insensitive. This case insensitivity includes the case convention conventions regarding [], {}, |, \, ^ and ~ described in RFC 2812.

lower()

Return nick, converted to lower-case per RFC 2812

class willie.tools.OutputRedirect(logpath, stderr=False, quiet=False)

A simplified object used to write to both the terminal and a log file.

write(string)

Write the given string to the logfile and terminal.

class willie.tools.PriorityQueue(maxsize=0)

A priority queue with a peek method.

peek()

Return a copy of the first element without removing it.

class willie.tools.WillieMemory(*args)

Availability: 4.0; available as ``Willie.WillieMemory`` in 3.1.0 - 3.2.0

A simple thread-safe dict implementation. In order to prevent exceptions when iterating over the values and changing them at the same time from different threads, we use a blocking lock on __setitem__ and contains.

contains(key)

Backwards compatability with 3.x, use in operator instead

lock()

Lock this instance from writes. Useful if you want to iterate

unlock()

Release the write lock

willie.tools.check_pid(pid)

Availability: Only on POSIX systems

Return True if there is a process running with the given PID.

willie.tools.eval_equation = <willie.tools.ExpressionEvaluator instance at 0x1963670>

Evaluates a Python equation expression and returns the result.

Supports addition (+), subtraction (-), multiplication (*), division (/), power (**) and modulo (%).

willie.tools.get_command_regexp(prefix, command)

Return a compiled regexp object that implements the command.

willie.tools.get_raising_file_and_line(tb=None)

Return the file and line number of the statement that raised the tb

Returns: (filename, lineno) tuple

class willie.tools.released(lock)

A context manager that releases a lock temporarily.

willie.tools.stderr(string)

Print the given string to stderr. This is equivalent to print >> sys.stderr, string

willie.tools.verify_ssl_cn(server, port)

Availability: Must have the OpenSSL Python module installed.

Verify the SSL certificate given by the server when connecting on the given port. This returns None if OpenSSL is not available or ‘NoCertFound’ if there was no certificate given. Otherwise, a two-tuple containing a boolean of whether the certificate is valid and the certificate information is returned.

willie.module

This module is meant to be imported from willie modules.

It defines the following decorators for defining willie callables: willie.module.rule willie.module.thread willie.module.name (deprecated) willie.module.commands willie.module.nickname_commands willie.module.priority willie.module.event willie.module.rate willie.module.example

willie/module.py - Willie IRC Bot (http://willie.dftba.net/) Copyright 2013, Ari Koivula, <ari@koivu.la> Copyright © 2013, Elad Alfassa <elad@fedoraproject.org>

Licensed under the Eiffel Forum License 2.

willie.module.NOLIMIT = 1

Return value for callables, which supresses rate limiting for the call.

Avalability: 4.0+; available as ``Willie.NOLIMIT`` in 3.2

Returning this value means the triggering user will not be prevented from triggering the command again within the rate limit. This can be used, for example, to allow a user to rety a failed command immediately.

willie.module.commands(*command_list)

Decorator. Sets a command list for a callable.

This decorator can be used to add multiple commands to one callable in a single line. The resulting match object will have the command as the first group, rest of the line, excluding leading whitespace, as the second group. Parameters 1 through 4, seperated by whitespace, will be groups 3-6.

Args:
command: A string, which can be a regular expression.
Returns:
A function with a new command appended to the commands attribute. If there is no commands attribute, it is added.
Example:
@command(“hello”):
If the command prefix is ”.”, this would trigger on lines starting with ”.hello”.
@commands(‘j’, ‘join’)
If the command prefix is ”.”, this would trigger on lines starting with either ”.j” or ”.join”.
willie.module.event(value)

Decorator. Equivalent to func.event = value.

This is one of a number of events, such as ‘JOIN’, ‘PART’, ‘QUIT’, etc. (More details can be found in RFC 1459.) When the Willie bot is sent one of these events, the function will execute. Note that functions with an event must also be given a rule to match (though it may be ‘.*’, which will always match) or they will not be triggered.

class willie.module.example(msg, result=None, privmsg=False, admin=False, owner=False, repeat=1, re=None)

Decorator. Add an example attribute into a function and generate a test.

willie.module.interval(*args)

Decorator. Equivalent to func.interval.append(value)

A function that uses this decorator will be called every X seconds, where X is the argument. This decorator can be used multiple times for multiple intervals, or all intervals can be given at once as arguments. The first time the function will be called is X seconds after the bot was started.

For the callable, the first argument will be the bot itself, but it will not have the say, reply or action methods as would be the case when called due to rule or command.

There is no guarantee that the bot is connected to a server or joined a channel when the function is called, so care must be taken.

Example::

import willie.module
@willie.module.interval(5)
def spam_every_5s(bot):
    if "#here" in bot.channels:
        bot.msg("#here", "It has been five seconds!")
willie.module.name(value)

Decorator. Equivalent to func.name = value.

This attribute is considered deprecated in 3.1.

willie.module.nickname_commands(*command_list)

Decorator. Triggers on lines starting with “$nickname: command”.

This decorator can be used multiple times to add multiple rules. The resulting match object will have the command as the first group, rest of the line, excluding leading whitespace, as the second group. Parameters 1 through 4, seperated by whitespace, will be groups 3-6.

Args:
command: A string, which can be a regular expression.
Returns:
A function with a new regular expression appended to the rule attribute. If there is no rule attribute, it is added.
Example:
@nickname_commands(“hello!”):
Would trigger on “$nickname: hello!”, “$nickname, hello!”, “$nickname hello!”, “$nickname hello! parameter1” and “$nickname hello! p1 p2 p3 p4 p5 p6 p7 p8 p9”.
@nickname_commands(”.*”):
Would trigger on anything starting with “$nickname[:,]? ”, and would have never have any additional parameters, as the command would match the rest of the line.
willie.module.priority(value)

Decorator. Equivalent to func.priority = value.

Args:
value: Priority can be one of “high”, “medium”, “low”. Defaults to
medium.

Priority allows you to control the order of callable execution, if your module needs it.

willie.module.rate(value)

Decorator. Equivalent to func.rate = value.

Availability: 2+

This limits the frequency with which a single user may use the function. If a function is given a rate of 20, a single user may only use that function once every 20 seconds. This limit applies to each user individually. Users on the admin list in Willie’s configuration are exempted from rate limits.

willie.module.rule(value)

Decorator. Equivalent to func.rule.append(value).

This decorator can be used multiple times to add more rules.

Args:
value: A regular expression which will trigger the function.

If the Willie instance is in a channel, or sent a PRIVMSG, where a string matching this expression is said, the function will execute. Note that captured groups here will be retrievable through the Trigger object later.

Inside the regular expression, some special directives can be used. $nick will be replaced with the nick of the bot and , or :, and $nickname will be replaced with the nick of the bot.

Prior to 3.1, rules could also be made one of three formats of tuple. The values would be joined together to form a singular regular expression. However, these kinds of rules add no functionality over simple regular expressions, and are considered deprecated in 3.1.

willie.module.thread(value)

Decorator. Equivalent to func.thread = value.

Args:
value: Either True or False. If True the function is called in
a separate thread. If False from the main thread.
willie.module.unblockable(function)

Decorator. Equivalent to func.unblockable = True

If this decorator is used, the function will be called, even if the bot has been configured to ignore commands from the user. This can be used to ensure events such as JOIN are always recorded.