* Standards-abiding: Based on [RFC1459](https://tools.ietf.org/html/rfc1459.html) with some small extension tweaks, with full support of optional extension standards:
* Modularized and extensible: Features on top of RFC1459 are implemented as seperate modules for a user to pick and choose, and write their own. Broad features are written to be as extensible as possible.
*`pydle.MinimalClient` - tinier client that supports `pydle.BasicClient` plus some features in `pydle.features`. (currently `ctcp`, `isupport` and `rfc1459`)
*`pydle.BasicClient` - base IRC message handler. Has no functionality.
-`pydle.features.rfc1459` - basic [RFC1459](https://tools.ietf.org/html/rfc1459.html) implementation with a few commonly-implemented [RF](https://tools.ietf.org/html/rfc2810.html)[C2](https://tools.ietf.org/html/rfc2811.html)[81](https://tools.ietf.org/html/rfc2812.html)[x](https://tools.ietf.org/html/rfc2813.html) extensions.
+ `pydle.features.ircv3_1.sasl` - [Simple Authentication and Security Layer](http://ircv3.atheme.org/extensions/sasl-3.1) support - currently limited to the `PLAIN` mechanism.
+ `pydle.features.ircv3_1.ircv3_1` - [Miscellaneous](http://ircv3.atheme.org/extensions/multi-prefix-3.1) [features](http://ircv3.atheme.org/extensions/account-notify-3.1) [ensuring](http://ircv3.atheme.org/extensions/away-notify-3.1) [support](http://ircv3.atheme.org/extensions/extended-join-3.1) for [IRCv3.1](http://ircv3.atheme.org/).
-`pydle.features.ircv3_2` - [IRCv3.2](http://ircv3.atheme.org) support (partial).
If you want to customize bot features, you can subclass `pydle.BasicClient` and one or more features from `pydle.features` or your own feature classes, like such:
```python
# Only support RFC1459 (+small features), CTCP and our own ACME extension to IRC.
**Q: When constructing my own client class from several base classes, I get the following error: _TypeError: Cannot create a consistent method resolution order (MRO) for bases X, Y, Z_. What causes this and how can I solve it?**
Pydle's use of class inheritance as a feature model may cause method resolution order conflicts if a feature inherits from a different feature, while a class inherits from both the original feature and the inheriting feature. To solve such problem, pydle offers a `featurize` function that will automatically put all classes in the right order and create an appropriate base class:
```python
# Purposely mis-ordered base classes, as SASLSupport inherits from CapabilityNegotiationSupport, but everything works fine.
`Client(nickname, fallback_nicknames=[], username=None, realname=None)` - construct a client. if `username`/`realname` are not given, they will be constructed from the nickname.
with `pydle.features.tls`, two extra keyword arguments are added:
-`tls_client_cert`: path to client certificate to use for TLS authentication;
-`tls_client_cert_key`: path to keyfile to use for `tls_client_cert`.
with `pydle.features.sasl`, three extra keyword arguments are added:
-`sasl_identity`: `AUTHZID` to use for SASL authentication. Default and most common option is `''` (empty);
`Client.whois(nickname)` - retrieve information about user. This method returns a `pydle.async.Future`: calling methods should be wrapped in the `pydle.coroutine` decorator and `yield` the returned future.
`Client.whowas(nickname)` - retrieve information about former user. This method returns a `pydle.async.Future`: see `Client.whois(nickname)` for usage.
with `pydle.features.cap`, one extra method is added:
-`Client.capability_negotiated(cap, success=True)` - indicate the capability `cap` has been negotiated, where `success` indicates if negotiation succeeded.
`Client.on_quit(user, reason=None)` - callback called when someone (maybe the client) quit the network.
`Client.on_kill(user, source, reason)` - callback called when someone (maybe the client) was killed from the network.
`Client.on_message(target, source, message)` - callback called when the client receives a PRIVMSG, either in a channel or privately.
`Client.on_channel_message(channel, source, message)` - callback called when the client receives a PRIVMSG in a channel.
`Client.on_private_message(source, message)` - callback called when the client receives a private PRIVMSG.
`Client.on_notice(target, source, message)` - callback called when the client receives a NOTICE, either in a channel or privately.
`Client.on_channel_notice(target, source, message)` - callback called when the client receives a NOTICE in a channel.
`Client.on_private_notice(source, message)` - callback called when the client receives a private NOTICE.
`Client.on_invite(channel, source)` - callback called when the client receives an invite to a channel.
`Client.on_join(channel, user)` - callback called when someone (maybe the client) joins a channel.
`Client.on_part(channel, user, message=None)` - callback called when someone (maybe the client) parted a channel.
`Client.on_kick(channel, user, source, reason=None)` - callback called when someone (maybe the client) was kicked from a channel.
`Client.on_topic_change(channel, topic, source)` - callback called when someone sets the topic in a channel.
`Client.on_mode_change(target, modes, source)` - callback called when either someone sets new modes on a channel or the client (or server) change their user mode.
`Client.on_nick_change(old, new)` - callback called when someone (maybe the client) changes their nickname.
`Client.on_unknown(command, source, params)` - callback called when the client receives a raw IRC message it doesn't know how to deal with.
with `pydle.features.ctcp`, two extra callbacks are added, and two generic callbacks:
-`Client.on_ctcp(target, source, query)` - callback called when the client receives a CTCP query, either directed to a channel or to the client privately, that is not handled by `Client.on_ctcp_<query>`;
-`Client.on_ctcp_reply(target, source, query, reply)` - callback called when the client receives a CTCP response, that is not handled by `Client.on_ctcp_<query>_reply`;
-`Client.on_ctcp_<query>(target, source)` - callback called when the client receives a CTCP <query>. The query name should be lower case. Example: `on_ctcp_version(target, source)` will be called if the client receives a CTCP VERSION request;
-`Client.on_ctcp_<query>_reply(target, source, reply)` - callback called when the client receives a CTCP <query> response.
with `pydle.features.isupport`, one generic callback is added:
-`Client.on_isupport_<feature>(value)` - callback called when the server announced support for ISUPPORT feature `feature`. `value` is None if not given by server.
with `pydle.features.cap`, three generic callbacks are added:
-`Client.on_capability_<cap>_available()` - callback called when the server announced support for capability `cap`. Should return whether or not the client wants to request this capability.
-`Client.on_capability_<cap>_enabled()` - callback called when the server acknowledges the client's request for capability `cap`. Should return one of three following values:
*`pydle.CAPABILITY_NEGOTIATED` - default value assumed when nothing returned. The capability has been successfully negotiated.
*`pydle.CAPABILITY_NEGOTIATING` - the callback is still negotiating the capability. Stall general capability negotiation until `Client.capability_negotiated(<cap>)` has been called.
*`pydle.CAPABILITY_FAILED` - the callback failed to negotiate the capability. Attempt to disable it again.
-`Client.on_capability_<cap>_disabled()` - callback called when capability `cap` that was requested before has been disabled.
You can also overload `Client.on_raw_<cmd>(message)`, where `cmd` is the raw IRC command (either a text command or a zero-filled numeric code) and `message` an instance of (a subclass of) `protocol.Message` if you really want to, but this is not advisable if you're not building features as it may disable certain built-in functionalities if you're not careful.
`python3 -m pydle.utils.irccat` - simple [irccat](http://sourceforge.net/projects/irccat/)-like implementation built on top of pydle. Read raw IRC commands from stdin, dumps incoming messages to stdout.
`python3 -m pydle.utils.console` - interactive console for a Pydle bot. `self` is defined in-scope as the running bot instance.
`python3 -m pydle.utils.run` - run a Pydle bot in the foreground.
TODO
----
* Work on documentation.
* Finalize IRCv3.2 support.
* Add DCC support.
License
-------
Pydle is licensed under the 3-clause BSD license. See LICENSE.md for details.