sopel.plugins.callables

Plugin object definitions.

Added in version 8.1.

The core of a plugin consists of several objects, either plugin callables or plugin jobs. These objects are represented by instances of PluginCallable and PluginJob respectively.

See also

The decorators in sopel.plugin create these objects directly.

Important

This is all relatively new. Its usage and documentation is for Sopel core development. It is subject to rapid changes between versions without much (or any) warning.

Do not build your plugin based on what is here, you do not need to.

Create a plugin decorator

Under the hood each decorator of sopel.plugin creates an instance of PluginCallable and sets various properties. Upon loading the plugin, Sopel will collect all instances of PluginCallable, to create the appropriate rule handlers (see sopel.plugins.rules).

The structure of a typical decorator without any parameters looks like this:

def decorator(
    function: TypedPluginCallableHandler | AbstractPluginObject
) -> PluginCallable:
    # ensure that you have an instance of PluginCallable
    handler = PluginCallable.ensure_callable(function)

    # do something with the handler
    # ...

    # return the PluginCallable
    return handler

The decorator can then be used like this:

@decorator
def some_plugin_function(bot: SopelWrapper, trigger: Trigger) -> None:
    # do something here
    ...

The key behaviors of a plugin decorator are to:

Everything else is mostly dealing with the various way you can use a decorator.

See also

All the decorators in sopel.plugin follow this structure, and they can be taken as implementation examples.

Plugin object reference

class sopel.plugins.callables.AbstractPluginObject(handler: Callable)

Abstract definition of a plugin object.

Parameters:

handler – the function to execute when calling the plugin object

A plugin object encapsulates the logic and attributes required for a plugin to register and execute this object.

Added in version 8.1.

doc: str | None

Documentation of the plugin object.

classmethod from_plugin_object(
obj: AbstractPluginObject,
) TypedPluginObject

Convert a plugin obj to this type of plugin object.

Parameters:

obj – the plugin object to convert from

Returns:

an instance of the new plugin object from obj

This class method will create a new instance of plugin object based on obj’s generic attributes (like its label) and the same callable, assuming obj is a different type of plugin object.

See also

The @label decorator returns a PluginGeneric that needs to be converted into a plugin callable or a plugin job by this class method.

abstract get_handler() Callable

Return this plugin object’s handler.

Returns:

the plugin object’s handler

label: str | None

Identifier of the plugin callable.

Can be set manually to define a human readable identifier.

plugin_name: str | None

Name of the plugin that this plugin object is for.

Set automatically by Sopel when loading a plugin object.

abstract replace_handler(
handler: Callable,
) Callable

Replace this plugin object’s handler.

Returns:

the plugin object’s previous handler

threaded: bool

Flag that indicates if the object is non blocking.

class sopel.plugins.callables.Capability(
*cap_req: str,
handler: CapabilityHandler | None = None,
)

Capability request representation.

See also

The decorator sopel.plugin.capability().

callback(
bot: SopelWrapper,
acknowledged: bool,
) tuple[bool, CapabilityNegotiation | None]

Execute the acknowlegement callback of a capability request.

Parameters:
  • bot – a Sopel instance

  • acknowledged – tell if the capability request is acknowledged (True) or deny (False)

Returns:

a 2-value tuple that contains if the request is done and the result of the handler (if any)

It executes the handler when the capability request receives an acknowledgement (either positive or negative), and returns the result. The handler’s return value is used to know if the capability request is done, or if the bot must wait for resolution from the plugin that requested the capability.

This method returns a 2-value tuple:

  • the first value tells if the negotiation is done for this request

  • the second is the handler’s return value (if any)

If no handler is registered, this automatically returns (True, None), as the negotiation is considered done (without any result).

This doesn’t prevent the handler from raising an exception.

property cap_req: tuple[str, ...]

Capability request as a sorted tuple.

This is the capability request that will be sent to the server as is. A request is acknowledged or denied for all the capabilities it contains, so the request (example/cap1, example/cap2) is not the same as two requests, one for example/cap1 and the other for example/cap2. This makes each request unique.

class sopel.plugins.callables.CapabilityHandler(*args, **kwargs)

