[Pymoul-svn] SF.net SVN: pymoul: [291] pymoul/trunk/src/moul
Status: Alpha
Brought to you by:
tiran
From: <ti...@us...> - 2007-05-24 17:19:05
|
Revision: 291 http://pymoul.svn.sourceforge.net/pymoul/?rev=291&view=rev Author: tiran Date: 2007-05-24 10:19:06 -0700 (Thu, 24 May 2007) Log Message: ----------- Chatlog parser enhancements Modified Paths: -------------- pymoul/trunk/src/moul/chatrelay/io.py pymoul/trunk/src/moul/chatrelay/ircclient.py pymoul/trunk/src/moul/file/chatlog.py pymoul/trunk/src/moul/file/tests/test_chatlog.py Modified: pymoul/trunk/src/moul/chatrelay/io.py =================================================================== --- pymoul/trunk/src/moul/chatrelay/io.py 2007-05-24 14:00:41 UTC (rev 290) +++ pymoul/trunk/src/moul/chatrelay/io.py 2007-05-24 17:19:06 UTC (rev 291) @@ -23,6 +23,10 @@ import os +from moul.file.chatlog import ChatlogParser +from moul.file.chatlog import ChatLineError +from moul.file.chatlog import CHAT_PRIVMSG + class NullFormatter(object): """A formatter that doesn't change the msg """ @@ -62,10 +66,16 @@ return lines = data.split(os.linesep) # XXX - KISS, don't check for imcomplete lines - for line in lines: - line = line.strip() - if line: - self._fifo.append(line) + for line in ChatlogParser(lines): + if isinstance(ChatLineError): + self._fifo.append("PARSER ERROR: " + line) + else: + if line.typ & CHAT_PRIVMSG: + continue + elif line.important: + self._fifo.append("*** " + line) + else: + self._fifo.append(line) def __iter__(self): self._read() @@ -80,8 +90,6 @@ class MessageWriter(object): """Write messages to a channel """ - maxlength = 80 - def __init__(self, client, channel, formatter=None): self._client = client self._channel = channel @@ -91,4 +99,4 @@ def log(self, msg): msg = self._fmt.format(msg) - self._client.say(self._channel, msg, self.maxlength) + self._client.say(self._channel, msg) Modified: pymoul/trunk/src/moul/chatrelay/ircclient.py =================================================================== --- pymoul/trunk/src/moul/chatrelay/ircclient.py 2007-05-24 14:00:41 UTC (rev 290) +++ pymoul/trunk/src/moul/chatrelay/ircclient.py 2007-05-24 17:19:06 UTC (rev 291) @@ -238,7 +238,7 @@ reactor.callLater(3.0, self.reply, reply, "0-/") reactor.callLater(3.5, self.reply, reply, "0-\\") - #@requirePasswd + @requirePasswd @usage("Open the chatlog and start relaying") def command_STARTLOG(self, user, reply, args): self.reply(reply, 'Opening chatlog ...') @@ -248,12 +248,12 @@ return self.msg(self.channel, "*** I'm relaying chat ***") - #@requirePasswd + @requirePasswd @usage("Stop relaying") def command_STOPLOG(self, user, reply, args): self.stop() self.reply(reply, 'chatlog closed') - self.msg(self.channel, "*** I've stopped to relay chat ***") + self.msg(self.channel, "*** I've stopped relaying chat ***") class ThrottledClientFactory(protocol.ClientFactory): lostDelay = 2 Modified: pymoul/trunk/src/moul/file/chatlog.py =================================================================== --- pymoul/trunk/src/moul/file/chatlog.py 2007-05-24 14:00:41 UTC (rev 290) +++ pymoul/trunk/src/moul/file/chatlog.py 2007-05-24 17:19:06 UTC (rev 291) @@ -41,7 +41,22 @@ from moul.file.utils import fileModTime +# Chat line types +CHAT_START = 1 << 0 +CHAT_STOP = 1 << 1 +CHAT_ERROR = 1 << 2 +CHAT_PRIVMSGFROM = 1 << 3 +CHAT_PRIVMSGTO = 1 << 4 +CHAT_PRIVMSG = CHAT_PRIVMSGFROM | CHAT_PRIVMSGTO +CHAT_MSG = 1 << 5 +CHAT_ACTION = 1 << 6 +# users +USER_CYAN = ['gregbert', 'greydragon'] +USER_DRC = ['Marie Sutherland', 'Douglas Sharper', 'Nick White', + 'Dr. Kodama', 'Victor Laxman', 'Michael Engberg'] +USER_IMPORTANT = USER_CYAN + USER_DRC + RE_FLAGS = re.LOCALE CHAT_RE = re.compile( r"^\((?P<M>\d{1,2})/(?P<D>\d{1,2})\ " # MM/DD @@ -52,20 +67,20 @@ r"^\((?P<date>[\d/]*)\ (?P<time>[\d:]*)\)" # (date time) r"(?P<space>\s{1,2})" # spaces r"(?P<msg>.*)$", # message - RE_FLAGS) -CHATLOG_STARTED = "Chat.log started..." -CHATLOG_STOPPED = "...Chat.log stopped." -TEXT_MSGFROM_RE = re.compile( + RE_FLAGS) +CHATLOG_START = "Chat.log started..." +CHATLOG_STOP = "...Chat.log stopped." +PRIVMSGFROM_RE = re.compile( # From USER in LOCATION: msg r"From (?P<user>.*) in (?P<location>.*): (?P<msg>.*)", RE_FLAGS) -TEXT_MSGTO_RE = re.compile( +PRIVMSGTO_RE = re.compile( r"To (?P<user>.*): (?P<msg>.*)", # From USER in LOCATION: msg RE_FLAGS) -TEXT_ERROR_RE = re.compile( +ERROR_RE = re.compile( r"Error: (?P<msg>.*)", # Error: message RE_FLAGS) -TEXT_RE = re.compile( +MSG_RE = re.compile( r"(?P<user>.*): (?P<msg>.*)", # User: message RE_FLAGS) CHATLOG_DATE_FNAME_RE = re.compile( @@ -76,7 +91,6 @@ LOG = getLogger('moul.chat') - class ChatlogMover(object): """ """ @@ -147,7 +161,7 @@ created = None if mo: data = mo.groupdict() - if data['msg'].startswith(CHATLOG_STARTED): + if data['msg'].startswith(CHATLOG_START): d = mo.groupdict() created = (None, int(d['M']), int(d['D']), int(d['h']), int(d['m']), int(d['s']), None, None, None) @@ -255,6 +269,8 @@ class ChatlogView(object): """A view of a single chat log file + + XXX replace it with ChatlogParser """ def __init__(self, fname): @@ -326,3 +342,85 @@ """ self.open() return self._fd.read() + +class ChatlogParser(object): + """Yet another chatlog parser + + New idea, new design + """ + def __init__(self, iterable, year=2007): + self._iterable = iterable + self._year = year # XXX + + def parse(self, line): + mo = CHAT_RE.match(line) + if mo is None: + self.error(line) + return + d = mo.groupdict() + date = (self._year, int(d['M']), int(d['D']), + int(d['h']), int(d['m']), int(d['s'])) + typ = None + msg = d['msg'] + info = {} + important = False + if len(d['space']) == 2: + typ = CHAT_MSG + mo = MSG_RE.match(msg) + if mo is None: + return ChatLineError(line) + info = mo.groupdict() + else: + if msg == CHATLOG_START: + typ = CHAT_START + elif msg == CHATLOG_STOP: + typ = CHAT_STOP + else: + for t, r in ((CHAT_PRIVMSGFROM, PRIVMSGFROM_RE), + (CHAT_PRIVMSGTO, PRIVMSGTO_RE), + (CHAT_ERROR, ERROR_RE)): + mo = r.match(msg) + if mo: + typ = t + info = mo.groupdict() + break + if typ is None: + typ = CHAT_ACTION + for user in USER_IMPORTANT: + if user in msg: + important = True + + user = info.get('user', None) + if user: + if user in USER_IMPORTANT: + important = True + if typ is not None: + return ChatLine(msg, date, typ, important, info) + else: + return ChatLineError(line) + + def __iter__(self): + for line in self._iterable: + yield self.parse(line) + +class ChatLine(unicode): + __slots__ = ('datetime', 'typ', 'important', 'info') + + def __new__(cls, ustr, datetime, typ=None, important=False, info={}): + self = unicode.__new__(cls, ustr) + self.datetime = datetime + self.typ = typ + self.important = important + self.info = info + return self + + def asDatetime(self): + return datetime(*self.date) + +class ChatLineError(unicode): + def __new__(cls, ustr): + self = unicode.__new__(cls, ustr) + return self + + def __nonzero(self): + return False \ No newline at end of file Modified: pymoul/trunk/src/moul/file/tests/test_chatlog.py =================================================================== --- pymoul/trunk/src/moul/file/tests/test_chatlog.py 2007-05-24 14:00:41 UTC (rev 290) +++ pymoul/trunk/src/moul/file/tests/test_chatlog.py 2007-05-24 17:19:06 UTC (rev 291) @@ -25,10 +25,37 @@ from doctest import DocTestSuite import moul.file.chatlog +from moul.file.chatlog import * +TEST_LOG = """(01/02 03:04:05) Chat.log started... +(01/02 03:04:05) ...Chat.log stopped. +(01/02 03:04:05) From USER in LOCATION: MSG +(01/02 03:04:05) Error: ERRORMSG +(01/02 03:04:05) USER: TEXT (note the two spaces!) +(01/02 03:04:05) To USER: TEXT +(01/02 03:04:05) USER action""".split('\n') +class ChatlogParserTest(unittest.TestCase): + + def test_parse(self): + parser = ChatlogParser(TEST_LOG) + results = list(iter(parser)) + fue = self.failUnlessEqual + for result in results: + fue(result.datetime, (2007, 1, 2, 3, 4, 5)) + fue(results[0].typ, CHAT_START) + fue(results[1].typ, CHAT_STOP) + fue(results[2].typ, CHAT_PRIVMSGFROM) + fue(results[3].typ, CHAT_ERROR) + fue(results[4].typ, CHAT_MSG) + fue(results[5].typ, CHAT_PRIVMSGTO) + fue(results[6].typ, CHAT_ACTION) + for i in (2, 4, 5): + fue(results[i].info['user'], 'USER') + def test_suite(): return unittest.TestSuite(( + unittest.makeSuite(ChatlogParserTest), DocTestSuite('moul.file.chatlog') )) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |