<commit_before># -*- coding: utf-8 -*-

"""
:mod:`gygax.irc` --- Internet Relay Chat client.
================================================

:mod:`gygax.irc` implements all functionality needed to communicate with an IRC
server. It does so using :mod:`asynchat` from the Python Standard Library,
which handles all asynchronous network complexities and leaves :mod:`gygax.irc`
only with the task of handling the IRC protocol.

:mod:`gygax.irc` defines the abstract class :class:`Client`, which can be
subclassed and provided an implementation for the :func:`Client.handle` method
to build IRC bots or custom clients.
"""

import asynchat
import asyncore
import logging

log = logging.getLogger(__name__)

class Client(asynchat.async_chat):

    """An abstract class which implements a minimal, but functional subset of
    the IRC client protocol.

    :param str nick: The client's nickname to use. Also used as the username.
    :param str real: The client's realname to use.

    Handles most IRC messages itself, but on private messages (messages sent to
    the client directly or to a channel the client is on) calls the
    :meth:`handle` abstract method. This method can be overridden by subclasses
    to create IRC bots or custom clients.
    """

    @property
    def nick(self):
        """The client's nickname. Also used as the username."""
        return self._nick

    @property
    def real(self):
        """The client's realname."""
        return self._real

    @property
    def channels(self):
        """A :func:`set` containing the channels the client is connected to."""
        return self._channels

    @property
    def password(self):
        """The connection password used."""
        return self._password

    def __init__(self, nick, real):
        """Creates a new IRC client and initializes its attributes."""
        super().__init__()
        self.set_terminator(b"\r\n")
        self._incoming = []

        self._nick = nick
        self._real = real
        self._channels = set()
        self._password = None

    def run(self, address, channels=None, password=None):
        """Connect to an IRC server and start the client's main loop.

        :param tuple address: A tuple ``(host, port)`` with the address of the
            IRC server to connect to.
        :param iter channels: The list of channels to join on startup.
        :param str password: The optional connection password to use.
        """
        self._channels = channels or self.channels
        self._password = password or self.password

        log.info("connecting to {}:{}...".format(*address))
        self.create_socket()
        self.connect(address)
        asyncore.loop()

    def handle_connect(self):
        log.info("connected")
        log.info("registering as {}...".format(self.nick))
        if self.password:
            self._command("PASS", self.password)
        self._command("NICK", self.nick)
        self._command("USER", self.nick, "0", "*", self.real)

    def _command(self, command, *args):
        """Send a command to the IRC server."""
        message_parts = [command]
        if args:
            args = list(args)
            if " " in args[-1]:
                args[-1] = ":" + args[-1]
            message_parts += args

        message = " ".join(message_parts).encode("utf-8")
        if len(message) > 510:
            newlen = 510
            while message[newlen] & 0xc0 == 0x80:  # UTF-8 continuation byte
                newlen -= 1
            log.warning("truncating message from {} to {} bytes".format(
                len(message), newlen))
            message = message[:newlen]

        log.debug("pushing {}".format(message))
        self.push(message + b"\r\n")

    def message(self, recipient, text):
        """Send a private message to the IRC network.

        :param str recipient: The recipient of the message. Can be a user or a
            channel name.
        :param str text: The text of the private message to send.
        """
        self._command("PRIVMSG", recipient, text)
<commit_msg>irc: Debug log pushed messages as Unicode<commit_after># -*- coding: utf-8 -*-

"""
:mod:`gygax.irc` --- Internet Relay Chat client.
================================================

:mod:`gygax.irc` implements all functionality needed to communicate with an IRC
server. It does so using :mod:`asynchat` from the Python Standard Library,
which handles all asynchronous network complexities and leaves :mod:`gygax.irc`
only with the task of handling the IRC protocol.

:mod:`gygax.irc` defines the abstract class :class:`Client`, which can be
subclassed and provided an implementation for the :func:`Client.handle` method
to build IRC bots or custom clients.
"""

import asynchat
import asyncore
import logging

log = logging.getLogger(__name__)

class Client(asynchat.async_chat):

    """An abstract class which implements a minimal, but functional subset of
    the IRC client protocol.

    :param str nick: The client's nickname to use. Also used as the username.
    :param str real: The client's realname to use.

    Handles most IRC messages itself, but on private messages (messages sent to
    the client directly or to a channel the client is on) calls the
    :meth:`handle` abstract method. This method can be overridden by subclasses
    to create IRC bots or custom clients.
    """

    @property
    def nick(self):
        """The client's nickname. Also used as the username."""
        return self._nick

    @property
    def real(self):
        """The client's realname."""
        return self._real

    @property
    def channels(self):
        """A :func:`set` containing the channels the client is connected to."""
        return self._channels

    @property
    def password(self):
        """The connection password used."""
        return self._password

    def __init__(self, nick, real):
        """Creates a new IRC client and initializes its attributes."""
        super().__init__()
        self.set_terminator(b"\r\n")
        self._incoming = []

        self._nick = nick
        self._real = real
        self._channels = set()
        self._password = None

    def run(self, address, channels=None, password=None):
        """Connect to an IRC server and start the client's main loop.

        :param tuple address: A tuple ``(host, port)`` with the address of the
            IRC server to connect to.
        :param iter channels: The list of channels to join on startup.
        :param str password: The optional connection password to use.
        """
        self._channels = channels or self.channels
        self._password = password or self.password

        log.info("connecting to {}:{}...".format(*address))
        self.create_socket()
        self.connect(address)
        asyncore.loop()

    def handle_connect(self):
        log.info("connected")
        log.info("registering as {}...".format(self.nick))
        if self.password:
            self._command("PASS", self.password)
        self._command("NICK", self.nick)
        self._command("USER", self.nick, "0", "*", self.real)

    def _command(self, command, *args):
        """Send a command to the IRC server."""
        message_parts = [command]
        if args:
            args = list(args)
            if " " in args[-1]:
                args[-1] = ":" + args[-1]
            message_parts += args

        message = " ".join(message_parts).encode("utf-8")
        if len(message) > 510:
            newlen = 510
            while message[newlen] & 0xc0 == 0x80:  # UTF-8 continuation byte
                newlen -= 1
            log.warning("truncating message from {} to {} bytes".format(
                len(message), newlen))
            message = message[:newlen]

        log.debug("pushing {}".format(message.decode("utf-8")))
        self.push(message + b"\r\n")

    def message(self, recipient, text):
        """Send a private message to the IRC network.

        :param str recipient: The recipient of the message. Can be a user or a
            channel name.
        :param str text: The text of the private message to send.
        """
        self._command("PRIVMSG", recipient, text)

{'fraction_non_alphanumeric': 0.11844352281044157, 'fraction_numerical': 0.004757257867772627, 'mean_word_length': 2.4756252649427726, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '856894', 'n_tokens_mistral': 2251, 'n_tokens_neox': 2130, 'n_words': 820}