Protocol definition for capability handler.

When a plugin requests a capability, it can define a callback handler for that request using the capability() decorator. That handler will be called upon Sopel receiving either an ACK (capability enabled) or a NAK (capability denied) CAP message.

Example:

from sopel import plugin
from sopel.bot import SopelWrapper

@plugin.capability('example/cap-name')
def capability_handler(
    cap_req: tuple[str, ...],
    bot: SopelWrapper,
    acknowledged: bool,
) -> plugin.CapabilityNegotiation:
    if acknowledged:
        # do something if acknowledged
        # i.e.
        # activate a plugin's feature
        pass
    else:
        # do something else if not
        # i.e. use a fallback mechanism
        # or deactivate a plugin's feature if needed
        pass

    # always return if Sopel can send "CAP END" (DONE)
    # or if the plugin must notify the bot for that later (CONTINUE)
    return plugin.CapabilityNegotiation.DONE

Note

This protocol class should be used for type checking and documentation purposes only.

class sopel.plugins.callables.CapabilityNegotiation(
value,
names=_not_given,
*values,
module=None,
qualname=None,
type=None,
start=1,
boundary=None,
)

Capability Negotiation status.

CONTINUE = 2

The capability negotiation must continue.

This must be returned by a capability request handler to signify to the bot that the capability requires further processing (e.g. SASL authentication) and negotiation must not end yet.

The plugin author MUST signal the bot once the negotiation is done.

DONE = 1

The capability negotiation can end.

This must be returned by a capability request handler to signify to the bot that the capability has been properly negotiated and negotiation can end if all other conditions are met.

ERROR = 3

The capability negotiation callback was improperly executed.

If a capability request’s handler returns this status, or if it raises an exception, the bot will mark the request as errored. A handler can use this return value to inform the bot that something wrong happened, without being an error in the code itself.

class sopel.plugins.callables.PluginCallable(handler: TypedPluginCallableHandler)

Plugin callable, i.e. execute a plugin function when triggered.

Parameters:

handler – a function to be called when the plugin callable is invoked

Note

You can guard against execution with predicates: all predicates must return True for the callable to execute.

action_commands: list[str]

List of plugin action commands.

allow_bots: bool

Flag to indicate if a bot can trigger this callable.

allow_echo: bool

Flag to indicate if an echo message can trigger this callable.

channel_rate: int | None

Per channel rate limit (in seconds).

channel_rate_message: str | None

Default message when a channel limit is reached.

commands: list[str]

List of plugin commands.

ctcp: list[str | Pattern]

List of CTCP messages that can trigger this callable.

default_rate_message: str | None

Default message when a limit is reached.

classmethod ensure_callable(
obj: TypedPluginCallableHandler | AbstractPluginObject,
) PluginCallable

Ensure that obj is a plugin callable.

Parameters:

obj – a function or a plugin object

Returns:

a properly defined plugin callable

If obj is already an instance of AbstractPluginObject, it is converted into a plugin callable. Otherwise, a new plugin callable is created, using the obj as its handler.

events: list[str]

List of IRC event types that can trigger this callable.

examples: list[dict]

List of examples (with usage and tests).

find_rules: list[str | Pattern]

List of find patterns.

find_rules_lazy_loaders: list

List of lazy loaders for find rules.

get_handler() TypedPluginCallableHandler

Return this plugin object’s handler.

Returns:

the plugin object’s handler

global_rate: int | None

Global rate limit (in seconds).

global_rate_message: str | None

Default message when the global limit is reached.

property is_generic_rule: bool

Check if the callable is a generic rule.

A generic rule is a trigger condition without any specific pattern outside of the plugin defined regex.

Note

This will return true if no pattern is defined but at least an event or a CTCP is required without the callable being a named rule or an URL callback.

property is_limitable: bool

Check if the callable is subject to rate limiting.

Returns:

True if it is subject to rate limiting

Limitable callables aren’t necessarily triggerable directly, but they all must pass through Sopel’s rate-limiting machinery during dispatching.

property is_named_rule: bool

Check if the callable is a named rule.

A named rule is anything with a name in it: commands, nickname commands, or action commands.

