<commit_before>"""Manages I/O for a single IRC server and client. This includes reading 
from the server and pushing a command to the server. It supports SSL 
connections.

"""
import asyncore, asynchat
import socket

try:
    import ssl
except ImportError:
    ssl_available = False
else:
    ssl_available = True
    import errno

import protocol
import responses


class Connection(asynchat.async_chat):
    """ This class represents an asynchronous connection with an IRC server. It
    handles all of the dirty work such as maintaining input and output with
    the server as well as automatically handling PING requests.
   
    """
    
    def __init__(self, ipv6=False):
        asynchat.async_chat.__init__(self)
        self.ping_auto_respond = True
        self.set_terminator("\r\n")
        self.collect_incoming_data = self._collect_incoming_data
        if ipv6:
            self.create_socket(socket.AF_INET6, socket.SOCK_STREAM)
        else:
            self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
    
    
    def connect(self, hostname, port=None, use_ssl=False, password=None):
        """ Create a connection to the specified host. If a port is given, it'll
        attempt to connect with that. A password may be specified and it'll
        be sent if the IRC server requires one.
        
        """
        self.hostname = hostname
        self.port = port
        self.use_ssl = use_ssl
        if use_ssl and not ssl_available:
            raise ImportError("Python's SSL module is unavailable.")
        elif use_ssl:
            port = port or 7000
            self.send = self._ssl_send
            self.recv = self._ssl_recv
        else:
            port = port or 6667
        asynchat.async_chat.connect(self, (hostname, port))
        if password is not None:
            self.execute("PASS", password)
    
    
    def found_terminator(self):
        """ Activated when ``\\r\\n`` is encountered. Do not call directly. """
        data = "".join(self.incoming)
        self.incoming = []
        prefix, command, params = protocol.parse_line(data)
        if command == "PING" and self.ping_auto_respond:
            self.execute("PONG", *params)
        if command.isdigit():
            command = responses.from_digit(command)
        self.handle_line(prefix, command, params)
    
    
    def execute(self, command, *params, **kwargs):
        """ This places an IRC command on the output queue. If you wish to use
        a trailing perameter, set it as a keyword argument, like so:
        
            >>> self.execute("PRIVMSG", "#channel", trailing="Hello!")
        
        """
        params = filter(lambda x:x is not None, params)
        if "trailing" in kwargs:
            params = list(params)
            params.append(":%s" % kwargs["trailing"])
        self.push("%s %s\r\n" % (command.upper(), " ".join(params)))
    
    <commit_msg>Fixed a small bug where trailing data was sometimes defaulting to None, which caused a string of ":None" to be sent, when it should have been ignored. For example, if we look at part_channel() in the SimpleClient, we see that message defaults to a None value, and is passed to the trailing keyword of execute(). That None value was then being converted into a string of ":None" and appended to the parameters. execute() should ignore None values.<commit_after>"""Manages I/O for a single IRC server and client. This includes reading 
from the server and pushing a command to the server. It supports SSL 
connections.

"""
import asyncore, asynchat
import socket

try:
    import ssl
except ImportError:
    ssl_available = False
else:
    ssl_available = True
    import errno

import protocol
import responses


class Connection(asynchat.async_chat):
    """ This class represents an asynchronous connection with an IRC server. It
    handles all of the dirty work such as maintaining input and output with
    the server as well as automatically handling PING requests.
   
    """
    
    def __init__(self, ipv6=False):
        asynchat.async_chat.__init__(self)
        self.ping_auto_respond = True
        self.set_terminator("\r\n")
        self.collect_incoming_data = self._collect_incoming_data
        if ipv6:
            self.create_socket(socket.AF_INET6, socket.SOCK_STREAM)
        else:
            self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
    
    
    def connect(self, hostname, port=None, use_ssl=False, password=None):
        """ Create a connection to the specified host. If a port is given, it'll
        attempt to connect with that. A password may be specified and it'll
        be sent if the IRC server requires one.
        
        """
        self.hostname = hostname
        self.port = port
        self.use_ssl = use_ssl
        if use_ssl and not ssl_available:
            raise ImportError("Python's SSL module is unavailable.")
        elif use_ssl:
            port = port or 7000
            self.send = self._ssl_send
            self.recv = self._ssl_recv
        else:
            port = port or 6667
        asynchat.async_chat.connect(self, (hostname, port))
        if password is not None:
            self.execute("PASS", password)
    
    
    def found_terminator(self):
        """ Activated when ``\\r\\n`` is encountered. Do not call directly. """
        data = "".join(self.incoming)
        self.incoming = []
        prefix, command, params = protocol.parse_line(data)
        if command == "PING" and self.ping_auto_respond:
            self.execute("PONG", *params)
        if command.isdigit():
            command = responses.from_digit(command)
        self.handle_line(prefix, command, params)
    
    
    def execute(self, command, *params, **kwargs):
        """ This places an IRC command on the output queue. If you wish to use
        a trailing perameter, set it as a keyword argument, like so:
        
            >>> self.execute("PRIVMSG", "#channel", trailing="Hello!")
        
        """
        params = filter(lambda x:x is not None, params)
        if "trailing" in kwargs:
            params = list(params)
            if kwargs["trailing"] is not None:
                params.append(":%s" % kwargs["trailing"])
        self.push("%s %s\r\n" % (command.upper(), " ".join(params)))
    
    
{'fraction_non_alphanumeric': 0.08923467767545253, 'fraction_numerical': 0.003493172435693871, 'mean_word_length': 2.3576759061833688, 'pattern_counts': {'":': 4, '<': 3, '<?xml version=': 0, '>': 9, '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': '5287529', 'n_tokens_mistral': 1763, 'n_tokens_neox': 1723, 'n_words': 607}