3
\$\begingroup\$

I'm looking to see if there is anything in this I could have done better or see if could have structured the code better. Here is the project on GitHub.

import socket
import string
import sys
import os

path = "plugins/"
plugins = []
# Load plugins
sys.path.insert(0, path)
for f in os.listdir(path):
    fname, ext = os.path.splitext(f)
    if ext == '.py':
        mod = __import__(fname)
        plugins.append(getattr(mod, fname))
sys.path.pop(0)

class IRC_Client(object):

    """docstring for IRC_Client"""
    sock = ""

    def __init__(self, ircserver, ircnicklist, ircident, ircrealname,
                 ircchanlist, nickpassword=None, ircport=6667):
        super(IRC_Client, self).__init__()
        if not isinstance(ircnicklist, list):
            raise TypeError("nicklist is not an instance of list")
        elif not isinstance(ircchanlist, list):
            raise TypeError("chanlist is not an instance of list")

        self.ircnicklist = ircnicklist
        self.ircident = ircident
        self.ircrealname = ircrealname
        self.ircchanlist = ircchanlist
        self.ircserver = ircserver
        self.ircport = ircport
        self.nickpassword = nickpassword

    def createconnection(self):
        self.sock = socket.socket()
        self.sock.connect((self.ircserver, self.ircport))

    def sendmessage(self, sender, message):
        sent = "PRIVMSG %s :%s\r\n" % (sender, message)
        self.sock.send(sent)

    def sendpong(self, sender):
        sent = "PONG %s\r\n" % sender
        self.sock.send(sent)

    def sendnotice(self, sender, message):
        sent = "NOTICE %s :%s\r\n" % (sender, message)
        self.sock.send(sent)

    def sendctcp(self):
        pass

    def setnick(self, nick):
        self.sock.send("NICK %s\r\n" % nick)

    def joinchannel(self, channel):
        self.sock.send("JOIN %s\r\n" % channel)

    def getusernick(self, serverbuffer):
        usernick = serverbuffer[0].split("!")
        usernick = usernick[0].replace(":", "")
        return usernick

    def getusermessage(self, serverbuffer):
        message = ""
        if len(serverbuffer) >= 4:
            serverbuffer[3] == serverbuffer[3][1:]
            for i in range(3, len(serverbuffer)):
                message += serverbuffer[i] + " "
            return message

    def getchannel(self, serverbuffer):
        if len(serverbuffer):
            return serverbuffer[2]

    def serverreplies(self, serverbuffer):
        serverbuffer = string.split(string.rstrip(serverbuffer))

        if serverbuffer[0].lower() == 'ping':
            self.sendpong(serverbuffer[0])
        if serverbuffer[1] == "431":
            print "No nick was given"
            exit()
        if serverbuffer[1] == "432":
            print "Erroneus nick"
            exit()
        if serverbuffer[1] == "433":
            if len(self.ircnicklist) != 0:
                self.setnick(self.ircnicklist.pop())
            else:
                raise IndexError("All nicks from nicklist are in use")

            for channel in self.ircchanlist:
                self.joinchannel(channel)

    def commandparser(self, line):
        line = string.split(string.rstrip(line.lower()))
        if (len(line) >= 4 and line[1] == 'privmsg'):
            map(lambda command: command(self, line), plugins)


    def connect(self):
        self.createconnection()
        self.setnick(self.ircnicklist[0])
        self.sock.send("USER %s %s bla :%s\r\n"
                       % (self.ircident, self.ircserver, self.ircrealname))

        if not self.nickpassword:
            pass
        else:
            self.sock.send("PASS %s\r\n" % self.nickpassword)

        for channel in self.ircchanlist:
            self.joinchannel(channel)

    def loop(self):

        readbuffer = ""
        while 1:
            readbuffer = self.sock.recv(1024)
            temp = string.split(readbuffer, "\n")
            readbuffer = temp.pop()
            for line in temp:
                print line
                self.serverreplies(line)
                self.commandparser(line)
                logger(self, line)

    def runclient(self):

        self.connect()
        self.loop()


