pydle/README.md

14 KiB

pydle

Python IRC library.

pydle is a compact, flexible and standards-abiding IRC library for Python 3.

Features

  • Compact: At ~1700SLoC at time of writing, it's not hard to find what you're looking for in the well-organized source code.
  • Standards-abiding: Based on RFC1459 with some small extension tweaks, with full support of optional extension standards:
  • Asynchronous: IRC is an asynchronous protocol and so should a library that implements it be. Callbacks are used to process events from the server.
  • 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.
  • Liberally licensed: The 3-clause BSD license ensures you can use it everywhere.

Structure

  • pydle.Client - full-featured client that supports pydle.BasicClient plus all the features in pydle.features.
  • pydle.MinimalClient - tinier client that supports pydle.BasicClient plus some features in pydle.features. (currently ctcp, isupport and tls)
  • pydle.BasicClient - basic RFC1459 implementation with a few commonly-implemented RFC281x extensions.
  • pydle.features - extra (official/unofficial) IRC extensions
  • pydle.ClientPool - a 'pool' of several clients in order to handle multiple clients in one swift main loop.

Basic Usage

python3 setup.py install

From there, you can import pydle and subclass pydle.Client for your own functionality.

Setting a nickname and starting a connection over TLS:

import pydle

# Simple echo bot.
class MyOwnBot(pydle.Client):
    def on_connect(self):
         self.join('#bottest')

    def on_message(self, source, target, message):
         self.message(target, message)

client = MyOwnBot('MyBot', realname='My Bot')
client.connect('irc.rizon.net', 6697, tls=True, tls_verify=False)
client.handle_forever()

But wait, I want to handle multiple clients!

No worries! Use pydle.ClientPool like such:

pool = pydle.ClientPool()
for i in range(10):
    client = MyOwnBot('MyBot' + str(i))
    client.connect('irc.rizon.net', 6697, tls=True, tls_verify=False)
    pool.add(client)

# This will make sure all clients are treated in a fair way priority-wise.
pool.handle_forever()

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:

# Only support RFC1459 (+small features), CTCP and our own ACME extension to IRC.
class MyFeaturedBot(pydle.features.ctcp.CTCPSupport, acme.ACMESupport, pydle.BasicClient):
    pass

To create your own features, just subclass from pydle.BasicClient and start adding callbacks for IRC messages:

# Support custom ACME extension.
class ACMESupport(pydle.BasicClient):
    def on_raw_999(self, source, params):
        """ ACME's custom 999 numeric tells us to change our nickname. """
        nickname = params[0]
        self.nickname = nickname

API

pydle.Client

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);
  • sasl_username: SASL username (AUTHCID);
  • sasl_password: SASL password.

Client.connect(host, port=None, password=None, encoding='utf-8')- connect to server.

with pydle.features.tls, two extra keyword arguments are added:

  • tls: whether or not to use TLS for this connection. Default is False;
  • tls_verify: whether or not to strictly verify the server certificate. Default is False.

Client.disconnect() - disconnect from server.

Client.handle_forever() - a 'main loop'-esque method. Will not return until the client disconnected.

Attributes

Client.DEFAULT_QUIT_MESSAGE - default quit message when Client.quit() is called without arguments.

Client.connected - whether or not this client is connected.

Client.registered - whether or not this client has passed the IRC registration stage.

Client.connection - the pydle.connection.Connection instance associated with this client.

Client.logger - the pydle.logging.Logger instance associated with this client.

Client.nickname - get or set to retrieve or attempt to set current nickname.

Client.username - the current username. Changes will only take effect on reconnect.

Client.realname - the current realname. Changes will only take effect on reconnect.

Client.password - the server password used for this connection. Changes will only take effect on reconnect.

Client.motd - set after connecting. The IRC server Message of the Day, if any.

Client.network - set after connecting if sent by server. The IRC network this server belongs to.

Client.server_tag - a 'tag' to use for the currently connected to server.

Client.users - an informational dictionary about users the client knows about.

Client.channels - an informational dictionary about the channels the client is in.

with pydle.features.tls, two extra attributes are added:

  • Client.tls_client_cert - file path to TLS client certificate to use;
  • Client.tls_client_cert_key - file path to keyfile to use for Client.tls_client_cert.

with pydle.features.sasl, four extra attributes are added:

  • Client.SASL_TIMEOUT: amount of seconds to wait for response from server before aborting SASL authentication.
  • Client.sasl_identity: AUTHZID to use for SASL authentication. Default and most common option is '' (empty);
  • Client.sasl_username: SASL username (AUTHCID);
  • Client.sasl_password: SASL password.

IRC

Client.join(channel, password=None) - join channel.

Client.part(channel, reason=None) - part channel.

Client.cycle(channel) - rejoin channel.

Client.quit(message=pydle.DEFAULT_QUIT_MESSAGE) - quit network.

Client.message(target, message) - send a message.

Client.notice(target, message) - send a notice.

Client.mode(target, *modes) - set channel or user modes.

Client.away(message) - set self as away with message.

Client.back() - set self as not away anymore.

Client.raw(message) - send raw IRC command.

with pydle.features.ctcp, two extra methods are added:

  • Client.ctcp(target, query) - send CTCP request;
  • Client.ctcp_reply(target, query, response) - send CTCP response.

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.

Helpers

Client.is_channel(target) - return whether or not target is a channel.

Client.in_channel(channel) - return whether or not client is in channel.

Client.same_nick(left, right) - compare nicknames according to proper IRC case mapping.

Callbacks

Client.on_connect() - callback called after the client has successfully connected and registered to the server.

Client.on_disconnect() - callback called after the client has disconnected from the server.

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 . 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 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>(source, params), where cmd is the raw IRC command (either a text command or a zero-filled numeric code) 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.

pydle.ClientPool

ClientPool(clients) - instantiate a pool with clients as initial clients.

ClientPool.add(client) - add client to pool.

ClientPool.remove(client) - remove client from pool.

ClientPool.has_message() - check whether or not there are unprocessed message(s) available in this pool.

ClientPool.handle_message() - handle a single unprocessed message.

ClientPool.wait_for_message() - wait for a new message to arrive.

ClientPool.handle_forever() - enter main loop for pool. Will not return until all clients disconnected.

Utilities

python3 -m pydle.utils.irccat - simple 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.