property is_triggerable: bool

Check if the callable can handle the bot’s triggers.

Returns:

True if it can handle the bot’s triggers

A triggerable is a callable that will be used by the bot to handle a particular trigger (i.e. an IRC message): it can be a regex rule, an event, a CTCP command, a command, a nickname command, or an action command, or even a URL callback. However, it must not be a job.

See also

Many of the decorators defined in sopel.plugin make the decorated function a triggerable object.

property is_url_callback: bool

Check if the callable can handle a URL callback.

Returns:

True if it can handle a URL callback

A URL callback handler is a callable that will be used by the bot to handle a particular URL in an IRC message.

See also

Both sopel.plugin.url() sopel.plugin.url_lazy() make the decorated function a URL callback handler.

nickname_commands: list[str]

List of plugin nick commands.

output_prefix: str

Output prefix used when sending PRIVMSG or NOTICE.

predicates: list[TypedCallablePredicate]

List of predicates used to allow or prevent execution.

priority: Literal['low', 'medium', 'high']

Priority of execution.

Plugin callables with a high priority will be executed before medium and low priority callables.

rate_limit_admins: bool

Flag to indicate if rate limits apply to the bot’s admins.

replace_handler(
handler: TypedPluginCallableHandler,
) TypedPluginCallableHandler

Replace this plugin object’s handler.

Returns:

the plugin object’s previous handler

rules: list[str | Pattern]

List of match patterns.

rules_lazy_loaders: list

List of lazy loaders for match rules.

search_rules: list[str | Pattern]

List of search patterns.

search_rules_lazy_loaders: list

List of lazy loaders for search rules.

setup(settings: Config) None

Setup of the plugin callable.

Parameters:

settings – the bot’s configuration

This method will be called by the bot before registering the callable. It ensures the value of various meta-data.

unblockable: bool

Flag to indicate if a blocked user can trigger this callable.

A user can be banned/ignored by the bot, however some callables must always execute (such as JOIN events).

url_lazy_loaders: list

List of lazy loaders for URL callbacks.

url_regex: list[str | Pattern]

List of URL callback patterns.

user_rate: int | None

Per user rate limit (in seconds).

user_rate_message: str | None

Default message when a user limit is reached.

class sopel.plugins.callables.PluginGeneric(handler: Callable)

Generic plugin object, used as a container for common properties.

Some properties of a plugin object are not tied to a specific role, i.e., it is not possible to know what kind of object it is when setting these properties. This is useful when creating decorators that need to set these:

Note

Other plugin object classes should not subclass PluginGeneric and always subclass AbstractPluginObject instead.

Added in version 8.1.

classmethod ensure_callable(
obj: Callable | AbstractPluginObject,
) PluginGeneric | AbstractPluginObject

Ensure that obj is a proper plugin object.

Parameters:

obj – a function or a plugin object

Returns:

a properly defined plugin object

If obj is already an instance of AbstractPluginObject, it is returned as-is. Otherwise, a new PluginGeneric is created from it.

Note

Since a generic plugin object doesn’t hold much value, it never converts a specific plugin object into a generic one as to prevent meta-data loss.

get_handler() Callable

Return this plugin object’s handler.

Returns:

the plugin object’s handler

replace_handler(handler: Callable) Callable

Replace this plugin object’s handler.

Returns:

the plugin object’s previous handler

class sopel.plugins.callables.PluginJob(handler: TypedPluginJobHandler)
classmethod ensure_callable(
obj: TypedPluginJobHandler | AbstractPluginObject,
) PluginJob

Ensure that obj is a plugin job.

Parameters:

obj – a function or a plugin object

Returns:

a properly defined plugin job

If obj is already an instance of AbstractPluginObject, it is converted into a plugin job. Otherwise, a new plugin job is created, using the obj as its handler.

get_handler() TypedPluginJobHandler

Return this plugin object’s handler.

Returns:

the plugin object’s handler

replace_handler(
handler: TypedPluginJobHandler,
) TypedPluginJobHandler

Replace this plugin object’s handler.

Returns:

the plugin object’s previous handler

setup(settings: Config) None

Optional setup.