def logger(ircclientinstance, serverbuffer):

    serverbuffer = string.split(string.rstrip(serverbuffer))

    if serverbuffer[1].lower() == "privmsg":
        if serverbuffer[2] in ircclientinstance.ircchanlist:
            filename = ("%s.log" % serverbuffer[2])
            f = open(filename, 'a+')
            f.write("<%s>%s\n" % (ircclientinstance.getusernick(
                serverbuffer), ircclientinstance.getusermessage(serverbuffer)))
            f.close()
        else:
            filename = ("%s.log" % ircclientinstance.getusernick(serverbuffer))
            f = open(filename, 'a+')
            f.write("<%s>%s\n" % (ircclientinstance.getusernick(
                serverbuffer), ircclientinstance.getusermessage(serverbuffer)))
            f.close()


if __name__ == "__main__":
    # TODO: config file? maybe
    mybot = IRC_Client('irc.freenode.net', ['swaglorde', 'swaglordeh'], 'swaglorde', 
                    'swaglorde', ['#dtest'])
    mybot.runclient()

Example of a plugin:

I am thinking about converting my plugin system to a class based system. I am also not sure if it would better, but I do have a bit of code I am reusing with every plugin.

import requests


def showInfo(tvname):
    tvname = tvname.replace(' ', '+')
    tvinfo = requests.get(
        "http://services.tvrage.com/tools/quickinfo.php?show=" + tvname).text
    try:
        tvdata = tvinfo.split('\n')
        tvinfo = []
        for data in tvdata:
            data = data.split('@')
            tvinfo.append(data)

        return tvinfo
    except:
        return None


def next(ircclientinstance, serverbuffer):
    commandname = 'next'
    commands = {':!': True, ':.': False, ':@': True}

    # This needs to be included in all plugins that take arguements
    commandarguements = ""
    parseargs = serverbuffer[3:][1:]

    for x in parseargs:
        commandarguements += x.strip() + " "

    if commandarguements == '':
        output = "No info found :3"
    else:
        try:
            tvinfo = showInfo(commandarguements)
            output = "[%s] :: [Next: %s] [Airs: %s]" % (
                tvinfo[1][1], tvinfo[7][1].replace('^', ' '), tvinfo[15][1])
        except:
            output = "No info found :3"

    # this needs to be included with all plugins
    if serverbuffer[3][2:] == commandname:
        if serverbuffer[3][:2] in commands:
            notice = commands.get(serverbuffer[3][:2])

            if not notice:
                if serverbuffer[1] == "privmsg":
                    if serverbuffer[2] in ircclientinstance.ircchanlist:
                        ircclientinstance.sendmessage(serverbuffer[2], output)
                    else:
                        ircclientinstance.sendmessage(
                            ircclientinstance.getusernick(serverbuffer), output)
            else:
                ircclientinstance.sendnotice(
                    ircclientinstance.getusernick(serverbuffer), output)
\$\endgroup\$
1
\$\begingroup\$

A few comments regarding the main code:

  • Try to order imports alphabetically
  • Use underscores to separate words in method names (createconnection -> create_connection, sendmessage, send_message, etc.)
  • Use class attributes instead of hardcded constants ("431" -> self.ERR_NONICKNAMEGIVEN, "432" -> self.ERR_ERRONEUSNICKNAME, etc.)
  • Use if/elif/elif instead of if/if/if to avoid unnecessary checks
  • Use the logging module instead of print statements.
  • To check if a list is not empty use just the list name self.ircnicklist instead of len(self.ircnicklist) != 0
  • Review exception types. Is IndexError really appropriate when there are no more elements in the list?l
  • Prefer to use list comprehensions instead of map
  • Remove pass if isn't really useful. Instead of:

    if not self.nickpassword:
        pass
    else:
        self.sock.send("PASS %s\r\n" % self.nickpassword)
    

    write:

    if self.nickpassword:
        self.sock.send("PASS %s\r\n" % self.nickpassword)
    
  • Instead of while 1 use while True

  • Use context managers to open and close files. Instead of:

    f = open(filename, 'a+')
    f.write("<%s>%s\n" % (ircclientinstance.getusernick(
        serverbuffer), ircclientinstance.getusermessage(serverbuffer)))
    f.close()
    

    write:

    with open(filename, 'a+') as f:
        f.write("<%s>%s\n"
                % (ircclientinstance.getusernick(serverbuffer),
                   ircclientinstance.getusermessage(serverbuffer)))
    

I hope this helps.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.