%global _empty_manifest_terminate_build 0 Name: python-miniirc Version: 1.9.1 Release: 1 Summary: A lightweight IRC framework. License: MIT URL: https://github.com/luk3yx/miniirc Source0: https://mirrors.nju.edu.cn/pypi/web/packages/05/46/1887889cc1907a2d7d3258199fed555153ee7fb61c84168960b46d5ed6a0/miniirc-1.9.1.tar.gz BuildArch: noarch Requires: python3-certifi %description # miniirc [![Python 3.4+]](#python-version-support) [![Available on PyPI.]](https://pypi.org/project/miniirc/) [![License: MIT]](https://github.com/luk3yx/miniirc/blob/master/LICENSE.md) 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). *This repository is available on both [GitHub](https://github.com/luk3yx/miniirc) and [GitLab](https://gitlab.com/luk3yx/miniirc).* [Python 3.4+]: https://img.shields.io/badge/python-3.4+-blue.svg [Available on PyPI.]: https://img.shields.io/pypi/v/miniirc.svg [License: MIT]: https://img.shields.io/pypi/l/miniirc.svg [deprecations list]: #deprecations ## Parameters ```py 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.* ### Typical usage You don't need to add every argument, and the `ip`, `port`, `nick`, and `channels` arguments should be specified as positional arguments. ```py irc = miniirc.IRC('irc.example.com', 6697, 'my-bot', ['#my-channel'], ns_identity=('my-bot', 'hunter2'), executor=concurrent.futures.ThreadPoolExecutor(), keepnick=True) ``` If you are not doing anything with the main thread after connecting to IRC, please call `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). ```py irc.wait_until_disconnected() ``` ### Parameter descriptions | Parameter | Description | | ------------- | -------------------------------------------------------- | | `ip` | The IP/hostname of the IRC server to connect to. | | `port` | The port to connect to. | | `nick` | The nickname of the bot. | | `channels` | 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. | | `ssl` | Enable TLS/SSL. If `None`, TLS is disabled unless the port is `6697`. | | `ident` | The ident to use, defaults to `nick`. | | `realname` | The realname to use, defaults to `nick` as well. | | `persist` | Whether to automatically reconnect. | | `debug` | 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 `logging.debug`). | | `ns_identity` | The NickServ account to use as a tuple/list of length 2 (`('', '')`). For compatibility, this can be a string (`' '`). | | `auto_connect`| Runs `irc.connect()` straight away. | | `ircv3_caps` | A set() of additional IRCv3 capabilities to request. SASL is auto-added if `ns_identity` is specified. | | `connect_modes` | A mode string (for example `'+B'`) of UMODEs to set when connected. | | `quit_message`| Sets the default quit message. This can be modified per-quit with `irc.disconnect()`. | | `ping_interval` | If no packets are sent or received for this amount of seconds, miniirc will send a `PING`, and if no reply is sent, after the ping timeout, miniirc will attempt to reconnect. Set to `None` to disable. | | `ping_timeout` | The ping timeout used alongside the above `ping_interval` option, if unspecified will default to `ping_interval`. | | `verify_ssl` | 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 `pip3 install certifi` first. | | `executor` | An instance of `concurrent.futures.ThreadPoolExecutor` to use when running handlers. | | `keepnick` | If enabled, miniirc will attempt to obtain the original nick like ZNC's *keepnick. `irc.nick` will be the original nickname rather than the current one. | *The only mandatory parameters are `ip`, `port`, and `nick`.* ## Functions | Function | Description | | ------------- | -------------------------------------------------------- | | `change_parser(parser=...)` | *See the message parser section for documentation.* | | `connect()` | Connects to the IRC server if not already connected. | | `ctcp(target, *msg, reply=False, tags=None)` | Sends a `CTCP` request or reply to `target`. | | `debug(...)` | Debug, calls `print(...)` if debug mode is on. | | `disconnect(msg=..., *, auto_reconnect=False)`| Disconnects from the IRC server. `auto_reconnect` will be overridden by `self.persist` if set to `True`. | | `Handler(...)` | An event handler, see [Handlers](#handlers) for more info. | | `me(target, *msg, tags=None)` | Sends a `/me` (`CTCP ACTION`) to `target`. | | `msg(target, *msg, tags=None)` | Sends a `PRIVMSG` to `target`. `target` should not contain spaces or start with a colon. | | `notice(target, *msg, tags=None)` | Sends a `NOTICE` to `target`. `target` should not contain spaces or start with a colon. | | `quote(*msg, force=False, tags=None)` | Sends a raw message to IRC, use `force=True` to send while disconnected. Do not send multiple commands in one `irc.quote()`, as the newlines will be stripped and it will be sent as one command. The `tags` parameter optionally allows you to add a `dict` with IRCv3 client tags (all starting in `+`), and will not be sent to IRC servers that do not support client tags. | | `send(*msg, force=False, tags=None)` | Sends a command to the IRC server, treating every positional argument as a parameter. The usage of this is recommended over `irc.quote()` unless you know what you are doing. | | `wait_until_disconnected()` | Waits until the IRC server is disconnected and automatic reconnecting is turned off. | *Note that if `force=False` on `irc.quote` (or `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.connected` is `None`).* ### irc.quote and irc.send The two functions `irc.quote` and `irc.send` may sound similar, however are fundamentally different: `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). #### Examples - `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 `#channel\xa0:Hello,`, where `\xa0` is a non-breaking space. *If you are unsure and do not need compatibility with miniirc <1.5.0, use `irc.send()`. `PRIVMSG` is just used as an example, if you need to send `PRIVMSG`s use `irc.msg()` instead.* ## Variables *These variables should not be changed outside `miniirc.py`.* | Variable | Description | | ------------- | -------------------------------------------------------- | | `active_caps` | A `set` of IRCv3 capabilities that have been successfully negotiated with the IRC server. This is empty while disconnected. | | `connected` | A boolean (or `None`), `True` when miniirc is connected, `False` when miniirc is connecting, and `None` when miniirc is not connected. | | `current_nick` | The bot/client's current nickname. Do not modify this, and use this instead of `irc.nick` when getting the bot's current nickname. | | `isupport` | A `dict` with values (not necessarily strings) from `ISUPPORT` messages sent to the client. | | `msglen` | The maximum length (in bytes) of messages (including `\r\n`). This is automatically changed if the server supports the `oragono.io/maxline-2` capability. | | `nick` | The nickname to use when connecting to IRC. Until miniirc v2.0.0, you should only use or modify this while disconnected, as it is currently automatically updated with nickname changes. | The following arguments passed to `miniirc.IRC` are also available: `ip`, `port`, `channels`, `ssl`, `ident`, `realname`, `persist`, `connect_modes`, `quit_message`, `ping_interval`, `verify_ssl`. ## Handlers `miniirc.Handler` and `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 (`irc.Handler`). The basic syntax for a handler is as followed, where `*events` is a list of events (`PRIVMSG`, `NOTICE`, etc) are called. ```py 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 parameter, setting `colon` to `False` is strongly recommended. If the `colon` parameter is omitted, it defaults to `True`, however this will change when miniirc v2.0.0 is released. - Although `Handler` and `CmdHandler` currently accept any object that can be converted to a string, every event is converted to a string internally. - Not specifying the [`ircv3`](#ircv3-tags) parameter when it is not required prevents a redundant `dict` from being created. - To add handlers to a specific `IRC` object and not every one in existence, use `irc.Handler` and `irc.CmdHandler` instead. If you want to create a `Bot` or `Client` class and automatically add handlers to `IRC` objects created inside it, see [making existing functions handlers](#making-existing-functions-handlers). ### Hostmask object Hostmasks are tuples with the format `('user', 'ident', 'hostname')`. If `ident` and `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 `hostmask` 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 empty strings. ### Making existing functions handlers You can make existing functions handlers (for example class instance methods) with `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 `IRC` object. You can also add multiple handlers of the same type easily: ```py 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 `Bot` (or `Client`) class and add class-specific handlers without creating global process-wide handlers or creating a wrapper function for every class instance. ### IRCv3 support #### IRCv3 tags If you want your handler to support IRCv3 message tags, you need to add `ircv3=True` to the `Handler` or `CmdHandler` decorator. You will need to add a `tags` parameter to your function after `hostmask`. IRCv3 tags are sent to the handlers as `dict`s, with values of either strings or `True`. *miniirc will automatically un-escape IRCv3 tag values.* ```py import miniirc @miniirc.Handler(*events, colon=False, ircv3=True) def handler(irc, hostmask, tags, args): pass ``` #### IRCv3 capabilities 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 `colon` argument for `Handler` when creating these handlers to avoid unexpected side-effects. ```py 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[0]) # 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 `str`) and 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. ```py 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 `irc.change_parser(func=...)`. If `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. ```py 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 `irc` and `hostmask`), containing a string with the command name (such as `PRIVMSG`). #### Catch-all handlers **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.* ### Example ```py 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[0], 'sent a message to', args[0], 'with content', args[1]) # nickname sent a message to #channel with content :Hello, world! @miniirc.CmdHandler('PRIVMSG', 'NOTICE', colon=False) def cmdhandler(irc, command, hostmask, args): print(hostmask[0], 'sent a', command, 'to', args[0], 'with content', args[1]) # nickname sent a PRIVMSG to #channel with content Hello, world! ``` This will print a line whenever the bot gets a `PRIVMSG` or `NOTICE`. ## Misc functions miniirc provides the following helper functions: | Name | Description | | ----------------------------- | ----------------------------------------- | | `miniirc.get_ca_certs()` | Runs `certifi.where()` if `certifi` is installed, otherwise returns `None`. | | `miniirc.ircv3_message_parser(msg)` | The default IRCv2/IRCv3 message parser, returns `cmd, hostmask, tags, args`. | | `miniirc.ver` | A tuple containing version information. | | `miniirc.version` | The `CTCP VERSION` reply, can be changed. | The version numbering system should be similar to [SemVer](https://semver.org/), 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 there is a bug/error in Python 3.4 or newer, please open an issue or pull request on [GitHub](https://github.com/luk3yx/miniirc/issues) or [GitLab](https://gitlab.com/luk3yx/miniirc/issues). *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.* ## miniirc_extras If you want more advanced(-ish) features such as user tracking, you can use [miniirc_extras](https://pypi.org/project/miniirc-extras/) ([GitHub](https://github.com/luk3yx/miniirc_extras), [GitLab](https://gitlab.com/luk3yx/miniirc_extras)). Note that miniirc_extras is still in beta and there will be breaking API changes in the future. ## Deprecations If miniirc v2.0.0 is ever released, the following breaking changes will (probably) be made: - Internal-only attributes `irc.handlers`, `irc.sock`, and `irc.sendq` (please do not use these) will be renamed. Again, please do not use these. - `irc.nick` will always be the nickname used when connecting to IRC rather than the current nickname, use `irc.current_nick` for the current nickname (since v1.4.3). - `irc.ns_identity` will 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 `ns_identity` keyword argument. - No exceptions will be raised in `irc.quote`/`irc.send` with `force=True` when the socket is closed. Instead of relying on these exceptions, use `irc.connected` which is set to `None` when 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. - The `colon` keyword argument to `Handler` and `CmdHandler` will default to `False` instead of `True`. - 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. - The `extended-join` capability will be requested by default, use `args[0]` instead of `args[-1]` to get the channel from a `JOIN` event. - The `tags` keyword argument will be read-only. ## Working examples/implementations 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](https://github.com/luk3yx/lurklite) link.* - [stdinbot] - A very simple bot that dumps stdin to an IRC channel. *[GitHub](https://github.com/luk3yx/stdinbot) link.* *Want to add your own bot/client to this list? Open an issue on [GitHub](https://github.com/luk3yx/miniirc/issues) or [GitLab](https://gitlab.com/luk3yx/miniirc/issues).* [irc-rss-feed-bot]: https://github.com/impredicative/irc-rss-feed-bot [irc-url-title-bot]: https://github.com/impredicative/irc-url-title-bot [lurklite]: https://gitlab.com/luk3yx/lurklite [stdinbot]: https://gitlab.com/luk3yx/stdinbot %package -n python3-miniirc Summary: A lightweight IRC framework. Provides: python-miniirc BuildRequires: python3-devel BuildRequires: python3-setuptools BuildRequires: python3-pip %description -n python3-miniirc # miniirc [![Python 3.4+]](#python-version-support) [![Available on PyPI.]](https://pypi.org/project/miniirc/) [![License: MIT]](https://github.com/luk3yx/miniirc/blob/master/LICENSE.md) 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). *This repository is available on both [GitHub](https://github.com/luk3yx/miniirc) and [GitLab](https://gitlab.com/luk3yx/miniirc).* [Python 3.4+]: https://img.shields.io/badge/python-3.4+-blue.svg [Available on PyPI.]: https://img.shields.io/pypi/v/miniirc.svg [License: MIT]: https://img.shields.io/pypi/l/miniirc.svg [deprecations list]: #deprecations ## Parameters ```py 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.* ### Typical usage You don't need to add every argument, and the `ip`, `port`, `nick`, and `channels` arguments should be specified as positional arguments. ```py irc = miniirc.IRC('irc.example.com', 6697, 'my-bot', ['#my-channel'], ns_identity=('my-bot', 'hunter2'), executor=concurrent.futures.ThreadPoolExecutor(), keepnick=True) ``` If you are not doing anything with the main thread after connecting to IRC, please call `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). ```py irc.wait_until_disconnected() ``` ### Parameter descriptions | Parameter | Description | | ------------- | -------------------------------------------------------- | | `ip` | The IP/hostname of the IRC server to connect to. | | `port` | The port to connect to. | | `nick` | The nickname of the bot. | | `channels` | 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. | | `ssl` | Enable TLS/SSL. If `None`, TLS is disabled unless the port is `6697`. | | `ident` | The ident to use, defaults to `nick`. | | `realname` | The realname to use, defaults to `nick` as well. | | `persist` | Whether to automatically reconnect. | | `debug` | 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 `logging.debug`). | | `ns_identity` | The NickServ account to use as a tuple/list of length 2 (`('', '')`). For compatibility, this can be a string (`' '`). | | `auto_connect`| Runs `irc.connect()` straight away. | | `ircv3_caps` | A set() of additional IRCv3 capabilities to request. SASL is auto-added if `ns_identity` is specified. | | `connect_modes` | A mode string (for example `'+B'`) of UMODEs to set when connected. | | `quit_message`| Sets the default quit message. This can be modified per-quit with `irc.disconnect()`. | | `ping_interval` | If no packets are sent or received for this amount of seconds, miniirc will send a `PING`, and if no reply is sent, after the ping timeout, miniirc will attempt to reconnect. Set to `None` to disable. | | `ping_timeout` | The ping timeout used alongside the above `ping_interval` option, if unspecified will default to `ping_interval`. | | `verify_ssl` | 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 `pip3 install certifi` first. | | `executor` | An instance of `concurrent.futures.ThreadPoolExecutor` to use when running handlers. | | `keepnick` | If enabled, miniirc will attempt to obtain the original nick like ZNC's *keepnick. `irc.nick` will be the original nickname rather than the current one. | *The only mandatory parameters are `ip`, `port`, and `nick`.* ## Functions | Function | Description | | ------------- | -------------------------------------------------------- | | `change_parser(parser=...)` | *See the message parser section for documentation.* | | `connect()` | Connects to the IRC server if not already connected. | | `ctcp(target, *msg, reply=False, tags=None)` | Sends a `CTCP` request or reply to `target`. | | `debug(...)` | Debug, calls `print(...)` if debug mode is on. | | `disconnect(msg=..., *, auto_reconnect=False)`| Disconnects from the IRC server. `auto_reconnect` will be overridden by `self.persist` if set to `True`. | | `Handler(...)` | An event handler, see [Handlers](#handlers) for more info. | | `me(target, *msg, tags=None)` | Sends a `/me` (`CTCP ACTION`) to `target`. | | `msg(target, *msg, tags=None)` | Sends a `PRIVMSG` to `target`. `target` should not contain spaces or start with a colon. | | `notice(target, *msg, tags=None)` | Sends a `NOTICE` to `target`. `target` should not contain spaces or start with a colon. | | `quote(*msg, force=False, tags=None)` | Sends a raw message to IRC, use `force=True` to send while disconnected. Do not send multiple commands in one `irc.quote()`, as the newlines will be stripped and it will be sent as one command. The `tags` parameter optionally allows you to add a `dict` with IRCv3 client tags (all starting in `+`), and will not be sent to IRC servers that do not support client tags. | | `send(*msg, force=False, tags=None)` | Sends a command to the IRC server, treating every positional argument as a parameter. The usage of this is recommended over `irc.quote()` unless you know what you are doing. | | `wait_until_disconnected()` | Waits until the IRC server is disconnected and automatic reconnecting is turned off. | *Note that if `force=False` on `irc.quote` (or `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.connected` is `None`).* ### irc.quote and irc.send The two functions `irc.quote` and `irc.send` may sound similar, however are fundamentally different: `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). #### Examples - `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 `#channel\xa0:Hello,`, where `\xa0` is a non-breaking space. *If you are unsure and do not need compatibility with miniirc <1.5.0, use `irc.send()`. `PRIVMSG` is just used as an example, if you need to send `PRIVMSG`s use `irc.msg()` instead.* ## Variables *These variables should not be changed outside `miniirc.py`.* | Variable | Description | | ------------- | -------------------------------------------------------- | | `active_caps` | A `set` of IRCv3 capabilities that have been successfully negotiated with the IRC server. This is empty while disconnected. | | `connected` | A boolean (or `None`), `True` when miniirc is connected, `False` when miniirc is connecting, and `None` when miniirc is not connected. | | `current_nick` | The bot/client's current nickname. Do not modify this, and use this instead of `irc.nick` when getting the bot's current nickname. | | `isupport` | A `dict` with values (not necessarily strings) from `ISUPPORT` messages sent to the client. | | `msglen` | The maximum length (in bytes) of messages (including `\r\n`). This is automatically changed if the server supports the `oragono.io/maxline-2` capability. | | `nick` | The nickname to use when connecting to IRC. Until miniirc v2.0.0, you should only use or modify this while disconnected, as it is currently automatically updated with nickname changes. | The following arguments passed to `miniirc.IRC` are also available: `ip`, `port`, `channels`, `ssl`, `ident`, `realname`, `persist`, `connect_modes`, `quit_message`, `ping_interval`, `verify_ssl`. ## Handlers `miniirc.Handler` and `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 (`irc.Handler`). The basic syntax for a handler is as followed, where `*events` is a list of events (`PRIVMSG`, `NOTICE`, etc) are called. ```py 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 parameter, setting `colon` to `False` is strongly recommended. If the `colon` parameter is omitted, it defaults to `True`, however this will change when miniirc v2.0.0 is released. - Although `Handler` and `CmdHandler` currently accept any object that can be converted to a string, every event is converted to a string internally. - Not specifying the [`ircv3`](#ircv3-tags) parameter when it is not required prevents a redundant `dict` from being created. - To add handlers to a specific `IRC` object and not every one in existence, use `irc.Handler` and `irc.CmdHandler` instead. If you want to create a `Bot` or `Client` class and automatically add handlers to `IRC` objects created inside it, see [making existing functions handlers](#making-existing-functions-handlers). ### Hostmask object Hostmasks are tuples with the format `('user', 'ident', 'hostname')`. If `ident` and `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 `hostmask` 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 empty strings. ### Making existing functions handlers You can make existing functions handlers (for example class instance methods) with `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 `IRC` object. You can also add multiple handlers of the same type easily: ```py 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 `Bot` (or `Client`) class and add class-specific handlers without creating global process-wide handlers or creating a wrapper function for every class instance. ### IRCv3 support #### IRCv3 tags If you want your handler to support IRCv3 message tags, you need to add `ircv3=True` to the `Handler` or `CmdHandler` decorator. You will need to add a `tags` parameter to your function after `hostmask`. IRCv3 tags are sent to the handlers as `dict`s, with values of either strings or `True`. *miniirc will automatically un-escape IRCv3 tag values.* ```py import miniirc @miniirc.Handler(*events, colon=False, ircv3=True) def handler(irc, hostmask, tags, args): pass ``` #### IRCv3 capabilities 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 `colon` argument for `Handler` when creating these handlers to avoid unexpected side-effects. ```py 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[0]) # 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 `str`) and 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. ```py 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 `irc.change_parser(func=...)`. If `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. ```py 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 `irc` and `hostmask`), containing a string with the command name (such as `PRIVMSG`). #### Catch-all handlers **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.* ### Example ```py 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[0], 'sent a message to', args[0], 'with content', args[1]) # nickname sent a message to #channel with content :Hello, world! @miniirc.CmdHandler('PRIVMSG', 'NOTICE', colon=False) def cmdhandler(irc, command, hostmask, args): print(hostmask[0], 'sent a', command, 'to', args[0], 'with content', args[1]) # nickname sent a PRIVMSG to #channel with content Hello, world! ``` This will print a line whenever the bot gets a `PRIVMSG` or `NOTICE`. ## Misc functions miniirc provides the following helper functions: | Name | Description | | ----------------------------- | ----------------------------------------- | | `miniirc.get_ca_certs()` | Runs `certifi.where()` if `certifi` is installed, otherwise returns `None`. | | `miniirc.ircv3_message_parser(msg)` | The default IRCv2/IRCv3 message parser, returns `cmd, hostmask, tags, args`. | | `miniirc.ver` | A tuple containing version information. | | `miniirc.version` | The `CTCP VERSION` reply, can be changed. | The version numbering system should be similar to [SemVer](https://semver.org/), 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 there is a bug/error in Python 3.4 or newer, please open an issue or pull request on [GitHub](https://github.com/luk3yx/miniirc/issues) or [GitLab](https://gitlab.com/luk3yx/miniirc/issues). *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.* ## miniirc_extras If you want more advanced(-ish) features such as user tracking, you can use [miniirc_extras](https://pypi.org/project/miniirc-extras/) ([GitHub](https://github.com/luk3yx/miniirc_extras), [GitLab](https://gitlab.com/luk3yx/miniirc_extras)). Note that miniirc_extras is still in beta and there will be breaking API changes in the future. ## Deprecations If miniirc v2.0.0 is ever released, the following breaking changes will (probably) be made: - Internal-only attributes `irc.handlers`, `irc.sock`, and `irc.sendq` (please do not use these) will be renamed. Again, please do not use these. - `irc.nick` will always be the nickname used when connecting to IRC rather than the current nickname, use `irc.current_nick` for the current nickname (since v1.4.3). - `irc.ns_identity` will 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 `ns_identity` keyword argument. - No exceptions will be raised in `irc.quote`/`irc.send` with `force=True` when the socket is closed. Instead of relying on these exceptions, use `irc.connected` which is set to `None` when 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. - The `colon` keyword argument to `Handler` and `CmdHandler` will default to `False` instead of `True`. - 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. - The `extended-join` capability will be requested by default, use `args[0]` instead of `args[-1]` to get the channel from a `JOIN` event. - The `tags` keyword argument will be read-only. ## Working examples/implementations 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](https://github.com/luk3yx/lurklite) link.* - [stdinbot] - A very simple bot that dumps stdin to an IRC channel. *[GitHub](https://github.com/luk3yx/stdinbot) link.* *Want to add your own bot/client to this list? Open an issue on [GitHub](https://github.com/luk3yx/miniirc/issues) or [GitLab](https://gitlab.com/luk3yx/miniirc/issues).* [irc-rss-feed-bot]: https://github.com/impredicative/irc-rss-feed-bot [irc-url-title-bot]: https://github.com/impredicative/irc-url-title-bot [lurklite]: https://gitlab.com/luk3yx/lurklite [stdinbot]: https://gitlab.com/luk3yx/stdinbot %package help Summary: Development documents and examples for miniirc Provides: python3-miniirc-doc %description help # miniirc [![Python 3.4+]](#python-version-support) [![Available on PyPI.]](https://pypi.org/project/miniirc/) [![License: MIT]](https://github.com/luk3yx/miniirc/blob/master/LICENSE.md) 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). *This repository is available on both [GitHub](https://github.com/luk3yx/miniirc) and [GitLab](https://gitlab.com/luk3yx/miniirc).* [Python 3.4+]: https://img.shields.io/badge/python-3.4+-blue.svg [Available on PyPI.]: https://img.shields.io/pypi/v/miniirc.svg [License: MIT]: https://img.shields.io/pypi/l/miniirc.svg [deprecations list]: #deprecations ## Parameters ```py 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.* ### Typical usage You don't need to add every argument, and the `ip`, `port`, `nick`, and `channels` arguments should be specified as positional arguments. ```py irc = miniirc.IRC('irc.example.com', 6697, 'my-bot', ['#my-channel'], ns_identity=('my-bot', 'hunter2'), executor=concurrent.futures.ThreadPoolExecutor(), keepnick=True) ``` If you are not doing anything with the main thread after connecting to IRC, please call `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). ```py irc.wait_until_disconnected() ``` ### Parameter descriptions | Parameter | Description | | ------------- | -------------------------------------------------------- | | `ip` | The IP/hostname of the IRC server to connect to. | | `port` | The port to connect to. | | `nick` | The nickname of the bot. | | `channels` | 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. | | `ssl` | Enable TLS/SSL. If `None`, TLS is disabled unless the port is `6697`. | | `ident` | The ident to use, defaults to `nick`. | | `realname` | The realname to use, defaults to `nick` as well. | | `persist` | Whether to automatically reconnect. | | `debug` | 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 `logging.debug`). | | `ns_identity` | The NickServ account to use as a tuple/list of length 2 (`('', '')`). For compatibility, this can be a string (`' '`). | | `auto_connect`| Runs `irc.connect()` straight away. | | `ircv3_caps` | A set() of additional IRCv3 capabilities to request. SASL is auto-added if `ns_identity` is specified. | | `connect_modes` | A mode string (for example `'+B'`) of UMODEs to set when connected. | | `quit_message`| Sets the default quit message. This can be modified per-quit with `irc.disconnect()`. | | `ping_interval` | If no packets are sent or received for this amount of seconds, miniirc will send a `PING`, and if no reply is sent, after the ping timeout, miniirc will attempt to reconnect. Set to `None` to disable. | | `ping_timeout` | The ping timeout used alongside the above `ping_interval` option, if unspecified will default to `ping_interval`. | | `verify_ssl` | 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 `pip3 install certifi` first. | | `executor` | An instance of `concurrent.futures.ThreadPoolExecutor` to use when running handlers. | | `keepnick` | If enabled, miniirc will attempt to obtain the original nick like ZNC's *keepnick. `irc.nick` will be the original nickname rather than the current one. | *The only mandatory parameters are `ip`, `port`, and `nick`.* ## Functions | Function | Description | | ------------- | -------------------------------------------------------- | | `change_parser(parser=...)` | *See the message parser section for documentation.* | | `connect()` | Connects to the IRC server if not already connected. | | `ctcp(target, *msg, reply=False, tags=None)` | Sends a `CTCP` request or reply to `target`. | | `debug(...)` | Debug, calls `print(...)` if debug mode is on. | | `disconnect(msg=..., *, auto_reconnect=False)`| Disconnects from the IRC server. `auto_reconnect` will be overridden by `self.persist` if set to `True`. | | `Handler(...)` | An event handler, see [Handlers](#handlers) for more info. | | `me(target, *msg, tags=None)` | Sends a `/me` (`CTCP ACTION`) to `target`. | | `msg(target, *msg, tags=None)` | Sends a `PRIVMSG` to `target`. `target` should not contain spaces or start with a colon. | | `notice(target, *msg, tags=None)` | Sends a `NOTICE` to `target`. `target` should not contain spaces or start with a colon. | | `quote(*msg, force=False, tags=None)` | Sends a raw message to IRC, use `force=True` to send while disconnected. Do not send multiple commands in one `irc.quote()`, as the newlines will be stripped and it will be sent as one command. The `tags` parameter optionally allows you to add a `dict` with IRCv3 client tags (all starting in `+`), and will not be sent to IRC servers that do not support client tags. | | `send(*msg, force=False, tags=None)` | Sends a command to the IRC server, treating every positional argument as a parameter. The usage of this is recommended over `irc.quote()` unless you know what you are doing. | | `wait_until_disconnected()` | Waits until the IRC server is disconnected and automatic reconnecting is turned off. | *Note that if `force=False` on `irc.quote` (or `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.connected` is `None`).* ### irc.quote and irc.send The two functions `irc.quote` and `irc.send` may sound similar, however are fundamentally different: `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). #### Examples - `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 `#channel\xa0:Hello,`, where `\xa0` is a non-breaking space. *If you are unsure and do not need compatibility with miniirc <1.5.0, use `irc.send()`. `PRIVMSG` is just used as an example, if you need to send `PRIVMSG`s use `irc.msg()` instead.* ## Variables *These variables should not be changed outside `miniirc.py`.* | Variable | Description | | ------------- | -------------------------------------------------------- | | `active_caps` | A `set` of IRCv3 capabilities that have been successfully negotiated with the IRC server. This is empty while disconnected. | | `connected` | A boolean (or `None`), `True` when miniirc is connected, `False` when miniirc is connecting, and `None` when miniirc is not connected. | | `current_nick` | The bot/client's current nickname. Do not modify this, and use this instead of `irc.nick` when getting the bot's current nickname. | | `isupport` | A `dict` with values (not necessarily strings) from `ISUPPORT` messages sent to the client. | | `msglen` | The maximum length (in bytes) of messages (including `\r\n`). This is automatically changed if the server supports the `oragono.io/maxline-2` capability. | | `nick` | The nickname to use when connecting to IRC. Until miniirc v2.0.0, you should only use or modify this while disconnected, as it is currently automatically updated with nickname changes. | The following arguments passed to `miniirc.IRC` are also available: `ip`, `port`, `channels`, `ssl`, `ident`, `realname`, `persist`, `connect_modes`, `quit_message`, `ping_interval`, `verify_ssl`. ## Handlers `miniirc.Handler` and `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 (`irc.Handler`). The basic syntax for a handler is as followed, where `*events` is a list of events (`PRIVMSG`, `NOTICE`, etc) are called. ```py 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 parameter, setting `colon` to `False` is strongly recommended. If the `colon` parameter is omitted, it defaults to `True`, however this will change when miniirc v2.0.0 is released. - Although `Handler` and `CmdHandler` currently accept any object that can be converted to a string, every event is converted to a string internally. - Not specifying the [`ircv3`](#ircv3-tags) parameter when it is not required prevents a redundant `dict` from being created. - To add handlers to a specific `IRC` object and not every one in existence, use `irc.Handler` and `irc.CmdHandler` instead. If you want to create a `Bot` or `Client` class and automatically add handlers to `IRC` objects created inside it, see [making existing functions handlers](#making-existing-functions-handlers). ### Hostmask object Hostmasks are tuples with the format `('user', 'ident', 'hostname')`. If `ident` and `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 `hostmask` 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 empty strings. ### Making existing functions handlers You can make existing functions handlers (for example class instance methods) with `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 `IRC` object. You can also add multiple handlers of the same type easily: ```py 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 `Bot` (or `Client`) class and add class-specific handlers without creating global process-wide handlers or creating a wrapper function for every class instance. ### IRCv3 support #### IRCv3 tags If you want your handler to support IRCv3 message tags, you need to add `ircv3=True` to the `Handler` or `CmdHandler` decorator. You will need to add a `tags` parameter to your function after `hostmask`. IRCv3 tags are sent to the handlers as `dict`s, with values of either strings or `True`. *miniirc will automatically un-escape IRCv3 tag values.* ```py import miniirc @miniirc.Handler(*events, colon=False, ircv3=True) def handler(irc, hostmask, tags, args): pass ``` #### IRCv3 capabilities 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 `colon` argument for `Handler` when creating these handlers to avoid unexpected side-effects. ```py 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[0]) # 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 `str`) and 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. ```py 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 `irc.change_parser(func=...)`. If `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. ```py 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 `irc` and `hostmask`), containing a string with the command name (such as `PRIVMSG`). #### Catch-all handlers **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.* ### Example ```py 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[0], 'sent a message to', args[0], 'with content', args[1]) # nickname sent a message to #channel with content :Hello, world! @miniirc.CmdHandler('PRIVMSG', 'NOTICE', colon=False) def cmdhandler(irc, command, hostmask, args): print(hostmask[0], 'sent a', command, 'to', args[0], 'with content', args[1]) # nickname sent a PRIVMSG to #channel with content Hello, world! ``` This will print a line whenever the bot gets a `PRIVMSG` or `NOTICE`. ## Misc functions miniirc provides the following helper functions: | Name | Description | | ----------------------------- | ----------------------------------------- | | `miniirc.get_ca_certs()` | Runs `certifi.where()` if `certifi` is installed, otherwise returns `None`. | | `miniirc.ircv3_message_parser(msg)` | The default IRCv2/IRCv3 message parser, returns `cmd, hostmask, tags, args`. | | `miniirc.ver` | A tuple containing version information. | | `miniirc.version` | The `CTCP VERSION` reply, can be changed. | The version numbering system should be similar to [SemVer](https://semver.org/), 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 there is a bug/error in Python 3.4 or newer, please open an issue or pull request on [GitHub](https://github.com/luk3yx/miniirc/issues) or [GitLab](https://gitlab.com/luk3yx/miniirc/issues). *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.* ## miniirc_extras If you want more advanced(-ish) features such as user tracking, you can use [miniirc_extras](https://pypi.org/project/miniirc-extras/) ([GitHub](https://github.com/luk3yx/miniirc_extras), [GitLab](https://gitlab.com/luk3yx/miniirc_extras)). Note that miniirc_extras is still in beta and there will be breaking API changes in the future. ## Deprecations If miniirc v2.0.0 is ever released, the following breaking changes will (probably) be made: - Internal-only attributes `irc.handlers`, `irc.sock`, and `irc.sendq` (please do not use these) will be renamed. Again, please do not use these. - `irc.nick` will always be the nickname used when connecting to IRC rather than the current nickname, use `irc.current_nick` for the current nickname (since v1.4.3). - `irc.ns_identity` will 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 `ns_identity` keyword argument. - No exceptions will be raised in `irc.quote`/`irc.send` with `force=True` when the socket is closed. Instead of relying on these exceptions, use `irc.connected` which is set to `None` when 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. - The `colon` keyword argument to `Handler` and `CmdHandler` will default to `False` instead of `True`. - 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. - The `extended-join` capability will be requested by default, use `args[0]` instead of `args[-1]` to get the channel from a `JOIN` event. - The `tags` keyword argument will be read-only. ## Working examples/implementations 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](https://github.com/luk3yx/lurklite) link.* - [stdinbot] - A very simple bot that dumps stdin to an IRC channel. *[GitHub](https://github.com/luk3yx/stdinbot) link.* *Want to add your own bot/client to this list? Open an issue on [GitHub](https://github.com/luk3yx/miniirc/issues) or [GitLab](https://gitlab.com/luk3yx/miniirc/issues).* [irc-rss-feed-bot]: https://github.com/impredicative/irc-rss-feed-bot [irc-url-title-bot]: https://github.com/impredicative/irc-url-title-bot [lurklite]: https://gitlab.com/luk3yx/lurklite [stdinbot]: https://gitlab.com/luk3yx/stdinbot %prep %autosetup -n miniirc-1.9.1 %build %py3_build %install %py3_install install -d -m755 %{buildroot}/%{_pkgdocdir} if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi pushd %{buildroot} if [ -d usr/lib ]; then find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst fi if [ -d usr/lib64 ]; then find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst fi if [ -d usr/bin ]; then find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst fi if [ -d usr/sbin ]; then find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst fi touch doclist.lst if [ -d usr/share/man ]; then find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst fi popd mv %{buildroot}/filelist.lst . mv %{buildroot}/doclist.lst . %files -n python3-miniirc -f filelist.lst %dir %{python3_sitelib}/* %files help -f doclist.lst %{_docdir}/* %changelog * Wed Apr 12 2023 Python_Bot - 1.9.1-1 - Package Spec generated