Callable decorators#
sopel.plugin#
This contains decorators and other tools for creating Sopel plugins.
- sopel.plugin.NOLIMIT = 1#
Return value for
callable
s, which suppresses rate limiting.Returning this value means the triggering user will not be prevented from triggering the same callable again within the rate limit. This can be used, for example, to allow a user to retry a failed command immediately.
New in version 4.0.
- sopel.plugin.action_command(*command_list: str) Callable #
Decorate a function to trigger on CTCP ACTION lines.
- Parameters:
command_list – one or more command name(s) to match
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; the rest of the line, excluding leading whitespace, as the second group; and parameters 1 through 4, separated by whitespace, as groups 3-6.
Example:
@action_command("hello!") # Would trigger on "/me hello!"
New in version 7.0.
Note
The command name will be escaped for use in a regular expression. As such it is not possible to use something like
/me command\d+
to catch something like/me command1
or/me command2
.You have several options at your disposal to replace a regex in the command name:
use a command alias
parse the arguments with your own regex within your plugin callable
use a
rule()
The
rule()
must be used with thectcp()
decorator:@rule(r'hello!?') @ctcp('ACTION') # Would trigger on "/me hello!" and "/me hello"
- sopel.plugin.action_commands(*command_list: str) Callable #
Alias to
action_command()
.
- sopel.plugin.allow_bots(function: Callable | None = None) Callable #
Decorate a function to specify that it should receive events from bots.
On networks implementing the Bot Mode specification, messages and other events from other clients that have identified themselves as bots will be tagged as such, and Sopel will ignore them by default. This decorator allows a function to opt into receiving these events.
- sopel.plugin.command(*command_list: str) Callable #
Decorate a function to set one or more commands that should trigger it.
- Parameters:
command_list – one or more command name(s) to match
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; the rest of the line, excluding leading whitespace, as the second group; and parameters 1 through 4, separated by whitespace, as groups 3-6.
Example:
@command("hello") # If the command prefix is "\.", this would trigger on lines # starting with ".hello". @command('j', 'join') # If the command prefix is "\.", this would trigger on lines # starting with either ".j" or ".join".
You can use a space in the command name to implement subcommands:
@command('main sub1', 'main sub2') # For ".main sub1", trigger.group(1) will return "main sub1" # For ".main sub2", trigger.group(1) will return "main sub2"
But in that case, be careful with the order of the names: if a more generic pattern is defined first, it will have priority over less generic patterns. So for instance, to have
.main
and.main sub
working properly, you need to declare them like this:@command('main sub', 'main') # This command will react properly to ".main sub" and ".main"
Then, you can check
trigger.group(1)
to know if it was used asmain sub
or justmain
in your callable. If you declare them in the wrong order,.main
will have priority and you won’t be able to take advantage of that.Another option is to declare command with subcommands only, like this:
@command('main sub1') # this command will be triggered on .main sub1 @command('main sub2') # this other command will be triggered on .main sub2
In that case,
.main
won’t trigger anything, and you won’t have to inspect the trigger’s groups to know which subcommand is triggered.Note
If you use this decorator multiple times, remember that the decorators are invoked in the reverse order of appearance:
# These two decorators... @command('hi') @command('hello') # ...are equivalent to this single decorator @command('hello', 'hi')
See also the Function Definitions chapter from the Python documentation for more information about functions and decorators.
Note
The command name will be escaped for use in a regular expression. As such it is not possible to use something like
.command\d+
to catch something like.command1
or.command2
.You have several options at your disposal to replace a regex in the command name:
use a command alias
parse the arguments with your own regex within your plugin callable
use a
rule()
instead
- sopel.plugin.ctcp( ) Callable #
Decorate a callable to trigger on CTCP commands (mostly,
ACTION
).- Parameters:
command_list – one or more CTCP command(s) on which to trigger
There are various CTCP commands to handle with this decorator, such as
ACTION
,CLIENTINFO
,TIME
, andVERSION
:from sopel import plugin @plugin.ctcp('TIME') @plugin.rule('.*') def ctcp_time(bot, trigger): bot.say('Sorry, not a clock.')
This decorator also works without parentheses, in which case it will trigger on CTCP
ACTION
:from sopel import plugin @plugin.ctcp @plugin.rule('.*') def ctcp_action(bot, trigger): bot.reply('Why would you do that?!')
New in version 7.1: This is now
ctcp
instead ofintent
, and it can be called without argument, in which case it will assumeACTION
.Note
This used to be
@intent
, for a long dead feature in the IRCv3 spec. It is now replaced by@ctcp
, which can be used without arguments. In that case, Sopel will assume it should trigger onACTION
.As
sopel.module
will be removed in Sopel 9, so will@intent
.
- sopel.plugin.echo(function: Callable | None = None) Callable #
Decorate a function to specify that it should receive echo messages.
This decorator can be used to listen in on the messages that Sopel is sending and react accordingly.
Important
The decorated callable will receive all matching messages that Sopel sends, including output from the same callable. Take care to avoid creating feedback loops when using this feature.
- sopel.plugin.event(*event_list: str) Callable #
Decorate a function to be triggered on specific IRC events.
- Parameters:
event_list – one or more event name(s) on which to trigger
This is one of a number of events, such as ‘JOIN’, ‘PART’, ‘QUIT’, etc. (More details can be found in RFC 1459.) When the Sopel bot is sent one of these events, the function will execute. Note that the default
rule()
(.*
) will match any line of the correct event type(s). If any rule is explicitly specified, it overrides the default.See also
sopel.tools.events
provides human-readable names for many of the numeric events, which may help your code be clearer.
- class sopel.plugin.example(
- msg: str,
- result: str | Iterable[str] | None = None,
- privmsg: bool = False,
- admin: bool = False,
- owner: bool = False,
- repeat: int = 1,
- re: bool = False,
- ignore: str | Iterable[str] | None = None,
- user_help: bool = False,
- online: bool = False,
- vcr: bool = False,
Decorate a function with an example, and optionally test output.
- Parameters:
msg – the example command (required; see below)
result – the command’s expected output (optional; see below)
privmsg – if
True
, the example will be tested as if it was received in a private message to the bot; otherwise, in a channel (optional; defaultFalse
)admin – whether to treat the test message as having come from a bot admin (optional; default
False
)owner – whether to treat the test message as having come from the bot’s owner (optional; default
False
)repeat – how many times to repeat the test; useful for commands that return random results (optional; default
1
)re – if
True
, theresult
is interpreted as a regular expression and used to match the command’s output (optional; see below)ignore – list of regular expression patterns to match ignored output (optional; see below)
user_help – whether this example should be included in user-facing help output such as .help command (optional; default
False
; see below)online – if
True
,pytest
will mark this example as “online” (optional; defaultFalse
; see below)vcr – if
True
, this example’s HTTP requests & responses will be recorded for later reuse (optional; defaultFalse
; see below)
For compatibility with the built-in help plugin,
msg
must use the defaulthelp_prefix
if it is a prefixed command. Other command types should give example invocations that work with Sopel’s default settings, especially if using the “example test” functionality to automatically generate a test(s) for the function.The presence of a
result
will generate tests automatically when Sopel’s test suite is run, usingmsg
as input. The exact behavior of the tests depends on the remaining optionalexample
arguments.Passing
re=True
, in particular, is useful for matchingresult
s that are random and/or dependent on an external API. This way, an example test can check the format of the result without caring about the exact data.Giving a list of
ignore``d patterns is helpful for commands that may return intermittent errors (mostly calls to an external API that isn't necessarily stable), especially when coupled with the ``repeat
parameter.By default, Sopel’s help plugin will display only one example (the one closest to the function’s def statement, due to how decorators work). You can override this choice or include multiple examples by passing
user_help=True
to one or moreexample
decorator(s).Passing
online=True
makes that particular example skippable if Sopel’s test suite is run in offline mode, which is mostly useful to make life easier for other developers working on Sopel without Internet access.Finally,
vcr=True
records the example’s HTTP requests and responses for replaying during later test runs. It can be an alternative (or complement) toonline
, and is especially useful for testing plugin code that calls on inconsistent or flaky remote APIs. The recorded “cassettes” of responses can be committed alongside the code for use by CI services, etc. (See VCR.py & pytest-vcr)
- sopel.plugin.find(*patterns: str | Pattern) Callable #
Decorate a function to be called for each time a pattern is found in a line.
- Parameters:
patterns – one or more regular expression(s)
Each argument is a regular expression which will trigger the function:
@find('hello', 'here') # will trigger once on "hello you" # will trigger twice on "hello here" # will trigger once on "I'm right here!"
This decorator can be used multiple times to add more rules:
@find('here') @find('hello') # will trigger once on "hello you" # will trigger twice on "hello here" # will trigger once on "I'm right here!"
If the Sopel instance is in a channel, or sent a
PRIVMSG
, the function will execute for each time a received message matches an expression. Each match will also contain the position of the instance it found.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:@find('$nickname') # will trigger for each time the bot's nick is in a trigger
New in version 7.1.
Note
The regex rule will match once for each non-overlapping match, from left to right, and the function will execute for each of these matches.
To match only once from anywhere in the line, use the
search()
decorator instead. To match only once from the start of the line, use therule()
decorator instead.
- sopel.plugin.find_lazy(*loaders: Callable) Callable #
Decorate a callable as a find rule with lazy loading.
- Parameters:
loaders – one or more functions to generate a list of compiled regexes to match patterns in a line
Each
loader
function must accept asettings
parameter and return a list (or tuple) of compiled regular expressions:import re def loader(settings): return [re.compile(r'<your_rule_pattern>')]
It will be called by Sopel when the bot parses the plugin to register the find rules to get its regexes. The
settings
argument will be the bot’ssopel.config.Config
object.If any of the
loader
functions raises aPluginError
exception, the find rule will be ignored; it will not fail the plugin’s loading.The decorated function will behave like any other
callable()
:from sopel import plugin @plugin.find_lazy(loader) def my_find_rule_handler(bot, trigger): bot.say('Rule triggered by: %s' % trigger.group(0))
New in version 7.1.
See also
When more than one loader is provided, they will be chained together with the
sopel.tools.chain_loaders()
function.
- sopel.plugin.interval(*intervals: int | float) Callable #
Decorate a function to be called by the bot every n seconds.
- Parameters:
intervals – one or more duration(s), in seconds
This decorator can be used multiple times for multiple intervals, or multiple intervals can be given in multiple arguments. The first time the function will be called is n seconds after the bot was started.
Plugin functions decorated by
interval
must only takebot
as their argument; they do not get atrigger
. Thebot
argument will not have a context, so functions likebot.say()
will not have a default destination.There is no guarantee that the bot is connected to a server or in any channels when the function is called, so care must be taken.
Example:
from sopel import plugin @plugin.interval(5) def spam_every_5s(bot): if "#here" in bot.channels: bot.say("It has been five seconds!", "#here")
- sopel.plugin.label(value: str) Callable #
Decorate a function to add a rule label.
- Parameters:
value – a label for the rule
The rule label allows the documentation and the logging system to refer to this function by its label. A function can have one and only one label:
@label('on_hello') @rule('hello') # will trigger on hello, and be labelled as "on_hello"
Note
By default, the “label” of a callable will be its function name, which can be confusing for end-users: the goal of the
label
decorator is to make generic rules as user-friendly as commands are, by giving them some name that isn’t tied to an identifier in the source code.
- sopel.plugin.nickname_command(*command_list: str) Callable #
Decorate a function to trigger on lines starting with “$nickname: command”.
- Parameters:
command_list – one or more command name(s) to match
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; the rest of the line, excluding leading whitespace, as the second group; and parameters 1 through 4, separated by whitespace, as groups 3-6.
Example:
@nickname_command("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".
Note
The command name will be escaped to be used in a regex command. As such it is not possible to use something like
command\d+
to catch something likeBot: command1
orBot: command2
.You have several options at your disposal to replace a regex in the command name:
use a command alias
parse the arguments with your own regex within your plugin callable
use a
rule()
The
rule()
can be used with a$nick
variable:@rule(r'$nick .*') # Would trigger on anything starting with "$nickname[:,]? ", # and would never have any additional parameters, as the # command would match the rest of the line.
- sopel.plugin.nickname_commands(*command_list: str) Callable #
Alias to
nickname_command()
.
- sopel.plugin.output_prefix(prefix: str) Callable #
Decorate a function to add a prefix on its output.
- Parameters:
prefix – the prefix to add (must include trailing whitespace if desired; Sopel does not assume it should add anything)
Prefix will be added to text sent through:
- sopel.plugin.priority(value: Literal['low', 'medium', 'high']) Callable #
Decorate a function to be executed with higher or lower priority.
- Parameters:
value – one of
high
,medium
, orlow
The priority allows you some control over the order of callable execution, if your plugin needs it. If a callable does not specify its
priority
, Sopel assumesmedium
.
- sopel.plugin.rate( ) Callable #
Decorate a function to be rate-limited.
- Parameters:
user – seconds between permitted calls of this function by the same user
channel – seconds between permitted calls of this function in the same channel, regardless of triggering user
server – seconds between permitted calls of this function no matter who triggered it or where
message – optional keyword argument; default message sent as NOTICE when a rate limit is reached
How often a function can be triggered on a per-user basis, in a channel, or across the server (bot) can be controlled with this decorator. A value of
0
means no limit. If a function is given a rate of 20, that function may only be used once every 20 seconds in the scope corresponding to the parameter:from sopel import plugin @plugin.rate(10) # won't trigger if used more than once per 10s by a user @plugin.rate(10, 10) # won't trigger if used more than once per 10s by a user/channel @plugin.rate(10, 10, 2) # won't trigger if used more than once per 10s by a user/channel # and never more than once every 2s
If a
message
is provided, it will be used as the default message sent as aNOTICE
to the user who hit the rate limit:@rate(10, 10, 10, message='Hit the rate limit for this function.') # will send a NOTICE
The message can contain placeholders which will be filled in:
nick
: the nick that hit the rate limitchannel
: the channel in which the rate limit was hit (will be'private-message'
for private messages)sender
: the sender (nick or channel) of the message which hit the rate limitplugin
: the name of the plugin that hit the rate limitlabel
: the label of the plugin handler that hit the rate limittime_left
: the time remaining before the rate limit expires, as a stringtime_left_sec
: the time remaining before the rate limit expires, expressed in number of secondsrate_limit
: the rate limit, as a stringrate_limit_sec
: the rate limit, expressed in number of secondsrate_limit_type
: the type of rate limit that was hit (one ofuser, group, global
)
For example:
@rate(10, 10, 2, message='Sorry {nick}, you hit the {rate_limit_type} rate limit!')
Changed in version 8.0: Optional keyword argument
message
was added in Sopel 8.Note
Users on the admin list in Sopel’s configuration are exempted from rate limits.
See also
You can control each rate limit separately, with their own custom message using
rate_user()
,rate_channel()
, orrate_global()
.
- sopel.plugin.rate_channel(rate: int, message: str | None = None) Callable #
Decorate a function to be rate-limited for a channel.
- Parameters:
rate – seconds between permitted calls of this function in the same channel, regardless of triggering user
message – optional; message sent as NOTICE when a user hits the limit
This decorator can be used alone or with the
rate()
decorator, as it will always take precedence:@rate(10, 10, 10) @rate_channel(5, 'You hit the channel rate limit for this function.') # channel limit will be set to 5, other to 10 # will send a NOTICE only when a user hits the channel limit # as other rate limits don't have any message set
If you don’t provide a message, the default message set by
rate()
(if any) will be used instead.The message can contain the same placeholders supported by
rate()
:@rate_channel( 5, 'Sorry {nick}, you hit the {rate_limit_sec}s limit for the {channel} channel!', )
New in version 8.0.
Note
Users on the admin list in Sopel’s configuration are exempted from rate limits.
- sopel.plugin.rate_global(rate: int, message: str | None = None) Callable #
Decorate a function to be rate-limited for the whole server.
- Parameters:
rate – seconds between permitted calls of this function no matter who triggered it or where
message – optional; message sent as NOTICE when a user hits the limit
This decorator can be used alone or with the
rate()
decorator, as it will always take precedence.For example:
@rate(10, 10, 10) @rate_global(5, 'You hit the global rate limit for this function.') # global limit will be set to 5, other to 10 # will send a NOTICE only when a user hits the global limit # as other rate limits don't have any message set
If you don’t provide a message, the default message set by
rate()
(if any) will be used instead.The message can contain the same placeholders supported by
rate()
:@rate_global(5, 'Sorry {nick}, you hit the 5s limit!')
New in version 8.0.
Note
Users on the admin list in Sopel’s configuration are exempted from rate limits.
- sopel.plugin.rate_user(rate: int, message: str | None = None) Callable #
Decorate a function to be rate-limited for a user.
- Parameters:
rate – seconds between permitted calls of this function by the same user
message – optional; message sent as NOTICE when a user hits the limit
This decorator can be used alone or with the
rate()
decorator, as it will always take precedence:@rate(10, 10, 10) @rate_user(20, 'You hit your rate limit for this function.') # user limit will be set to 20, other to 10 # will send a NOTICE only when a user hits their own limit # as other rate limits don't have any message set
The message can contain the same placeholders supported by
rate()
:@rate_user(5, 'Sorry {nick}, you hit your {rate_limit_sec}s limit!')
If you don’t provide a message, the default message set by
rate()
(if any) will be used instead.New in version 8.0.
Note
Users on the admin list in Sopel’s configuration are exempted from rate limits.
- sopel.plugin.require_account( ) Callable #
Decorate a function to require services/NickServ authentication.
- Parameters:
A decorated plugin callable will be triggered only if the triggering user is logged into a network services account:
from sopel import plugin @plugin.command('.regonly') @plugin.require_account('Registered users only.') def logged_in_command(bot, trigger): # trigger only if user is logged in to services
If an unauthenticated user triggers the decorated function, the
message
will be said if given. By default, it usesbot.say()
, but whenreply
isTrue
it usesbot.reply()
instead.This decorator also works without parentheses, if you want its default (no arguments) behavior:
from sopel import plugin @plugin.command('.regonly') @plugin.require_account def logged_in_command(bot, trigger): # trigger only if user is logged in to services
New in version 7.0.
Note
Only some networks support services authentication, and not all of those implement the standards required for clients like Sopel to determine authentication status. This decorator will block all use of functions it decorates on networks that lack the relevant features.
- sopel.plugin.require_admin( ) Callable #
Decorate a function to require the triggering user to be a bot admin.
- Parameters:
A decorated plugin callable will be triggered only if the triggering user is an admin of the bot, according to its configuration:
from sopel import plugin @plugin.command('.adminonly') @plugin.require_admin('Bot admin only command.') def admin_command(bot, trigger): # trigger only if user is a bot admin
The bot’s
owner
is also an admin.When the triggering user is not an admin, the command is not run, and the bot will say the
message
if given. By default, it usesbot.say()
, but whenreply
isTrue
it usesbot.reply()
instead.This decorator also works without parentheses, if you want its default (no arguments) behavior:
from sopel import plugin @plugin.command('.adminonly') @plugin.require_admin def admin_command(bot, trigger): # trigger only if user is a bot admin
Changed in version 7.0: Added the
reply
parameter.
- sopel.plugin.require_bot_privilege(
- level: AccessLevel,
- message: str | None = None,
- reply: bool = False,
Decorate a function to require a minimum channel privilege for the bot.
- Parameters:
level
can be one of the privilege level constants defined in this module. If the bot does not have the privilege, the bot will saymessage
if given. By default, it usesbot.say()
, but whenreply
isTrue
it usesbot.reply()
instead.Use of
require_bot_privilege()
impliesrequire_chanmsg()
.New in version 7.1.
Changed in version 8.0: Decorated callables no longer run in response to private messages.
- sopel.plugin.require_chanmsg( ) Callable #
Decorate a function to only be triggerable from a channel message.
- Parameters:
A decorated plugin callable will be triggered only by messages from a channel:
from sopel import plugin @plugin.command('.mtopic') @plugin.require_chanmsg('Channel only command.') def manage_topic(bot, trigger): # trigger on channel messages only
If the decorated function is triggered by a private message, the
message
will be said if given. By default, it usesbot.say()
, but whenreply
isTrue
it usesbot.reply()
instead.This decorator also works without parentheses, if you want its default (no arguments) behavior:
from sopel import plugin @plugin.command('.mtopic') @plugin.require_chanmsg def manage_topic(bot, trigger): # trigger on channel messages only
Changed in version 7.0: Added the
reply
parameter.
- sopel.plugin.require_owner( ) Callable #
Decorate a function to require the triggering user to be the bot owner.
- Parameters:
A decorated plugin callable will be triggered only if the triggering user is recognized as the bot’s owner, according to its configuration:
from sopel import plugin @plugin.command('.owneronly') @plugin.require_owner('Bot owner only command.') def owner_command(bot, trigger): # trigger only if user is the bot's owner
When the triggering user is not the bot’s owner, the command is not run, and the bot will say
message
if given. By default, it usesbot.say()
, but whenreply
isTrue
it usesbot.reply()
instead.This decorator also works without parentheses, if you want its default (no arguments) behavior:
from sopel import plugin @plugin.command('.owneronly') @plugin.require_owner def owner_command(bot, trigger): # trigger only if user is the bot's owner
Changed in version 7.0: Added the
reply
parameter.
- sopel.plugin.require_privilege(
- level: AccessLevel,
- message: str | None = None,
- reply: bool = False,
Decorate a function to require at least the given channel permission.
- Parameters:
level
can be one of the privilege level constants defined in this module. If the user does not have at least that privilege, the bot will saymessage
if given. By default, it usesbot.say()
, but whenreply
isTrue
it usesbot.reply()
instead.Use of
require_privilege()
impliesrequire_chanmsg()
.Changed in version 7.0: Added the
reply
parameter.Changed in version 8.0: Decorated callables no longer run in response to private messages.
- sopel.plugin.require_privmsg( ) Callable #
Decorate a function to only be triggerable from a private message.
- Parameters:
A decorated plugin callable will be triggered only by messages sent to the bot in private:
from sopel import plugin @plugin.command('.shh') @plugin.require_privmsg('PM only command.') def confidential_command(bot, trigger): # trigger on private messages only
If the decorated function is triggered by a channel message, the
message
will be said if given. By default, it usesbot.say()
, but whenreply
isTrue
, then it usesbot.reply()
instead.This decorator also works without parentheses, if you want its default (no arguments) behavior:
from sopel import plugin @plugin.command('.shh') @plugin.require_privmsg def confidential_command(bot, trigger): # trigger on private messages only
Changed in version 7.0: Added the
reply
parameter.
- sopel.plugin.rule(*patterns: str | Pattern) Callable #
Decorate a function to be called when a line matches the given pattern.
- Parameters:
patterns – one or more regular expression(s)
Each argument is a regular expression which will trigger the function:
@rule('hello', 'how') # will trigger once on "how are you?" # will trigger once on "hello, what's up?"
This decorator can be used multiple times to add more rules:
@rule('how') @rule('hello') # will trigger once on "how are you?" # will trigger once on "hello, what's up?"
If the Sopel 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 theTrigger
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.Changed in version 7.0: The
rule()
decorator can be called with multiple positional arguments, each used to add a rule. This is equivalent to decorating the same function multiple times with this decorator.
- sopel.plugin.rule_lazy(*loaders: Callable) Callable #
Decorate a callable as a rule with lazy loading.
- Parameters:
loaders – one or more functions to generate a list of compiled regexes to match URLs
Each
loader
function must accept asettings
parameter and return a list (or tuple) of compiled regular expressions:import re def loader(settings): return [re.compile(r'<your_rule_pattern>')]
It will be called by Sopel when the bot parses the plugin to register rules to get its regexes. The
settings
argument will be the bot’ssopel.config.Config
object.If any of the
loader
functions raises aPluginError
exception, the rule will be ignored; it will not fail the plugin’s loading.The decorated function will behave like any other
callable()
:from sopel import plugin @plugin.rule_lazy(loader) def my_rule_handler(bot, trigger): bot.say('Rule triggered by: %s' % trigger.group(0))
New in version 7.1.
See also
When more than one loader is provided, they will be chained together with the
sopel.tools.chain_loaders()
function.
- sopel.plugin.search(*patterns: str | Pattern) Callable #
Decorate a function to be called when a pattern matches anywhere in a line.
- Parameters:
patterns – one or more regular expression(s)
Each argument is a regular expression which will trigger the function:
@search('hello', 'here') # will trigger once on "hello you" # will trigger twice on "hello here" # will trigger once on "I'm right here!"
This decorator can be used multiple times to add more search rules:
@search('here') @search('hello') # will trigger once on "hello you" # will trigger twice on "hello here" (once per expression) # will trigger once on "I'm right here!"
If the Sopel instance is in a channel, or sent a PRIVMSG, where a part of a string matching this expression is said, the function will execute. Note that captured groups here will be retrievable through the
Trigger
object later. The match will also contain the position of the first instance found.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:@search('$nickname') # will trigger once when the bot's nick is in a trigger
New in version 7.1.
Note
The regex rule will match for the first instance only, starting from the left of the line, and the function will execute only once per regular expression.
To match for each time an expression is found, use the
find()
decorator instead. To match only once from the start of the line, use therule()
decorator instead.
- sopel.plugin.search_lazy(*loaders: Callable) Callable #
Decorate a callable as a search rule with lazy loading.
- Parameters:
loaders – one or more functions to generate a list of compiled regexes to match patterns in a line
Each
loader
function must accept asettings
parameter and return a list (or tuple) of compiled regular expressions:import re def loader(settings): return [re.compile(r'<your_rule_pattern>')]
It will be called by Sopel when the bot parses the plugin to register the search rules to get its regexes. The
settings
argument will be the bot’ssopel.config.Config
object.If any of the
loader
functions raises aPluginError
exception, the find rule will be ignored; it will not fail the plugin’s loading.The decorated function will behave like any other
callable()
:from sopel import plugin @plugin.search_lazy(loader) def my_search_rule_handler(bot, trigger): bot.say('Rule triggered by: %s' % trigger.group(0))
New in version 7.1.
See also
When more than one loader is provided, they will be chained together with the
sopel.tools.chain_loaders()
function.
- sopel.plugin.thread(value: bool) Callable #
Decorate a function to specify if it should be run in a separate thread.
- Parameters:
value – if
True
, the function is called in a separate thread; otherwise, from the bot’s main thread
Functions run in a separate thread (as is the default) will not prevent the bot from executing other functions at the same time. Functions not run in a separate thread may be started while other functions are still running, but additional functions will not start until it is completed.
- sopel.plugin.unblockable(function: Callable | None = None) Callable #
Decorate a function to exempt it from Sopel’s ignore system.
For example, this can be used to ensure that important events such as
JOIN
are always recorded even if the user’s nickname or hostname is ignored:from sopel import plugin @plugin.event('JOIN') @plugin.unblockable def on_join_callable(bot, trigger): # do something when a user JOINs a channel # a blocked nickname or hostname *will* trigger this pass
See also
Sopel’s
dispatch()
method.
- sopel.plugin.url(*url_rules: str) Callable #
Decorate a function to handle URLs.
- Parameters:
url_rules – one or more regex pattern(s) to match URLs
This decorator takes a regex string that will be matched against URLs in a message. The function it decorates is like any other callable:
from sopel import plugin @plugin.url(r'https://example.com/bugs/([a-z0-9]+)') @plugin.url(r'https://short.com/([a-z0-9]+)') def handle_example_bugs(bot, trigger): bot.reply('Found bug ID #%s' % trigger.group(1))
The
bot
is an instance ofSopelWrapper
, andtrigger
is the usualTrigger
object.Under the hood, when Sopel collects the decorated handler it uses an instance of
sopel.plugins.rules.URLCallback
to register it to itsrules manager
and itsregister_url_callback()
method.Changed in version 7.0: The same function can be decorated multiple times with
url()
to register different URL patterns.Changed in version 7.0: More than one pattern can be provided as positional argument at once.
Changed in version 7.1: The
match
parameter is obsolete and can be omitted. When present however, it represents the same match as thetrigger
argument.This behavior will be kept for backward compatibility and will be removed in Sopel 9.
See also
To detect URLs, Sopel uses a matching pattern built from a list of URL schemes, configured by
auto_url_schemes
.
- sopel.plugin.url_lazy(*loaders: Callable) Callable #
Decorate a function to handle URL, using lazy-loading for its regex.
- Parameters:
loaders – one or more functions to generate a list of compiled regexes to match URLs.
Each
loader
function must accept asettings
parameter and return a list (or tuple) of compiled regular expressions:import re def loader(settings): return [re.compile(r'<your_url_pattern>')]
It will be called by Sopel when the bot parses the plugin to register URL callbacks to get its regexes. The
settings
argument will be the bot’ssopel.config.Config
object.If any of the
loader
functions raises aPluginError
exception, the URL callback will be ignored; it will not fail the plugin’s loading.The decorated function will behave like any other
callable()
:from sopel import plugin @plugin.url_lazy(loader) def my_url_handler(bot, trigger): bot.say('URL found: %s' % trigger.group(0))
New in version 7.1.
See also
When more than one loader is provided, they will be chained together with the
sopel.tools.chain_loaders()
function.
About sopel.module
#
Before Sopel 7.1, sopel.module
was the preferred and only way to decorate
callables for plugins. However, since the term module
can be confusing
(mostly because it already has a special meaning in Python), it has been
replaced by plugin
in most cases related to add-ons for Sopel.
The sopel.module
sub-module is replaced by sopel.plugin
.
Deprecated since version 7.1: Use sopel.plugin
instead. This will be removed in Sopel 9.
- sopel.module.intent(*intent_list)#
Decorate a callable to trigger on intent messages.
- Parameters:
intent_list (str) – one or more intent(s) on which to trigger (really, the only useful value is
ACTION
)
New in version 5.2.0.
Deprecated since version 7.1.
Important
This will be removed in Sopel 9, as the IRCv3 intent specification is long dead. You can use
@ctcp
instead.