IRC Core Implementation#

Operation of the sopel.irc core is supported by these utility submodules:

sopel.irc#

sopel.irc is the core IRC module for Sopel.

This sub-package contains everything that is related to the IRC protocol (connection, commands, abstract client, etc.) and that can be used to implement the Sopel bot.

In particular, it defines the interface for the IRC backend (AbstractIRCBackend), and the interface for the bot itself (AbstractBot).

Warning

This is all internal code, not intended for direct use by plugins. It is subject to change between versions, even patch releases, without any advance warning.

Please use the public APIs on bot.

Important

When working on core IRC protocol related features, consult protocol documentation at https://modern.ircdocs.horse/

class sopel.irc.AbstractBot(settings: Config)#

Abstract definition of Sopel’s interface.

action(text: str, dest: str) None#

Send a CTCP ACTION PRIVMSG to a user or channel.

Parameters:
  • text (str) – the text to send in the CTCP ACTION

  • dest (str) – the destination of the CTCP ACTION

The same loop detection and length restrictions apply as with say(), though automatic message splitting is not available.

backend: AbstractIRCBackend#

IRC Connection Backend.

property capabilities: Capabilities#

Capabilities negotiated with the server.

change_current_nick(new_nick: str) None#

Change the current nick without configuration modification.

Parameters:

new_nick (str) – new nick to be used by the bot

property config: Config#

The sopel.config.Config for the current Sopel instance.

property connection_registered: bool#

Whether the IRC connection is registered.

This is a property so it can accurately reflect not only the socket state (connection to IRC server), but also whether the connection is ready to accept “normal” IRC commands.

Before registration is completed, only a very limited set of commands are allowed to be used. Sopel itself takes care of these, so plugins will be more concerned with whether they are allowed to use methods like say() yet.

abstract dispatch(pretrigger: PreTrigger)#

Handle running the appropriate callables for an incoming message.

Parameters:

pretrigger (sopel.trigger.PreTrigger) – Sopel PreTrigger object

Important

This method MUST be implemented by concrete subclasses.

property enabled_capabilities: set[str]#

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

Deprecated since version 8.0: Enabled server capabilities are now managed by bot.capabilities and its various methods and attributes:

Will be removed in Sopel 9.

get_irc_backend(
host: str,
port: int,
source_address: tuple[str, int] | None,
) AbstractIRCBackend#

Set up the IRC backend based on the bot’s settings.

Returns:

the initialized IRC backend object

Return type:

an object implementing the interface of AbstractIRCBackend

abstract property hostmask: str | None#

The bot’s hostmask.

property isupport: ISupport#

Features advertised by the server.

Type:

ISupport instance

join(channel: str, password: str | None = None) None#

Join a channel.

Parameters:
  • channel (str) – the channel to join

  • password (str) – an optional channel password

If channel contains a space, and no password is given, the space is assumed to split the argument into the channel to join and its password. channel should not contain a space if password is given.

kick(nick: str, channel: str, text: str | None = None) None#

Kick a nick from a channel.

Parameters:
  • nick – nick to kick out of the channel

  • channel – channel to kick nick from

  • text – optional text for the kick

The bot must be an operator in the specified channel for this to work.

New in version 7.0.

log_raw(line: str, prefix: str) None#

Log raw line to the raw log.

Parameters:
  • line (str) – the raw line

  • prefix (str) – additional information to prepend to the log line

The prefix is usually either >> for an outgoing line or << for a received one.

make_identifier(name: str) Identifier#

Instantiate an Identifier using the bot’s context.

New in version 8.0.

make_identifier_memory() SopelIdentifierMemory#

Instantiate a SopelIdentifierMemory using the bot’s context.

This is a shortcut for SopelIdentifierMemory’s most common use case, which requires remembering to pass the bot’s own make_identifier() method so the SopelIdentifierMemory will cast its keys to Identifiers that are compatible with what the bot tracks internally and sends with Triggers when a plugin callable runs.

Calling this method is equivalent to the following:

from sopel.tools import memories

memories.SopelIdentifierMemory(
    identifier_factory=bot.make_identifier,
)

New in version 8.0.

See also

The tools.memories module describes how to use SopelIdentifierMemory and its siblings.

property myinfo: MyInfo#

Server/network information.

Type:

MyInfo instance

New in version 7.0.

property name: str#

Sopel’s “real name”, as used for WHOIS responses.

property nick: Identifier#

Sopel’s current nick.

Changing this while Sopel is running is unsupported and can result in undefined behavior.

notice(text: str, dest: str) None#

Send an IRC NOTICE to a user or channel (dest).

Parameters:
  • text – the text to send in the NOTICE

  • dest – the destination of the NOTICE

on_close() None#

Call shutdown methods.

on_connect() None#

Handle successful establishment of IRC connection.

on_error() None#

Handle any uncaptured error in the bot itself.

on_message(message: str) None#

Handle an incoming IRC message.

Parameters:

message (str) – the received raw IRC message

on_message_sent(raw: str) None#

Handle any message sent through the connection.

Parameters:

