Interact with the bot¶
Once a Rule has been triggered, it’s time to do whatever the plugin is
supposed to do. Thanks to the
bot parameter, you can make the bot talk:
say something in a channel, reply to someone, send a notice, or join a channel.
The most basic way to make the bot talk is to use its
say() method. The wrapper knows the origin of
the trigger (a channel or a private message), and it will use this origin as
the default destination for your message:
# will send that to trigger.sender bot.say('The bot is now talking!')
If you want to send the message to another destination, you can pass it as the second argument:
bot.say('The bot is now talking!', '#private-channel')
Instead of a string, you can use an instance of
If you want to reply to a user in a private message, you can use the trigger’s
nick attribute as destination:
bot.say('I reply in private message', trigger.nick)
And if you want to send a private message to the bot’s owner every time your rule is triggered, you can use the bot’s settings:
bot.say('Hi owner!', bot.settings.core.owner)
say method sends a
PRIVMSG command to the IRC server. To send
NOTICE command instead, you need to use the
notice() method instead.
Now maybe you want to make sure the user gets notified by the bot’s message.
For that, you could use
trigger.nick this way:
bot.say('%s: ping!' % trigger.nick)
It’ll work fine and it’s a common usage. So common indeed that Sopel provides a shortcut for that:
As with the
say method seen above, the
method can send your message to another destination:
Also, if you want to reply to someone else, you can do that too by using
In that example, we send a message on the same channel, with a highlight to the bot’s owner.
By default the
reply method sends its message using a
command. You can set
notice=True as argument to make it use a
NOTICE command instead:
Besides talking, the bot can also act:
Oh, and let’s not forget about
/me does something, which can be done with
When the bot talks, replies, or acts, it can do so with style: colors,
bold, italic, underline, strikethrough, or
monospace. IRC formatting works with control codes, bytes you can use to
tell IRC clients how to display some part of the text.
If you want to know more about IRC formatting in general and some of its limitations, the modern IRC documentation may be of interest to you.
However, dealing with control codes yourself is not the most dev-friendly
approach, hence the
sopel.formatting module. It contains various
functions to help you create styled text.
Let’s dive into examples, starting with
from sopel import formatting bot.say(formatting.bold('This is some bold text!'))
This will output a line like this:
<Sopel> This is some bold text!
You can use them with Python string formatting:
emphasis = formatting.bold('important') bot.say('And here is the %s part.' % emphasis)
To get that kind of output:
<Sopel> And here is the important part.
And you can use multiple style functions together, for example with the
word = formatting.italic('very') emphasis = formatting.bold('%s important' % word) bot.say('And here is the %s part.' % emphasis)
To get a result that looks like this:
<Sopel> And here is the very important part.
color function takes a line of text and a foreground color. It also
accepts an optional background color that uses the same color codes. The color
codes are listed by the
colors class, and can be used like this:
bot.say(formatting.color('Red text.', formatting.colors.RED))
The above example should produce this output:
<Sopel> Red text.
You can combine colors and styles, like this:
big = formatting.color( formatting.bold('WARNING'), formatting.colors.RED) small = formatting.italic('warning') bot.say('[%s] This is a %s.' % (big, small))
So you get a similar result as:
<Sopel> [WARNING] This is a warning.
If you want to prevent spoilers, you could be tempted to take advantage of the background color:
spoiler = formatting.color( 'He was the killer.', formatting.colors.BLACK, formatting.colors.BLACK, ) bot.say(spoiler)
And expect this (you need to select the text to read it):
<Sopel> He was the killer.
Note that not all combinations of foreground and background colors are happy ones, and you should be mindful of using too many unnecessary colors.
Knowing how to talk is good for a bot, but you may be wondering what the bot
knows about the channels and their users. For that, you can use the bot’s
For example, to list all channels the bot is in:
for name, channel in bot.channels.items(): # do something with the name and the channel
Sopel doesn’t know about channels it didn’t join first, and it forgets everything about a channel when it leaves.
To get a channel’s information, you need to know its name, with its channel
#), such as this:
channel = bot.channels['#channel_name']
trigger object, you can also access the channel object directly
(assuming the message comes from a channel, which you should check first):
channel = bot.channels[trigger.sender]
channel object is an instance of
which provides the following information:
To check if a message comes from a channel, you have two options:
To get a list of users in a channel, you can use its
users attribute: this is a map of users you
can iterate over to get all the users:
for nick, user in channel.users.items(): # do something with the nick and the user
You can access one user in a channel with its nick:
user = channel.users['Nickname']
trigger object, you can also access the user object directly:
user = channel.users[trigger.nick]
Once you have a user’s nick (either from the trigger or directly) and a
channel, you can get that user’s privileges through the channel’s
user_privileges = channel.privileges['Nickname'] user_privileges = channel.privileges[trigger.nick]
You can check the user’s privileges manually using bitwise operators. Here for example, we check if the user is voiced (+v) or above:
from sopel import plugin if user_privileges & plugin.VOICED: # user is voiced elif user_privileges > plugin.VOICED: # not voiced, but higher privileges # like plugin.HALFOP or plugin.OP else: # no privilege
Another option is to use dedicated methods from the
if channel.is_voiced('Nickname'): # user is voiced elif channel.has_privileges('Nickname', plugin.VOICED): # not voiced, but higher privileges # like plugin.HALFOP or plugin.OP else: # no privilege
You can also iterate over the list of users and filter them by privileges:
# get users with the OP privilege op_users = [ user for nick, user in channel.users if channel.is_op(nick, plugin.OP) ] # get users with OP privilege or above op_or_higher_users = [ user for nick, user in channel.users if channel.has_privileges(nick, plugin.OP) ]