"""cached profiles""" import datetime import glob import os import sys import lxml.etree as etree from lxml.builder import ElementMaker import filing from nitpo import Nitpo from nixer import Nixer from profile import Profile # from xpaths import Xpaths from surks import Surks class Kapro(Nitpo): def __init__(self, do_verbose=False, do_suppress=True): super().__init__() ns = self.const['ns'] self.nsmap = {None: ns} self.N = "{%s}" % self.const['ns'] self.check_conf('folders', 'profile') self.check_conf('folders', 'kapro') self.to_print = '' self.event = {} self.d = {} self.dirs = {} self.dirs['profile'] = self.conf['folders']['profile'] self.dirs['kapro'] = self.conf['folders']['kapro'] self.start_time = datetime.datetime.now().timestamp() self.parser = etree.XMLParser(remove_blank_text=True) # self.x = Xpaths() self.profile = Profile() self.nixer = Nixer() self.surks = Surks() # # state variable self.indat = None # # library of profiles for brore testing self.lib = None self.repcode = None self.do_suppress = do_suppress self.do_verbose = do_verbose def all(self): """do all reports from scratch""" for root, dirs, banas in os.walk(self.dirs['profile']): for bana in banas: if bana == 'omnibus.xml': continue if not bana.endswith(".xml"): continue fufi = root + '/' + bana doc = filing.parse_lax(fufi, parser=self.parser) if doc is None: continue self.get_all(doc) self.dump_all() def dump_all(self): for repcode in self.d: self.dump(repcode) def dump(self, repcode): if self.do_verbose: print(f"kapro dumps for {repcode}") out_fufi = self.get_fufi(repcode) filing.dump(out_fufi, self.d[repcode]) os.utime(out_fufi, (self.start_time, self.start_time)) def load(self, repcode): if self.do_verbose: print(f"kapro dumps for {repcode}") kapro_fufi = self.get_fufi(repcode) if not os.path.isfile(kapro_fufi): return {} surks_data = filing.load(kapro_fufi) return surks_data def delete(self, repcode, emad): if repcode not in self.d: self.d[repcode] = self.load(repcode) if emad not in self.d[repcode]: return False del self.d[repcode][emad] self.dump(repcode) ### should be called by surks.fecha but it can not import # def add(self, surk_ele, emad): # """should be called by surks.fecha but it can not import""" # if 'repcode' not in surk_ele.attrib: # print(f"kapro sees not repcode on the surk", # file=sys.stderr) # return None # repcode = surk_ele.attrib['repcode'] # if repcode not in self.d: # self.d[repcode] = self.load(repcode) # self.d[repcode][emad] = self.surks.sint(surk_ele) # self.dump(repcode) def get_all(self, doc): surk_eles = self.profile.live_surks(doc) if len(surk_eles) == 0: return False emad = self.surks.get_emad(doc) if self.do_suppress: if self.nixer.has_it_current_fufi(emad): if self.do_verbose: print(f"kapro skips nixed {emad}") return False for surk_ele in surk_eles: self.from_surk(surk_ele, emad) return True def from_surk(self, surk_ele, emad): repcode = surk_ele.attrib['repcode'] if repcode not in self.d: self.d[repcode] = {} self.d[repcode][emad] = self.surks.sint(surk_ele) def start(self, repcode): """start a kapro with no data""" self.d[repcode] = {} self.dump(repcode) def get_fufi(self, repcode): out_fufi = self.dirs['kapro'] + '/' + repcode + '.json.gz' return out_fufi def update(self, repcode): """update for a report""" out_fufi = self.get_fufi(repcode) out_time = 0 if os.path.isfile(out_fufi): out_time = os.path.getmtime(out_fufi) fufis = [] for root, dirs, banas in os.walk(self.dirs['profile']): for bana in banas: if bana.endswith('~'): continue fufi = root + '/' + bana if bana == 'omnibus.xml' or bana == 'omnibus.xml.gz': continue if not os.path.isfile(fufi): continue if os.path.getmtime(fufi) < out_time: if self.do_verbose: print(f"kapro skips {fufi} as too recent.") continue if self.do_verbose: print(f"I have to read {fufi}") if self.do_verbose: print("kapro adds {fufi}") fufis.append(fufi) if len(fufis) == 0: if self.do_verbose: print(f"kapro found no files to update for {repcode}.") return False if not os.path.isfile(out_fufi): if self.do_verbose: print(f"kapro does not see {out_fufi}") self.indat = {} else: self.indat = filing.load(out_fufi) self.repcode = repcode count_updates = 0 for fufi in fufis: needs_update = self.update_for_fufi(fufi) count_updates += needs_update if count_updates == 0: if self.do_verbose: print("krapo sees no changes to write.") if os.path.isfile(out_fufi): os.utime(out_fufi, (self.start_time, self.start_time)) else: if self.do_verbose: print(f"krapo writes {out_fufi}") filing.dump(self.indat, out_fufi) # # set to the start time of the script self.indat = None self.repcode = None def update_for_fufi(self, fufi): # doc = etree.parse_lax(fufi) doc = filing.parse_lax(fufi) if doc is None: return 0 if self.do_verbose: print(f"kapro reads {fufi}.") live_surk = self.profile.live_surk(doc, self.repcode) emad = self.surks.get_emad(doc) if live_surk is None: if emad not in self.indat: return 0 if self.do_verbose: print(f"kapro dels {emad}.") del self.indat[emad] return 1 else: if emad in self.indat: return 0 if self.do_verbose: print(f"kapro adds {emad}.") self.indat[emad] = self.surks.sint(live_surk) return 1 def build_lib(self, do_clear=True): if not self.has_conf('files', 'libpro'): print("reports: I need a [files][libpro] configuration.") sys.exit(1) libpro_fufi = self.conf['files']['libpro'] if do_clear and os.path.isfile(libpro_fufi): os.remove(libpro_fufi) fufis = [] for root, dirs, banas in os.walk(self.dirs['profile']): for bana in banas: if not bana.endswith('.xml'): continue if bana == 'omnibus.xml': continue fufi = root + '/' + bana fufis.append(fufi) filing.dump(fufis, libpro_fufi) def load_lib(self): if not self.has_conf('files', 'libpro'): print("reports: I need a [files][libpro] configuration.") sys.exit(1) self.lib = filing.load(self.conf['files']['libpro']) return self.lib def summarize(self): """returns subbers and surks""" from lxml.builder import ElementMaker glob_string = self.dirs['kapro'] + '/*.json.gz' fufis = glob.glob(glob_string) sumsu = {} sumsu['reports'] = {} count_surks = 0 subbers = {} for fufi in fufis: bana = os.path.basename(fufi) repcode = bana.partition('.')[0] sumsu['reports'][repcode] = 0 data = filing.load(fufi) for emad in data: if data[emad] != 's' and self.do_verbose: print("I skip {emad} with value {data[emad]}") count_surks += 1 sumsu['reports'][repcode] += 1 if emad in subbers: continue subbers[emad] = 1 sumsu['subbers'] = len(subbers) sumsu['surks'] = count_surks return sumsu def sumsu_doc(self, sumsu): nsmap = {None: self.const['ns']} em = ElementMaker(nsmap=nsmap) sumsu_ele = em(self.N + 'sumsu') sumsu_ele.attrib['surks'] = str(sumsu['surks']) sumsu_ele.attrib['subbers'] = str(sumsu['subbers']) sumsu_ele.attrib['datim'] = self.now() for repcode in sumsu['reports']: report_ele = etree.SubElement(sumsu_ele, self.N + 'report') report_ele.attrib['repcode'] = repcode report_ele.attrib['count'] = str(sumsu['reports'][repcode]) # filing.install_xml(sumsu_ele, '/tmp/sumsu.xml') return sumsu_ele