A lightweight IRC framework.
A relatively simple thread-safe(-ish) IRC client framework.
To install miniirc, simply run
pip3 install miniirc.
If you have previously used miniirc, you may want to read the deprecations list (last updated 2020-04-28).
irc = miniirc.IRC(ip, port, nick, channels=None, *, ssl=None, ident=None, realname=None, persist=True, debug=False, ns_identity=None, auto_connect=True, ircv3_caps=set(), quit_message='I grew sick and died.', ping_interval=60, ping_timeout=None, verify_ssl=True, executor=None)
Note that everything before the * is a positional argument.
You don't need to add every argument, and the
channels arguments should be specified as positional arguments.
irc = miniirc.IRC('irc.example.com', 6697, 'my-bot', ['#my-channel'], ns_identity=('my-bot', 'hunter2'), executor=concurrent.futures.ThreadPoolExecutor())
If you are not doing anything with the main thread after connecting to IRC,
irc.wait_until_disconnected() to prevent Python from trying to
shut down while miniirc is still connected, breaking thread pools (in
Python 3.9 and later).
||The IP/hostname of the IRC server to connect to.|
||The port to connect to.|
||The nickname of the bot.|
||The channels to join on connect. This can be an iterable containing strings (list, set, etc), or (since v1.5.0) a comma-delimited string.|
||Enable TLS/SSL. If
||The ident to use, defaults to
||The realname to use, defaults to
||Whether to automatically reconnect.|
||Enables debug mode, prints all IRC messages. This can also be a file-like object (with write mode enabled) if you want debug messages to be written into a file instead of being printed to stdout, or a function (for example
||The NickServ account to use as a tuple/list of length 2 (
||A set() of additional IRCv3 capabilities to request. SASL is auto-added if
||A mode string (for example
||Sets the default quit message. This can be modified per-quit with
||If no packets are sent or received for this amount of seconds, miniirc will send a
||The ping timeout used alongside the above
||Verifies TLS/SSL certificates. Disabling this is not recommended as it opens the IRC connection up to MiTM attacks. If you have trouble with certificate verification, try running
||An instance of
The only mandatory parameters are
||See the message parser section for documentation.|
||Connects to the IRC server if not already connected.|
||Disconnects from the IRC server.
||An event handler, see Handlers for more info.|
||Sends a raw message to IRC, use
||Sends a command to the IRC server, treating every positional argument as a parameter. The usage of this is recommended over
||Waits until the IRC server is disconnected and automatic reconnecting is turned off.|
Note that if
irc.msg etc is called) while
miniirc is not connected, messages will be temporarily stored and then sent
once miniirc is connected. Setting
force=True will throw errors if miniirc is
completely disconnected (
irc.quote and irc.send
The two functions
irc.send may sound similar, however are
irc.quote() joins all provided arguments with spaces
and sends them as a raw message to IRC, while
irc.send() treats each argument
as a parameter. If arguments passed to
irc.send() contain spaces, they are
replaced with U+00A0 (a non-breaking space, visually similar to a regular
space however not interpreted as one).
irc.quote('PRIVMSG', '#channel :Hello,', 'world!')sends "Hello, world!" to #channel.
irc.quote('PRIVMSG', '#channel', 'Hello, world!')is invalid ("Hello," and "world!" are sent as separate parameters).
irc.send('PRIVMSG', '#channel', 'Hello, world!')will send "Hello, world!" to "#channel".
irc.send('PRIVMSG', '#channel :Hello,', 'world!')will send "world!" to
\xa0is a non-breaking space.
If you are unsure and do not need compatibility with miniirc <1.5.0, use
PRIVMSG is just used as an example, if you need to send
These variables should not be changed outside
||A boolean (or
||New in v1.4.3. The bot/client's current nickname, currently an alias for
||The maximum length (in bytes) of messages (including
||The nickname to use when connecting to IRC. Until miniirc v2.0.0, you should only modify this while disconnected, as it is currently automatically updated with nickname changes.|
The following arguments passed to
miniirc.IRC are also available:
miniirc.CmdHandler are function decorators that add
functions to an event handler list. Functions in this list are called in their
own thread when their respective IRC event(s) is/are received. Handlers may
work on every IRC object in existence (
miniirc.Handler) or only on
specific IRC objects (
The basic syntax for a handler is as followed, where
*events is a list of events (
NOTICE, etc) are called.
import miniirc @miniirc.Handler(*events, colon=False) def handler(irc, hostmask, args): # irc: An 'IRC' object. # hostmask: A 'hostmask' object. # args: A list containing the arguments sent to the command. Everything # following the first `:` in the command is put into one item # (args[-1]). If "colon" is "False", the leading ":" (if any) # is automatically removed. To prevent your code from horribly # breaking, always set it to False unless you know what you are # doing. pass
Recommendations when using handlers:
- If you don't need support for miniirc <1.4.0 and are parsing the last
Falseis strongly recommended. If the
colonparameter is omitted, it defaults to
True, however this will change when miniirc v2.0.0 is released.
CmdHandlercurrently accept any object that can be converted to a string, every event is converted to a string internally.
- Not specifying the
ircv3parameter when it is not required prevents a redundant
dictfrom being created.
- To add handlers to a specific
IRCobject and not every one in existence, use
irc.CmdHandlerinstead. If you want to create a
Clientclass and automatically add handlers to
IRCobjects created inside it, see making existing functions handlers.
Hostmasks are tuples with the format
('user', 'ident', 'hostname'). If
hostname aren't sent from the server, they will be filled in with the
previous value. If a command is received without a hostmask, all the
elements will be set to the name of the command. This is deprecated, however,
and when miniirc v2.0.0 is released the
hostmask elements will be set to
Making existing functions handlers
You can make existing functions handlers (for example class instance methods)
irc.Handler(*events)(handler_function). You probably don't want to use
miniirc.Handler for class instance methods, as this will create a handler
that gets triggered for every
You can also add multiple handlers of the same type easily:
add_handler = irc.Handler('PRIVMSG', colon=False) add_handler(handler_1) add_handler(self.instance_handler)
This is useful if you want to create a
Client) class and add
class-specific handlers without creating global process-wide handlers or
creating a wrapper function for every class instance.
If you want your handler to support IRCv3 message tags, you need to add
ircv3=True to the
CmdHandler decorator. You will need to add a
tags parameter to your function after
hostmask. IRCv3 tags are sent to the
dicts, with values of either strings or
miniirc will automatically un-escape IRCv3 tag values.
import miniirc @miniirc.Handler(*events, colon=False, ircv3=True) def handler(irc, hostmask, tags, args): pass
You can handle IRCv3 capabilities before connecting using a handler.
You must use
force=True on any
irc.quote() called here, as when this is
called, miniirc may not yet be fully connected. Do not use the
Handler when creating these handlers to avoid unexpected side-effects.
import miniirc @miniirc.Handler('IRCv3 my-cap-name') def handler(irc, hostmask, args): # Process the capability here # IRCv3.2 capabilities: # args = ['my-cap-name', 'IRCv3.2-parameters'] # IRCv3.1 capabilities: # args = ['my-cap-name'] # Remove the capability from the processing list. irc.finish_negotiation(args) # This can also be 'my-cap-name'.
Custom message parsers (not recommended)
If the IRC server you are connecting to supports a non-standard message syntax, you can
create custom message parsers. These are called with the raw message (as a
can either return
None to ignore the message or a 4-tuple (
cmd, hostmask, tags, args)
that will then be sent on to the handlers. The items in this 4-tuple should be the same
type as the items expected by handlers (and
cmd should be a string).
Message parser example
This message parser makes the normal parser allow
~ as an IRCv3 tag prefix character.
import miniirc def my_message_parser(msg): if msg.startswith('~'): msg = '@' + msg[1:] return miniirc.ircv3_message_parser(msg)
Changing message parsers
To change message parsers, you can use
func is not
specified, it will default to the built-in parser. You can only change message parsers
on-the-fly (for example in an IRCv3 CAP handler). If you need to change message parsers
before connecting, you can disable
auto_connect and change it then.
irc = miniirc.IRC(..., auto_connect=False) irc.change_parser(my_message_parser) irc.connect()
Handling multiple events
If you want to handle multiple events and/or be able to get the name of the
event being triggered, you can use
irc.CmdHandler. This will pass an extra
command argument to the handler function (between
containing a string with the command name (such as
Please do not use these unless there is no other alternative.
If you want to handle every event, you can use catch-all handlers. To create
these, you can call
irc.CmdHandler() without any parameters. Note that this
handler will be called many times while connecting (and once connected).
You cannot call
irc.Handler() without parameters.
import miniirc # Not required, however this makes sure miniirc isn't outdated. assert miniirc.ver >= (1,8,2) @miniirc.Handler('PRIVMSG', 'NOTICE', colon=True) def handler(irc, hostmask, args): print(hostmask, 'sent a message to', args, 'with content', args) # nickname sent a message to #channel with content :Hello, world! @miniirc.CmdHandler('PRIVMSG', 'NOTICE', colon=False) def cmdhandler(irc, command, hostmask, args): print(hostmask, 'sent a', command, 'to', args, 'with content', args) # nickname sent a PRIVMSG to #channel with content Hello, world!
This will print a line whenever the bot gets a
miniirc provides the following helper functions:
||The default IRCv2/IRCv3 message parser, returns
||A tuple containing version information.|
The version numbering system should be similar to SemVer, however backwards compatibility is preserved where possible when major releases change.
Python version support
- Python 3.3 and below are unsupported and do not work with miniirc.
- Python 3.4, 3.5, and 3.6 are currently supported, but support will likely be dropped in miniirc v2.1.0. Major bugfixes may be backported to v2.0 for a few months after v2.1's release.
- Python 3.7 and above should work with the latest stable version of miniirc.
If you are using Python 3.7 or an older version of Python, I strongly recommend updating. Later versions of Python include features such as f-strings that make software development easier.
If you want more advanced(-ish) features such as user tracking, you can use miniirc_extras (GitHub, GitLab). Note that miniirc_extras is still in beta and there will be breaking API changes in the future.
When miniirc v2.0.0 is released, the following breaking changes will (probably) be made:
- Internal-only attributes
irc.sendq(please do not use these) will be renamed. Again, please do not use these.
irc.nickwill be the nickname used when connecting to IRC rather than the current nickname, use
irc.current_nickfor the current nickname (since v1.4.3). This will stop lots of underscores being automatically appended to nicknames.
irc.ns_identitywill be stored as a tuple instead of a string, for example
('username', 'password with spaces')instead of
'username password with spaces'. Both formats are currently accepted and will be accepted in the
- No exceptions will be raised in
force=Truewhen the socket is closed. Instead of relying on these exceptions, use
irc.connectedwhich is set to
Nonewhen completely disconnected.
- As stated in the Python version support section, Python 3.4 support will be dropped in miniirc v2.1.0, however bugfixes will be backported for a few months.
colonkeyword argument to
CmdHandlerwill default to
- Unspecified hostmasks will be an empty string instead of the command. Don't rely on this "feature" if possible, simply ignore the hostmask if you do not need it.
extended-joincapability will be requested by default, use
args[-1]to get the channel from a
tagskeyword argument will be read-only.
Here is a list of some (open-source) bots using miniirc, in alphabetical order:
- irc-rss-feed-bot - Posts RSS entry titles and shortened URLs to IRC channels. Python 3.8+
- irc-url-title-bot - Gets webpage titles from URLs posted in IRC channels. Python 3.8+
- lurklite - A generic configurable IRC bot. GitHub link.
- stdinbot - A very simple bot that dumps stdin to an IRC channel. GitHub link.
Release history Release notifications | RSS feed
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.