###################################################################### # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Copyright 2007 Petteri Aimonen # '''Log keeper for import and upkeep events, and log rendering''' from pymisc import _ class LogCategory: '''Base class for log categories''' name = 'baselog' priority = 0 class ListLogCategory(LogCategory): '''Base class for list based log categories''' header = '' cols = [] formatstring = '' sortbyindex = 0 sortreverse = False separator = '
' def __init__(self): self.entries = [] def haslog(self): return bool(self.entries) def log(self, *args): self.entries.append(args) def format(self): pars = {'count': len(self.entries)} msg = '' + self.header % pars + '
' self.entries.sort(key = lambda r, i = self.sortbyindex: r[i], reverse = self.sortreverse) rows = [] for entry in self.entries: pars = {} for i, colname in enumerate(self.cols): pars[colname] = entry[i] rows.append(self.formatstring % pars) msg += self.separator.join(rows) return msg class BooleanLogCategory(LogCategory): '''Base class for boolean state log categories''' message = '' def __init__(self): self.state = False def haslog(self): return self.state def log(self): self.state = True def format(self): if self.state: return self.message else: return '' class AidListLogCategory(ListLogCategory): '''Simple list of animalids''' cols = ['aid'] separator = ', ' formatstring = _('%(aid)d') # Log categories class LC_Animals(AidListLogCategory): name = 'new_animal' priority = 1 header = _('Added %(count)d new animals to database:') class LC_Moves(ListLogCategory): name = 'moved_animal' priority = 2 cols = ['aid', 'from', 'to'] header = _('Moved %(count)d animals:') formatstring = _('Animal %(aid)d ' \ 'from %(from)d ' \ 'to %(to)d') class LC_ReadFail(ListLogCategory): name = 'readfail' priority = 5 cols = ['file', 'exc'] header = _('Reading following files failed:') formatstring = _('File %(file)s:
%(exc)s
') class LC_InactiveHasFeeds(AidListLogCategory): name = 'inactivehasfeeds' priority = 2 header = _('Following animals have feed data despite marked inactive:') class LC_MarkedInactive(AidListLogCategory): name = 'markedinactive' priority = 1 header = _('Following animals were marked inactive:') class LC_RemovedAnimal(AidListLogCategory): name = 'removedanimal' priority = 1 header = _('Following animals were removed from database:') format = _('%(aid)s') # No link for removed animals class LC_UpkeepCheckFail(ListLogCategory): name = 'upkeep_checkfail' priority = 5 header = _('Following upkeep checks failed:') cols = ['desc', 'exc'] formatstring = _('%(desc)s:
%(exc)s
') class LC_SkippedAfeed(ListLogCategory): name = 'skipped_afeed' priority = 5 header = _('Parsing following lines in per-animal data failed:') cols = ['file', 'line'] formatstring = _('%(file)s: %(line)s') class LC_SkippedGfeed(ListLogCategory): name = 'skipped_gfeed' priority = 5 header = _('Parsing following lines in groupfeed data failed:') cols = ['line'] formatstring = _('%(line)s') class LC_MissingGfeed(BooleanLogCategory): name = 'missing_gfeed' priority = 5 message = _('Days are missing from groupfeed data') class LC_FilledInGfeed(BooleanLogCategory): name = 'filledin_gfeed' priority = 3 message = _('Missing days in groupfeed data have been filled in ' \ 'with averages') class LC_SmallFeed(ListLogCategory): name = 'smallfeed' priority = 2 sortbyindex = 1 header = _('Following animals have low feed amounts:') cols = ['aid', 'grams'] formatstring = _('%(aid)d: %(grams)d grams') class LC_FeedDelta(ListLogCategory): name = 'feeddelta' priority = 2 sortbyindex = 1 sortreverse = True header = _('Following animals have high deviations in feed amounts:') cols = ['aid', 'delta'] formatstring = _('%(aid)d: %(delta)0.1f %%') def get_lclist(): '''Gather list of LogCategories''' r = [] for name, value in globals().items(): if not name.startswith('LC_'): continue if not issubclass(value, LogCategory): continue r.append(value) return r class ImportLogger: '''Keeps track of import events''' def __init__(self): self.categories = dict([(c.name, c()) for c in get_lclist()]) def haslog(self): for c in self.categories: if c.haslog(): return True return False # Log formatting def format(self): '''Format all messages as html''' msgs = [] categories = self.categories.values() categories.sort(key = lambda c: c.priority, reverse = True) for c in categories: if c.haslog(): msgs.append(c.format()) return '
'.join(msgs) # Logging, like Logger.log_smallfeed(...) def __getattr__(self, name): if name.startswith('log_') and self.categories.has_key(name[4:]): return self.categories[name[4:]].log else: raise AttributeError, name