[Pymoul-svn] SF.net SVN: pymoul: [296] pymoul/trunk/src/moul
Status: Alpha
Brought to you by:
tiran
From: <ti...@us...> - 2007-05-29 13:49:35
|
Revision: 296 http://pymoul.svn.sourceforge.net/pymoul/?rev=296&view=rev Author: tiran Date: 2007-05-29 06:44:29 -0700 (Tue, 29 May 2007) Log Message: ----------- More work on the IRC chat relay system Modified Paths: -------------- pymoul/trunk/src/moul/chatrelay/filter.py pymoul/trunk/src/moul/chatrelay/formatter.py pymoul/trunk/src/moul/chatrelay/interfaces.py pymoul/trunk/src/moul/file/chatlog.py pymoul/trunk/src/moul/file/tests/test_chatlog.py Added Paths: ----------- pymoul/trunk/src/moul/chatrelay/handler.py Removed Paths: ------------- pymoul/trunk/src/moul/chatrelay/parser.py Modified: pymoul/trunk/src/moul/chatrelay/filter.py =================================================================== --- pymoul/trunk/src/moul/chatrelay/filter.py 2007-05-28 16:53:00 UTC (rev 295) +++ pymoul/trunk/src/moul/chatrelay/filter.py 2007-05-29 13:44:29 UTC (rev 296) @@ -2,6 +2,7 @@ from moul.chatrelay.interfaces import ILineFilter from moul.chatrelay.interfaces import ISnoopyLineFilter +from moul.chatrelay.interfaces import IConfigureableFilter from moul.file.chatlog import (CHAT_UNKNOWN, CHAT_PRIVMSG, CHAT_PRIVMSGTO, CHAT_PRIVMSGFROM, CHAT_ACTION, CHAT_ERROR, CHAT_MSG) @@ -9,42 +10,43 @@ __all__ = [obj for obj in globals() if ILineFilter.isImplementedBy(obj)] class NullFilter(object): + """Filter nothing + """ implements(ILineFilter) - name = 'Null filter' def filter(self, line, **kwargs): return line, kwargs class HightlightImportantFilter(object): + """Highlight important people + """ implements(ILineFilter) - name = 'Highlight important people' def filter(self, line, **kwargs): if kwargs.get('important', False): kwargs['highlight'] = True return line, kwargs -class AbstractMessageFilter(object): +class _AbstractMessageFilter(object): implements(ILineFilter) - name = None - msg_type = None + msg_flags = None def __init__(self): - assert self.msg_type, "No message type applied" + assert self.msg_flags, "No message type applied" def filter(self, line, **kwargs): typ = kwargs.get('type', CHAT_UNKNOWN) - if typ & self.msg_type: - return None, None + if typ & self.msg_flags: + kwargs['skip'] = True return line, kwargs -class PrivateMessageFilter(AbstractMessageFilter): +class PrivateMessageFilter(_AbstractMessageFilter): name = 'Private message filter' - msg_type = CHAT_PRIVMSG + msg_flags = CHAT_PRIVMSG -class ErrorMessageFilter(AbstractMessageFilter): +class ErrorMessageFilter(_AbstractMessageFilter): name = 'Error message filter' - msg_type = CHAT_ERROR + msg_flags = CHAT_ERROR class NonImportantFilter(object): implements(ILineFilter) @@ -52,5 +54,6 @@ def filter(self, line, **kwargs): if not kwargs.get('important', False): - return None, None + kwargs['skip'] = True return line, kwargs + Modified: pymoul/trunk/src/moul/chatrelay/formatter.py =================================================================== --- pymoul/trunk/src/moul/chatrelay/formatter.py 2007-05-28 16:53:00 UTC (rev 295) +++ pymoul/trunk/src/moul/chatrelay/formatter.py 2007-05-29 13:44:29 UTC (rev 296) @@ -8,25 +8,41 @@ __all__ = [obj for obj in globals() if IOutputFormatter.isImplementedBy(obj)] class NullFormatter(object): + """Null formatter + + The null formatter returns the line without changing it. + """ implements(IOutputFormatter) - name = 'Null formatter' def format(self, line, **kwargs): + if kwargs.get('skip', False): + return None return line class MOULFormatter(object): + """MOUL formatter + + The MOUL formatter formats the text based on its type. It also understands + some additional keyword arguments: + + * highlight: text is highlighted with bold characters + * skip: text is skipped (no output) + """ implements(IOutputFormatter) name = 'MOUL formatter' def format(self, line, **kwargs): + if not line: + return typ = kwargs.get('type', CHAT_UNKNOWN) - highlight = kwargs.get('highlight', False) if typ == CHAT_PRIVMSGTO: line = "-> %s" % line elif typ == CHAT_PRIVMSGFROM: line = "<- %s" % line elif typ == CHAT_ACTION: line = "* %s" % line - if highlight: + if kwargs.get('highlight', False): line = "%B%s" % line + if kwargs.get('skip', False): + return None return line Copied: pymoul/trunk/src/moul/chatrelay/handler.py (from rev 295, pymoul/trunk/src/moul/chatrelay/parser.py) =================================================================== --- pymoul/trunk/src/moul/chatrelay/handler.py (rev 0) +++ pymoul/trunk/src/moul/chatrelay/handler.py 2007-05-29 13:44:29 UTC (rev 296) @@ -0,0 +1,37 @@ +import os +from zope.interface import implements +from moul.file.chatlog import ChatlogParser +from moul.chatrelay.interfaces import IInputHandler + +__all__ = [obj for obj in globals() if IInputHandler.isImplementedBy(obj)] + +class NullHandler(object): + implements(IInputHandler) + name = 'Null parser' + delimiter = '\n' + + def __init__(self, delimiter=None, **kwargs): + if delimiter: + self.delimiter = delimiter + self._buffer = '' + + def handle(self, raw): + data = self._buffer + raw + lines = data.split(self.delimiter) + self._buffer = lines.pop(-1) + for line in lines: + yield self.parse(line) + + def parse(self, line): + return line, {} + +class MOULChatlogHandler(NullHandler): + name = 'MOUL chatlog parser' + delimiter = os.linesep + + def __init__(self): + super(MOULChatlogHandler).__init__() + self._parser = ChatlogParser([]) + + def parse(self, line): + return self._parser.parse(line) Modified: pymoul/trunk/src/moul/chatrelay/interfaces.py =================================================================== --- pymoul/trunk/src/moul/chatrelay/interfaces.py 2007-05-28 16:53:00 UTC (rev 295) +++ pymoul/trunk/src/moul/chatrelay/interfaces.py 2007-05-29 13:44:29 UTC (rev 296) @@ -4,8 +4,9 @@ class IFileAppendWatchService(Interface): """A service which monitors text files and calls the callback for new lines """ + default_interval = Attribute("Default interval length in seconds") - def monitorFile(path, callback, errback=None): + def monitorFile(path, callback, errback=None, interval=None): """Monitor a file @param path: path to a file @@ -14,8 +15,26 @@ @type callback: callable @param errback: errback function(path, error) @type errback: callable + @param interval: interval in seconds (None for default interval + @type interval: int or None """ + + def pauseFile(path): + """Pause monitoring the file (closes fd) + @param path: path to a registered file + @type path: string + """ + + def resumeFile(path, fromEnd=True): + """Pause monitoring the file (closes fd) + + @param path: path to a registered file + @type path: string + @param fromEnd: start from EOF or last position + @type fromEnd: bool + """ + def unmonitorFile(path): """Stop monitoring files @@ -30,10 +49,19 @@ @rtype: list """ -class IInputParser(Interface): - """Parse input data +class IInputHandler(Interface): + """Handle raw input and parse it """ - name = Attribute("name of the parser") + delimiter = Attribute("line delimiter (default: '\n')") + + def handle(raw): + """Handle raw data + + @param raw: raw data + @type raw: string + @return: parsed data as an iterable + @rtype: generator yielding (str, dict) + """ def parse(line): """Parse a single line @@ -46,17 +74,19 @@ class ILineFilter(Interface): """A line filter + + In order to suppress the output of a line the filter may set + kwargs['skip'] to True. """ - name = Attribute("name of the filter") def filter(line, **kwargs): - """ + """Filter a line @param line: the line to filter @type line: string @param kwargs: additional information - @return: (filtered line, kwargs) or None, None - @rtype: (string, dict) / None, None + @return: (filtered line, kwargs) + @rtype: (string, dict) """ class ISnoopyLineFilter(ILineFilter): @@ -75,10 +105,16 @@ @return: None """ +class IConfigureableFilter(ILineFilter): + """A filter which may be configured using commands + """ + def listCommands(): + """List commands XXX: finish me + """ + class IOutputFormatter(Interface): """A line formatter """ - name = Attribute("name of the output formatter") def format(line, **kwargs): """Format a line @@ -86,8 +122,8 @@ @param line: the line to filter @type line: string @param kwargs: additional information - @return: a formatted line - @rtype: string + @return: a formatted line or None + @rtype: string, None """ class IChatRelay(Interface): @@ -121,3 +157,7 @@ @param name: name of the filter @type name: string """ + + def listFilters(): + """Return a list of filters + """ Deleted: pymoul/trunk/src/moul/chatrelay/parser.py =================================================================== --- pymoul/trunk/src/moul/chatrelay/parser.py 2007-05-28 16:53:00 UTC (rev 295) +++ pymoul/trunk/src/moul/chatrelay/parser.py 2007-05-29 13:44:29 UTC (rev 296) @@ -1,27 +0,0 @@ -from zope.interface import implements - -from moul.file.chatlog import ChatlogParser - -from moul.chatrelay.interfaces import IInputParser - -__all__ = [obj for obj in globals() if IInputParser.isImplementedBy(obj)] - -class NullParser(object): - implements(IInputParser) - name = 'Null parser' - - def __init__(self, *args, **kwargs): - pass - - def parse(self, line): - return line, {} - -class MOULChatlogParser(ChatlogParser): - implements(IInputParser) - name = 'MOUL chatlog parser' - - def __init__(self, year): - self.setYear(year) - - def setYear(self, year): - self._year = int(year) Modified: pymoul/trunk/src/moul/file/chatlog.py =================================================================== --- pymoul/trunk/src/moul/file/chatlog.py 2007-05-28 16:53:00 UTC (rev 295) +++ pymoul/trunk/src/moul/file/chatlog.py 2007-05-29 13:44:29 UTC (rev 296) @@ -349,17 +349,17 @@ New idea, new design """ - def __init__(self, iterable=[], year=2007): + def __init__(self, iterable): self._iterable = iterable - self._year = year # XXX def parse(self, line): mo = CHAT_RE.match(line) if mo is None: - return ChatLine(line, (1970, 1, 1, 0, 0, 0), CHAT_UNKNOWN) + return line, {'type' : CHAT_UNKNOWN} d = mo.groupdict() - dt = (self._year, int(d['M']), int(d['D']), + dt = (0, int(d['M']), int(d['D']), int(d['h']), int(d['m']), int(d['s'])) + dt = self.estimateDT(dt) msg = d['msg'] info = {'type' : CHAT_UNKNOWN, 'datetime' : dt, 'important' : False} if len(d['space']) == 2: @@ -393,6 +393,13 @@ if user in USER_IMPORTANT: info['important'] = True return msg, info + + def estimateDT(self, lst): + lt = localtime() + year = lt[0] + if lst[1:2] == (12, 31) and lt[1:2] == (1, 1): + year = year - 1 + return (year,) + lst[1:] def __iter__(self): for line in self._iterable: Modified: pymoul/trunk/src/moul/file/tests/test_chatlog.py =================================================================== --- pymoul/trunk/src/moul/file/tests/test_chatlog.py 2007-05-28 16:53:00 UTC (rev 295) +++ pymoul/trunk/src/moul/file/tests/test_chatlog.py 2007-05-29 13:44:29 UTC (rev 296) @@ -41,17 +41,14 @@ 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 msg, info in results: + fue(info['datetime'], (2007, 1, 2, 3, 4, 5)) + for i, t in enumerate((CHAT_START, CHAT_STOP, CHAT_PRIVMSGFROM, + CHAT_ERROR, CHAT_MSG, CHAT_PRIVMSGTO)): + msg, info = results[i] + fue(info['type'], t) for i in (2, 4, 5): - fue(results[i].info['user'], 'USER') + fue(results[i][1]['user'], 'USER') def test_suite(): return unittest.TestSuite(( This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |