summaryrefslogtreecommitdiff
path: root/python-miniirc.spec
diff options
context:
space:
mode:
Diffstat (limited to 'python-miniirc.spec')
-rw-r--r--python-miniirc.spec1288
1 files changed, 1288 insertions, 0 deletions
diff --git a/python-miniirc.spec b/python-miniirc.spec
new file mode 100644
index 0000000..450b04a
--- /dev/null
+++ b/python-miniirc.spec
@@ -0,0 +1,1288 @@
+%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 (`('<user>', '<password>')`). For compatibility, this can be a string (`'<user> <password>'`). |
+| `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 (`('<user>', '<password>')`). For compatibility, this can be a string (`'<user> <password>'`). |
+| `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 (`('<user>', '<password>')`). For compatibility, this can be a string (`'<user> <password>'`). |
+| `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 <Python_Bot@openeuler.org> - 1.9.1-1
+- Package Spec generated