Parameters:

settings – the bot’s configuration

This method will be called by the bot before registering the job.

Note

This method is a no-op. It exists for subclasses that may need to perform operations before registration.

class sopel.plugins.callables.TypedCallablePredicate(*args, **kwargs)

Protocol definition of a plugin callable predicate function.

A predicate function must accept two positional arguments:

And it must return a boolean:

  • if True, the plugin callable can execute

  • otherwise, the predicate prevents the execution of the plugin callable

Added in version 8.1.

class sopel.plugins.callables.TypedPluginCallableHandler(*args, **kwargs)

Protocol definition of a plugin callable handler function.

A callable handler function must accept two positional arguments:

Added in version 8.1.

class sopel.plugins.callables.TypedPluginJobHandler(*args, **kwargs)

Protocol definition of a plugin job handler function.

A job handler function must accept one positional argument:

Added in version 8.1.

class sopel.plugins.callables.TypedPluginObject

A TypeVar bound to AbstractPluginObject.

When used in the AbstractPluginObject.from_plugin_object() class method, it means the return value must be an instance of the class used to call that method and not a different subclass of AbstractPluginObject.

Added in version 8.1.

alias of TypeVar(‘TypedPluginObject’, bound=AbstractPluginObject)

sopel.plugins.callables.clean_callable(func, config)

Clean the callable. (compile regexes, fix docs, set defaults)

Parameters:
  • func (callable) – the callable to clean

  • config (sopel.config.Config) – Sopel’s settings

This function will set all the default attributes expected for a Sopel callable, i.e. properties related to threading, docs, examples, rate limiting, commands, rules, and other features.

Deprecated since version 8.1: This function is made obsolete by the new plugin callable system and will be removed in Sopel 9.

Changed in version 8.1: This function used to be defined in sopel.loader but was moved into the sopel.plugins internal machinery.

sopel.plugins.callables.clean_module(
module: ModuleType,
config: Config,
) tuple[list[PluginCallable], list[PluginJob], list[Callable], list[PluginCallable]]

Clean a module and return its command, rule, job, etc. callables.

Parameters:
Returns:

a tuple with triggerable, job, shutdown, and url functions

Return type:

tuple

This function will parse the module looking for callables:

  • shutdown actions

  • triggerables (commands, rules, etc.)

  • jobs

  • URL callbacks

This function will set all the default attributes expected for a Sopel callable, i.e. properties related to threading, docs, examples, rate limiting, commands, rules, and other features.

Changed in version 8.1: This function used to be defined in sopel.loader but was moved into the sopel.plugins internal machinery.

sopel.plugins.callables.is_limitable(obj)

Check if obj needs to carry attributes related to limits.

Parameters:

obj – any function to check

Returns:

True if obj must have limit-related attributes

Limitable callables aren’t necessarily triggerable directly, but they all must pass through Sopel’s rate-limiting machinery during dispatching. Therefore, they must have the attributes checked by that machinery.

Deprecated since version 8.1: This function is made obsolete by the new plugin callable system and will be removed in Sopel 9.

sopel.plugins.callables.is_triggerable(obj)

Check if obj can handle the bot’s triggers.

Parameters:

obj – any function to check

Returns:

True if obj can handle the bot’s triggers

A triggerable is a callable that will be used by the bot to handle a particular trigger (i.e. an IRC message): it can be a regex rule, an event, a CTCP command, a command, a nickname command, or an action command. However, it must not be a job or a URL callback.

See also

Many of the decorators defined in sopel.plugin make the decorated function a triggerable object.

Deprecated since version 8.1: This function is made obsolete by the new plugin callable system and will be removed in Sopel 9.

sopel.plugins.callables.is_url_callback(obj)

Check if obj can handle a URL callback.

Parameters:

obj – any function to check

Returns:

True if obj can handle a URL callback

A URL callback handler is a callable that will be used by the bot to handle a particular URL in an IRC message.

See also

Both sopel.plugin.url() sopel.plugin.url_lazy() make the decorated function a URL callback handler.

Deprecated since version 8.1: This function is made obsolete by the new plugin callable system and will be removed in Sopel 9.