#!/usr/bin/python # -*- coding: utf-8 -*- ''' Template module for a Kai's Text Tools. (c) 2013 Ivan "Kai SD" Korystin License: GPLv3 ''' import re class TemplateV3(object): ''' Class for reading ATGv3 templates. ''' pass class TemplateV2(object): ''' Class for reading ATGv2 templates. ''' def __init__(self, filename=None, encoding='utf-8', text=''): ''' Constructor ''' if filename: with open(filename, 'r') as templateFile: topline = templateFile.readline().decode(encoding) if not topline.startswith('ATGV2'): raise BaseException('%s is not an ATGv2 template' % (filename)) key = templateFile.readline().decode(encoding) if key[:2] == '[$' and key[-3:-1] == '$]': keyInfo = key[2:-2].split('$') if len(keyInfo) < 4: raise BaseException('%s has bad ATGv2 key' % (filename)) self.keyField = keyInfo[0] self.extension = keyInfo[1] self.prefix = keyInfo[2] self.encoding = keyInfo[3] if 'oneFile' in keyInfo[4:]: self.oneFile = True else: self.oneFile = False if 'transpose' in keyInfo[4:]: self.transpose = True else: self.transpose = False self.text = u'' else: raise BaseException('%s has bad ATGv2 key' % (filename)) for i in templateFile.readlines(): self.text += i.decode(encoding) else: self.text = text self.key = u'' self.footer = u'' self.replacement = {} self._data = None self._multiWords = None def parse(text): topParts = [] matches = {} openers = re.finditer('\[\$.*?\$', text) closers = re.finditer('\$\]', text) ops = [] try: cl = closers.next() while not cl is None: try: op = openers.next() if op.start() < cl.start(): ops.append(op) else: idx = -1 try: while ops[idx].start() > cl.start(): idx -= 1 except: raise BaseException('Template parsing error: can not find the opener for '+str(cl.start())) matches[ops[idx]] = cl if len(ops) == 1 or idx == -len(ops): topParts.append(ops[idx]) del ops[idx] ops.append(op) try: cl = closers.next() except StopIteration: cl = None except StopIteration: idx = -1 try: while ops[idx].start() > cl.start(): idx -= 1 except: raise BaseException('Template parsing error: can not find the opener for '+str(cl.start())) matches[ops[idx]] = cl if len(ops) == 1 or idx == -len(ops): topParts.append(ops[idx]) del ops[idx] try: cl = closers.next() except StopIteration: cl = None except StopIteration: pass parts = [] for i in topParts: startPoint = i.end() endPoint = matches[i].start() p = (i.group()[2:-1], text[startPoint:endPoint]) if p[0].startswith('ATG'): parts.insert(0, p) else: parts.append(p) return parts partCommands = {} def plain(index, flow, keytag): if not keytag in self._data.keys: self.warning('WARNING: keyword not found in table - %s' % (keytag)) return flow return flow.replace('[$%s$]' % (keytag), unicode(self._data[keytag, index])) partCommands['_ATGPLAIN'] = plain def nPlain(index, flow, keytag, number): if not keytag+str(number) in self._data.keys: self.warning('WARNING: keyword not found in table - %s' % (keytag+str(number))) return flow return flow.replace('[$%s$]' % (keytag), unicode(self._data[keytag+str(number), index])) def lIndex(index, flow, keytag, number): return flow.replace('[$ATGLINDEX$]', str(number)) def addkey(index, flow, text): if self.key.find(text) < 0: self.key += text key = '[$ATGkey$' + text + '$]' return flow.replace(key,'') partCommands['ATGkey'] = addkey def addFooter(index, flow, text): if self.footer.find(text) < 0: self.footer += text key = '[$ATGFOOTER$' + text + '$]' return flow.replace(key,'') partCommands['ATGFOOTER'] = addFooter def addList(index, flow, string): key = '[$ATGLIST$%s$%s$]' % (string.split('$')[0], string[len(string.split('$')[0])+1:]) sub = string[len(string.split('$')[0])+1:] keyTag = string.split('$')[0] subparts = parse(sub) myText = u'' if not keyTag in self._multiWords: self.warning('Keytag %s is not multiple!' % (keyTag)) return flow for j in xrange(1, self._multiWords[keyTag]+1): subText = sub for sp in subparts: if sp[0] in self._multiWords: subText = nPlain(index, subText, sp[0], j) elif sp[0] == 'ATGLINDEX': subText = lIndex(index, subText, sp[0], j) elif sp[0] in partCommands: subText = partCommands[sp[0]](index, subText, sp[1]) elif sp[1] == '': subText = plain(index, subText, sp[0]) else: self.warning('Warning: unknown command '+sp[0]) if not self._data[keyTag+str(j), index] == u'': myText += subText return flow.replace(key, myText) partCommands['ATGLIST'] = addList def addListCut(index, flow, string): key = '[$ATGLISTCUT$%s$%s$]' % (string.split('$')[0], string[len(string.split('$')[0])+1:]) sub = string[len(string.split('$')[0])+1:] keyTag = string.split('$')[0] subparts = parse(sub) myText = u'' if not keyTag in self._multiWords: self.warning('Keytag %s is not multiple!' % (keyTag)) return flow for j in xrange(1, self._multiWords[keyTag]+1): subText = sub for sp in subparts: if sp[0] in self._multiWords: subText = nPlain(index, subText, sp[0], j) elif sp[0] == 'ATGLINDEX': subText = lIndex(index, subText, sp[0], j) elif sp[0] in partCommands: subText = partCommands[sp[0]](index, subText, sp[1]) elif sp[1] == '': subText = plain(index, subText, sp[0]) else: self.warning('Warning: unknown command '+sp[0]) if not self._data[keyTag+str(j), index] == u'': myText += subText return flow.replace(key, myText[:-1]) partCommands['ATGLISTCUT'] = addListCut def addIf(index, flow, string): key = '[$ATGIF$%s$%s$]' % (string.split('$')[0], string[len(string.split('$')[0])+1:]) sub = string[len(string.split('$')[0])+len(string.split('$')[1])+2:] keyTag = string.split('$')[0] targetValue = string.split('$')[1] subparts = parse(sub) myText = u'' if self._data[keyTag, 0] == []: self.warning('WARNING: keyword not found in table - %s' % (keyTag)) return flow if unicode(self._data[keyTag, index]) == unicode(targetValue): subText = sub for sp in subparts: if sp[0] in partCommands: subText = partCommands[sp[0]](index, subText, sp[1]) elif sp[1] == '': subText = plain(index, subText, sp[0]) else: self.warning('Warning: unknown command '+sp[0]) myText += subText return flow.replace(key, myText) partCommands['ATGIF'] = addIf def addIfNot(index, flow, string): key = '[$ATGIFNOT$%s$%s$]' % (string.split('$')[0], string[len(string.split('$')[0])+1:]) sub = string[len(string.split('$')[0])+len(string.split('$')[1])+2:] keyTag = string.split('$')[0] targetValue = string.split('$')[1] subparts = parse(sub) myText = u'' if self._data[keyTag, 0] == []: self.warning('WARNING: keyword not found in table - %s' % (keyTag)) return flow if not unicode(self._data[keyTag, index]) == unicode(targetValue): subText = sub for sp in subparts: if sp[0] in partCommands: subText = partCommands[sp[0]](index, subText, sp[1]) elif sp[1] == '': subText = plain(index, subText, sp[0]) else: self.warning('Warning: unknown command '+sp[0]) myText += subText return flow.replace(key, myText) partCommands['ATGIFNOT'] = addIfNot def addGreater(index, flow, string): key = '[$ATGGREATER$%s$%s$]' % (string.split('$')[0], string[len(string.split('$')[0])+1:]) sub = string[len(string.split('$')[0])+len(string.split('$')[1])+2:] keyTag = string.split('$')[0] targetValue = string.split('$')[1] subparts = parse(sub) myText = u'' if self._data[keyTag, 0] == []: self.warning('WARNING: keyword not found in table - %s' % (keyTag)) return flow try: if float(self._data[keyTag, index]) > float(targetValue): subText = sub for sp in subparts: if sp[0] in partCommands: subText = partCommands[sp[0]](index, subText, sp[1]) elif sp[1] == '': subText = plain(index, subText, sp[0]) else: self.warning('Warning: unknown command '+sp[0]) myText += subText except: self.warning('ERROR: trying to compare uncomparable values!') return flow.replace(key, myText) partCommands['ATGGREATER'] = addGreater def addLess(index, flow, string): key = '[$ATGLESS$%s$%s$]' % (string.split('$')[0], string[len(string.split('$')[0])+1:]) sub = string[len(string.split('$')[0])+len(string.split('$')[1])+2:] keyTag = string.split('$')[0] targetValue = string.split('$')[1] subparts = parse(sub) myText = u'' if self._data[keyTag, 0] == []: self.warning('WARNING: keyword not found in table - %s' % (keyTag)) return flow try: if float(self._data[keyTag, index]) < float(targetValue): subText = sub for sp in subparts: if sp[0] in partCommands: subText = partCommands[sp[0]](index, subText, sp[1]) elif sp[1] == '': subText = plain(index, subText, sp[0]) else: self.warning('Warning: unknown command '+sp[0]) myText += subText except: self.warning('ERROR: trying to compare uncomparable values!') return flow.replace(key, myText) partCommands['ATGLESS'] = addLess def addReplace(index, flow, string): key = '[$ATGREPLACE$%s$%s$]' % (string.split('$')[0], string[len(string.split('$')[0])+1:]) targetString = string[len(string.split('$')[0])+1:] srcString = string.split('$')[0] self.replacement[srcString] = targetString key = '[$ATGREPLACE$' + string + '$]' return flow.replace(key,'') partCommands['ATGREPLACE'] = addReplace def addPrefix(index, flow, string): key = '[$ATGPREFIX$%s$%s$]' % (string.split('$')[0], string[len(string.split('$')[0])+1:]) sub = string subparts = parse(sub) for sp in subparts: if sp[0] in partCommands: sub = partCommands[sp[0]](index, sub, sp[1]) elif sp[1] == '': sub = plain(index, sub, sp[0]) else: self.warning('Warning: unknown command '+sp[0]) self.bonusPrefix += sub key = '[$ATGPREFIX$' + string + '$]' return flow.replace(key,'') partCommands['ATGPREFIX'] = addPrefix def skip(index, flow, string): return u'[$ATGSKIP_DO$]' partCommands['ATGSKIP'] = skip def prev(index, flow, string): key = '[$ATGPREV$%s$]' % (string.split('$')[0]) keytag = string.split('$')[0] if self._data[keytag, 0] == []: self.warning('WARNING: keyword not found in table - %s' % (keytag)) return flow if index == 0: self.log('INFORMATION: Skipping ATGPREV tag for entry with index = 0') return u'[$ATGSKIP_DO$]' return flow.replace('[$ATGPREV$%s$]' % (keytag), unicode(self._data.col_by_key(keytag)[index-1])) partCommands['ATGPREV'] = prev self.commands = partCommands self.parts = parse(self.text) def process(self, data): self._data = data multiWords = {} numbs = ('1','2','3','4','5','6','7','8','9','0') for i in data.keys: multi = False while i[-1] in numbs: i = i[:-1] multi = True if multi: if i in multiWords: multiWords[i] += 1 else: multiWords[i] = 1 self._multiWords = multiWords if self.oneFile: out = '' else: out = {} index = 0 partCommands = self.commands for element in data.col_by_key(self.keyField): self.bonusPrefix = self.prefix text = self.text for i in self.parts: if i[0] in partCommands: text = partCommands[i[0]](index, text, i[1]) elif i[1] == u'': text = partCommands['_ATGPLAIN'](index, text, i[0]) else: self.warning('Warning: unknown command '+i[0]) for i in self.replacement: text = text.replace(i, self.replacement[i]) self.replacement = {} index += 1 if u'[$ATGSKIP_DO$]' in text: self.log('ATGSKIP Tag found. Skipping ' + unicode(element) + '.') else: if self.oneFile: out += text else: name = self.bonusPrefix + unicode(element) out[name] = text self.log('Created %s' % (element)) if self.oneFile: out = self.key + out + self.footer return out def warning(self, text): print text def log(self, text): pass @staticmethod def express(cls, text, **kwargs): obj = cls() obj.text = text self.keyField = kwargs.get('keyField', 'Index') self.extension = kwargs.get('extension', '') self.prefix = kwargs.get('prefix', '') self.encoding = kwargs.get('encoding', 'utf-8') return obj