raw (str) – raw text message sent through the connection

When a message is sent through the IRC connection, the bot will log the raw message. If necessary, it will also simulate the echo-message feature of IRCv3.

part(channel: str, msg: str | None = None) None#

Leave a channel.

Parameters:
  • channel – the channel to leave

  • msg – the message to display when leaving a channel

quit(message: str | None = None) None#

Disconnect from IRC and close the bot.

Parameters:

message – optional QUIT message to send (e.g. “Bye!”)

rebuild_nick() None#

Rebuild nick as a new identifier.

This method exists to update the casemapping rules for the Identifier that represents the bot’s nick, e.g. after ISUPPORT info is received.

reply(
text: str,
dest: str,
reply_to: str,
notice: bool = False,
) None#

Send a PRIVMSG to a user or channel, prepended with reply_to.

Parameters:
  • text – the text of the reply

  • dest – the destination of the reply

  • reply_to – the nickname that the reply will be prepended with

  • notice – whether to send the reply as a NOTICE or not, defaults to False

If notice is True, send a NOTICE rather than a PRIVMSG.

The same loop detection and length restrictions apply as with say(), though automatic message splitting is not available.

restart(message: str | None = None) None#

Disconnect from IRC and restart the bot.

Parameters:

message – optional QUIT message to send (e.g. “Be right back!”)

run(host: str, port: int = 6667) None#

Connect to IRC server and run the bot forever.

Parameters:
  • host (str) – the IRC server hostname

  • port (int) – the IRC server port

safe_text_length(recipient: str) int#

Estimate a safe text length for an IRC message.

Returns:

the maximum possible length of a message to recipient

When the bot sends a message to a recipient (channel or nick), it has 512 bytes minus the command, arguments, various separators and trailing CRLF for its text. However, this is not what other users will see from the server; the message forwarded to other clients will be sent using this format:

:nick!~user@hostname PRIVMSG #channel :text

Which takes more bytes, reducing the maximum length available for a single line of text. This method computes a safe length of text that can be sent using PRIVMSG or NOTICE by subtracting the size required by the server to convey the bot’s message.

See also

This method is useful when sending a message using say(), and can be used with sopel.tools.get_sendable_message().

say(
text: str,
recipient: str,
max_messages: int = 1,
truncation: str = '',
trailing: str = '',
) None#

Send a PRIVMSG to a user or channel.

Parameters:
  • text – the text to send

  • recipient – the message recipient

  • max_messages – split text into at most this many messages if it is too long to fit in one (optional)

  • truncation – string to append if text is too long to fit in a single message, or into the last message if max_messages is greater than 1 (optional)

  • trailing – string to append after text and (if used) truncation (optional)

By default, this will attempt to send the entire text in one message. If the text is too long for the server, it may be truncated.

If max_messages is given, the text will be split into at most that many messages. The split is made at the last space character before the “safe length” (which is calculated based on the bot’s nickname and hostmask), or exactly at the “safe length” if no such space character exists.

If the text is too long to fit into the specified number of messages using the above splitting, the final message will contain the entire remainder, which may be truncated by the server. You can specify truncation to tell Sopel how it should indicate that the remaining text was cut off. Note that the truncation parameter must include leading whitespace if you desire any between it and the truncated text.

The trailing parameter is always appended to text, after the point where truncation would be inserted if necessary. It’s useful for making sure e.g. a link is always included, even if the summary your plugin fetches is too long to fit.

Here are some examples of how the truncation and trailing parameters work, using an artificially low maximum line length:

# bot.say() outputs <text> + <truncation?> + <trailing>
#                   always     if needed       always

bot.say(
    '"This is a short quote.',
    truncation=' […]',
    trailing='"')
# Sopel says: "This is a short quote."

bot.say(
    '"This quote is very long and will not fit on a line.',
    truncation=' […]',
    trailing='"')
# Sopel says: "This quote is very long […]"

bot.say(
    # note the " included at the end this time
    '"This quote is very long and will not fit on a line."',
    truncation=' […]')
# Sopel says: "This quote is very long […]
# The ending " goes missing

New in version 7.1: The truncation and trailing parameters.

property server_capabilities: dict[str, str | None]#

A dict mapping supported IRCv3 capabilities to their options.

For example, if the server specifies the capability sasl=EXTERNAL, it will be here as {"sasl": "EXTERNAL"}. Capabilities specified without any options will have None as the value.

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

Deprecated since version 8.0: Enabled server capabilities are now managed by bot.capabilities and its various methods and attributes:

Will be removed in Sopel 9.

settings#

Bot settings.

property user: str#

Sopel’s user/ident.

write(args: Iterable[str], text: str | None = None) None#

Send a command to the server.

Parameters:
  • args – an iterable of strings, which will be joined by spaces

  • text – a string that will be prepended with a : and added to the end of the command

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 preceded 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 sopel.write(('PRIVMSG',), 'Hello, world!') and sopel.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.

See also

The connection backend is responsible for formatting and sending the message through the IRC connection. See the sopel.irc.abstract_backends.AbstractIRCBackend.send_command() method for more information.