Welcome to FatBotSlim’s documentation!¶
Introduction¶
About FatBotSlim¶
Author: | Mathieu D. (MatToufoutu) |
---|---|
Contact: | mattoufootu[at]gmail.com |
Homepage: | https://github.com/mattoufoutu/fatbotslim |
Documentation: | http://fatbotslim.rtfd.org |
Issue tracker: | https://github.com/mattoufoutu/fatbotslim/issues |
Git clone URI: | https://github.com/mattoufoutu/fatbotslim.git |
FatBotSlim is an asynchronous IRC bot library written in Python using the gevent library.
A FatBotSlim bot consists of a bot object to which handlers are registered to make it react to events. When triggered, the handlers’ methods are called asynchronously, therefore you don’t have to worry about time-consuming operations that could block your code execution.
Usage¶
Tutorials¶
Writing a simple bot¶
In this tutorial, we’ll take the code from the README.md and explain what happens, it is a bot that answers Hello <username>! when someone says !hello in a public message.
The code¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | from fatbotslim.cli import make_bot, main
from fatbotslim.handlers import CommandHandler, EVT_PUBLIC
class HelloCommand(CommandHandler):
triggers = {
u'hello': [EVT_PUBLIC],
}
def hello(self, msg):
self.irc.msg(msg.dst, u"Hello {0}!".format(msg.src.name))
bot = make_bot()
bot.add_handler(HelloCommand)
main(bot)
|
Explanations¶
Imports:¶
Line 1:
We import 2 functions, fatbotslim.cli.make_bot() and fatbotslim.cli.main(), both are useful when dealing with a bot that will connect to only one server.
The fatbotslim.cli.make_bot() function takes care of gathering the command line options, which are used to create a fatbotslim.irc.IRC instance, and then returns it.
The fatbotslim.cli.main() function is there to spawn the bot in a greenlet (see gevent’s documentation for details about this) and run the main loop for you.
Line 2:
Here we import the fatbotslim.handlers.CommandHandler that will be used to make the bot react to the !hello command and the EVT_PUBLIC variable, which is used to define
The handler:¶
Lines 5-7:
The triggers attribute is a dict used to define to which commands and on which type of events the bot should react. It consists of command names mapped to a tuple listing events. If we wanted the bot to react to !hello both in public and private messages, the value would have been (‘public’, ‘private’).
Lines 9-10:
This is the method that will be called when the !hello command will be triggered, it must have the same name as defined in triggers and takes two arguments, the first is the instance of the fatbotslim.irc.bot.Message that triggered the command, and the second is an instance of fatbotslim.irc.bot.IRC which is used to communicate back with the server.
Starting the bot:¶
Line 12:
Nothing to explain here, the fatbotslim.cli.make_bot() function is already described in the imports part.
Line 13:
The previously created handler is instanciated and added to the bot’s handlers.
Line 14:
The bot is passed to the fatbotslim.cli.main() function, which will take care of
Writing a multi-server bot¶
In this tutorial, we’ll take the code from the “simple bot” tutorial, and make it run on multiple servers.
The code¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | from fatbotslim.irc.bot import IRC, run_bots
from fatbotslim.handlers import CommandHandler, EVT_PUBLIC
class HelloCommand(CommandHandler):
triggers = {
u'hello': [EVT_PUBLIC],
}
def hello(self, msg):
self.irc.msg(msg.dst, u"Hello {0}!".format(msg.src.name))
servers = [
{
'server': 'irc.rizon.net',
'port': 6697,
'ssl': True,
'nick': 'fatbotslim',
'realname': 'fatbotslim',
'channels': ['#testbot']
},
{
'server': 'irc.freenode.net',
'port': 6697,
'ssl': True,
'nick': 'fatbotslim',
'realname': 'fatbotslim',
'channels': ['#testbot']
}
]
bots = []
for server in servers:
bot = IRC(server)
bot.add_handler(HelloCommand)
bots.append(bot)
run_bots(bots)
|
Explanations¶
Imports¶
Line 1:
The fatbotslim.irc.bot.IRC class will be used to instanciate and configure our bots. And the fatbotslim.irc.bot.run_bots() will allow us to run all our bots in parallel.
Configuration¶
Lines 12-29:
Instead of having our settings passed via the command line, we create a dict for each server our bot will connect to.
Running the bots¶
Lines 31-35:
Here we create a list to hold our fatbotslim.irc.bot.IRC instances. We loop over each server configuration, and use them in our bots instanciations.
Line 37:
The fatbotslim.irc.bot.run_bots() function takes a list of bots as argument, and launches each one’s main loop in a greenlet.
Creating custom handlers¶
Note
Internally, all processed data are unicode strings. If you need to decode strings, you can use the provided fatbotslim.irc.u() function.
Basic handlers¶
Basic handlers simply react to IRC events by calling methods mapped to them, they are subclasses of fatbotslim.handlers.BaseHandler.
Events are mapped to methods names in the handler’s commands attribute, which is a dict where the key is an IRC event as defined in the fatbotslim.irc.codes module and the value is the name of the method to call. The mapped methods take just one attribute, the fatbotslim.irc.bot.Message object which triggered the event. To communicate back to the server, use the handler’s irc (which is a fatbotslim.bot.IRC instance).
A good example of a custom handler is FatBotSlim’s integrated fatbotslim.handlers.CTCPHandler:
class CTCPHandler(BaseHandler):
"""
Reacts to CTCP events (VERSION,SOURCE,TIME,PING). (enabled by default)
"""
commands = {
CTCP_VERSION: 'version',
CTCP_SOURCE: 'source',
CTCP_TIME: 'time',
CTCP_PING: 'ping'
}
def version(self, msg):
self.irc.ctcp_reply(
u'VERSION', msg.src.name,
u'{0}:{1}:{2}'.format(NAME, VERSION, platform.system())
)
def source(self, msg):
self.irc.ctcp_reply(
u'SOURCE', msg.src.name,
u'https://github.com/mattoufoutu/fatbotslim'
)
self.irc.ctcp_reply(u'SOURCE', msg.src.name)
def time(self, msg):
now = datetime.now().strftime(u'%a %b %d %I:%M:%S%p %Y %Z').strip()
self.irc.ctcp_reply(u'TIME', msg.src.name, now)
def ping(self, msg):
self.irc.ctcp_reply(u'PING', msg.src.name, u' '.join(msg.args))
Another, simpler, basic handler is the integrated fatbotslim.handlers.PingHandler, this one simply answers to server’s PINGs:
class PingHandler(BaseHandler):
"""
Answers to PINGs sent by the server. (enabled by default)
"""
commands = {
PING: 'ping'
}
def ping(self, msg):
self.irc.cmd(u'PONG', u' '.join(msg.args))
Command handlers¶
The fatbotslim.handlers.CommandHandler is a special kind of handler that reacts only to PRIVMSG and NOTICE messages, they are used to implement !foo-like commands to your bot.
The prefix character is defined by the handler’s trigger_char attribute, and defaults to !.
Commands are defined in the handler’s triggers attribute, a dict that maps method names to events they should react to. Possible events are EVT_PUBLIC, EVT_PRIVATE, and EVT_NOTICE. The methods take just 1 argument, the first is a fatbotslim.irc.bot.Message object, and the second is a fatbotslim.irc.bot.IRC object used to send messages back to the server.
For example, the message !foo bar would call the handler’s foo() method.
Here is a command handler that says hello when it receives !hello in public:
from fatbotslim.handlers import CommandHandler, EVT_PUBLIC
class HelloCommand(CommandHandler):
triggers = {
u'hello': [EVT_PUBLIC],
}
def hello(self, msg):
self.irc.msg(msg.dst, u"Hello, {0}!".format(msg.src.name))
If you wanted the handler to answer also to private messages, you would simply have to add ‘private’ to the “hello” event list and set the answer destination accordingly:
from fatbotslim.handlers import CommandHandler, EVT_PUBLIC, EVT_PRIVATE
class HelloCommand(CommandHandler):
triggers = {
u'hello': [EVT_PUBLIC, EVT_PRIVATE],
}
def hello(self, msg):
dst = msg.src.name if (msg.dst == irc.nick) else msg.dst
self.irc.msg(dst, u"Hello {0}!".format(msg.src.name))
Utilities¶
Commands Help¶
If you want to have help messages for your handlers’ commands automatically generated, fatbotslim provides a convenience handler.
The fatbotslim.handlers.HelpHandler provides two kind of help messages, one that simply lists available commands when !help is called (assuming ! is your current trigger_char), and one that displays the command’s docstring when help [command] is called.
To use this feature, simply document your commands’ docstrings (try to keep a consistent format across all your docstrings), and add the handler to your bot.
from fatbotslim.cli import make_bot, main
from fatbotslim.handlers import CommandHandler, HelpHandler, EVT_PUBLIC
class HelloCommand(CommandHandler):
triggers = {
u'hello': [EVT_PUBLIC],
}
def hello(self, msg):
"""hello - says hello"""
self.irc.msg(msg.dst, u"Hello {0}!".format(msg.src.name))
def say(self, msg):
"""say <message> - simply repeats the message"""
self.irc.msg(msg.dst, ' '.join(msg.args[1:]))
bot = make_bot()
bot.add_handler(HelpHandler)
bot.add_handler(HelloCommand)
main(bot)
Given the previous code, if one called !help, the bot would answer:
Available commands: hello, say
and if one called !help say, the bot would answer:
say <message> - simply repeats the message
Colored Messages¶
To send colored messages, you can use the fatbotslim.irc.colors.ColorMessage class. It mimics strings behaviour, and thus allows to call string methods on it.
from fatbotslim.irc.colors import ColorMessage
message = ColorMessage('sOmE rAnDoM tExT', color='blue')
message = ColorMessage('sOmE rAnDoM tExT', color='blue', bold=True)
message = ColorMessage('sOmE rAnDoM tExT', color='blue', underline=True)
message = ColorMessage('sOmE rAnDoM tExT', color='blue', highlight=True)
upper_message = message.upper()
title_message = message.title()
Available colors are:
- blue
- brown
- dark_green
- magenta
- purple
- dark_grey
- light_grey
- yellow
- black
- teal
- cyan
- olive
- green
- white
- dark_blue
- red
If no color is specified when instanciating fatbotslim.irc.colors.ColorMessage, the value defaults to “black”.
Rights Management¶
FatBotSlim provides a built-in handler (fatbotslim.handlers.RightsHandler) to manage who should be allowed to run specific commands. It allows to define which users can run which commands, and on which event(s) type(s).
This special handler is automatically enabled, and is accessible through the fatbotslim.irc.bot.IRC.rights attribute. It can be permanently disabled using the fatbotslim.irc.bot.IRC.enable_rights() method, and can be re-enabled using the fatbotslim.irc.bot.IRC.disable_rights() method.
Settings permissions¶
Adding a new permission is done using the fatbotslim.irc.bot.IRC.rights.set_restriction() method.
For example, to restrict usage of the hello command to a user named LeetUser in public messages, the following code should be used (assuming bot is the fatbotslim.irc.bot.IRC instance:
bot.rights.set_permission('hello', 'LeetUser', [EVT_PUBLIC])
Once this is done, only LeetUser will be allowed to use the hello command, and only in public messages.
Global rights can also be set using * as the username. In the following example, LeetUser would be allowed to use the hello command in private messages only, and all the other users would be allowed to use it in public messages and notices only.
bot.rights.set_restriction('hello', 'LeetUser', [EVT_PRIVATE])
bot.rights.set_restriction('hello', '*', [EVT_PUBLIC, EVT_NOTICE])
Removing permissions¶
Removing a permission is done using the fatbotslim.irc.bot.IRC.rights.del_restriction() method.
The following code snippet would remove the previously set permission for LeetUser.
bot.rights.del_restriction('hello', 'LeetUser', [EVT_PRIVATE])
Only given event(s) type(s) are removed from the permission, so, if LeetUser was previously allowed to use the hello command in public messages too, it would still have the right to.
API Reference¶
fatbotslim.irc¶
fatbotslim.irc.bot¶
This module contains IRC protocol related stuff.
- class fatbotslim.irc.bot.IRC(settings)[source]¶
The main IRC bot class.
The only expected argument is the bot’s configuration, it should be a dict with at least the following keys defined:
- server: the ircd’s host (str)
- port: the ircd’s port (int)
- ssl: connect to the server using SSL (bool)
- channels: the channels to join upon connection (list)
- nick: the bot’s nickname (str)
- realname: the bot’s real name (str)
Parameters: settings (dict) – bot configuration. - add_handler(handler, args=None, kwargs=None)[source]¶
Registers a new handler.
Parameters: - handler (fatbotslim.handlers.BaseHandler) – handler to register.
- args (list) – positional arguments to pass to the handler’s constructor.
- kwargs (dict) – keyword arguments to pass to the handler’s constructor.
- cmd(command, args, prefix=None)[source]¶
Sends a command to the server.
Parameters: - command (unicode) – IRC code to send.
- args (basestring) – arguments to pass with the command.
- prefix (str or None) – optional prefix to prepend to the command.
- disable_rights()[source]¶
Disables rights management provided by fatbotslim.handlers.RightsHandler.
- enable_rights()[source]¶
Enables rights management provided by fatbotslim.handlers.RightsHandler.
- notice(target, msg)[source]¶
Sends a NOTICE to an user or channel.
Parameters: - target (str) – user or channel to send to.
- msg (basestring) – message to send.
- class fatbotslim.irc.bot.Message(data)[source]¶
Holds informations about a line received from the server.
Parameters: data (unicode) – line received from the server.
- exception fatbotslim.irc.bot.NullMessage[source]¶
Raised when an empty line is received from the server.
fatbotslim.irc.tcp¶
This module contains the low-level networking stuff.
- class fatbotslim.irc.tcp.SSL(host, port, timeout=300)[source]¶
SSL wrapper for a fatbotslim.irc.tcp.TCP connection.
Parameters:
fatbotslim.irc.codes¶
This module lists the known IRC codes as defined in the RFC 1459.
—
It also defines some custom codes:
RPL_CONNECTED (001): Connection established with the server.
RPL_SERVERVERSION (002): Server’s name/version.
RPL_SERVERCREATED (003): Server’s creation date.
RPL_SERVERMODES (004): Modes supported by the server.
RPL_ISUPPORT (005): Protocol extensions supported by the server.
CTCP_VERSION, CTCP_PING, CTCP_TIME, CTCP_SOURCE: self-explanatory.
PING, PRIVMSG, NOTICE, JOIN, PART: self-explanatory.
—
Codes are also grouped by type to make matching them easier:
ERRORS, RESPONSES, RESERVED, CTCP, OTHERS
—
There are also 2 special code sets:
ALL_CODES: Matches any code if listed in the groups previously mentionned.
UNKNOWN_CODE: Matches any code not listed in ALL_CODES.
fatbotslim.irc.colors¶
This module provides message colors capabilities.
- class fatbotslim.irc.colors.ColorMessage(content, color='black', bold=False, underline=False, highlight=False)[source]¶
Allows to create colorized strings. Created objects behave like real strings, allowing to call str methods.
Parameters:
fatbotslim.cli¶
This module contains utilities to run a bot from the command line.
- fatbotslim.cli.main(bot)[source]¶
Entry point for the command line launcher.
Parameters: bot (fatbotslim.irc.bot.IRC) – the IRC bot to run
- fatbotslim.cli.make_parser()[source]¶
Creates an argument parser configured with options to run a bot from the command line.
Returns: configured argument parser Return type: argparse.ArgumentParser
fatbotslim.handlers¶
This module contains a collection of handlers to react to basic IRC events and allow creation of custom handlers.
- class fatbotslim.handlers.BaseHandler(irc)[source]¶
The base of every handler.
A handler should at least have a commands attribute of type dict which maps IRC codes (as defined in fatbotslim.irc.codes) to methods.
Mapped methods take 1 argument, the fatbotslim.irc.bot.Message object that triggered the event.
- class fatbotslim.handlers.CommandHandler(irc)[source]¶
The CommandHandler is a special kind of handler that eases the creation of bots that react to prefixed commands (like !command). It only reacts to PRIVMSG and NOTICE messages.
The prefix character is defined by the handler’s trigger_char attribute, and defaults to !.
Commands are defined in the handler’s triggers attribute, a dict that maps method names to events to which they should react. Possible events are EVT_PUBLIC, EVT_PRIVATE, and EVT_NOTICE. The methods should take 1 argument, which is the fatbotslim.irc.bot.Message object that triggered the event.
For example, the message !foo bar would call the handler’s foo() method.
Here is a command handler that says hello when it receives !hello in public:
class HelloCommand(CommandHandler): triggers = { 'hello': [EVT_PUBLIC], } def hello(self, msg): self.irc.msg(msg.dst, "Hello, {0}!".format(msg.src.name))
- class fatbotslim.handlers.PingHandler(irc)[source]¶
Answers to PINGs sent by the server. (enabled by default)
- class fatbotslim.handlers.CTCPHandler(irc)[source]¶
Reacts to CTCP events (VERSION,SOURCE,TIME,PING). (enabled by default)
- class fatbotslim.handlers.UnknownCodeHandler(irc)[source]¶
Logs messages for which the IRC code is unknown. (enabled by default)
- class fatbotslim.handlers.HelpHandler(irc)[source]¶
Provides automatic help messages for fatbotslim.handlers.CommandHandler commands.
- class fatbotslim.handlers.RightsHandler(irc)[source]¶
Provides rights management for fatbotslim.handlers.CommandHandler commands.
- del_restriction(command, user, event_types)[source]¶
Removes restriction for given command.
Parameters:
fatbotslim.log¶
This module contains everything useful to enable logging.
- class fatbotslim.log.ColorFormatter(fmt=None, datefmt=None)[source]¶
A logging formatter that displays the loglevel with colors and the logger name in bold.
Initialize the formatter with specified format strings.
Initialize the formatter either with the specified format string, or a default as described above. Allow for specialized date formatting with the optional datefmt argument (if omitted, you get the ISO8601 format).