# Created By: Virgil Dupras # Created On: 2006/05/02 # Copyright 2011 Hardcoded Software (http://www.hardcoded.net) # # This software is licensed under the "BSD" License as described in the "LICENSE" file, # which should be included with this package. The terms are also available at # http://www.hardcoded.net/licenses/bsd_license from xml.etree import ElementTree as ET from hscommon.util import FileOrPath class IgnoreList: """An ignore list implementation that is iterable, filterable and exportable to XML. Call Ignore to add an ignore list entry, and AreIgnore to check if 2 items are in the list. When iterated, 2 sized tuples will be returned, the tuples containing 2 items ignored together. """ #---Override def __init__(self): self._ignored = {} self._count = 0 def __iter__(self): for first,seconds in self._ignored.items(): for second in seconds: yield (first,second) def __len__(self): return self._count #---Public def AreIgnored(self,first,second): def do_check(first,second): try: matches = self._ignored[first] return second in matches except KeyError: return False return do_check(first,second) or do_check(second,first) def Clear(self): self._ignored = {} self._count = 0 def Filter(self,func): """Applies a filter on all ignored items, and remove all matches where func(first,second) doesn't return True. """ filtered = IgnoreList() for first,second in self: if func(first,second): filtered.Ignore(first,second) self._ignored = filtered._ignored self._count = filtered._count def Ignore(self,first,second): if self.AreIgnored(first,second): return try: matches = self._ignored[first] matches.add(second) except KeyError: try: matches = self._ignored[second] matches.add(first) except KeyError: matches = set() matches.add(second) self._ignored[first] = matches self._count += 1 def remove(self, first, second): def inner(first, second): try: matches = self._ignored[first] if second in matches: matches.discard(second) if not matches: del self._ignored[first] self._count -= 1 return True else: return False except KeyError: return False if not inner(first, second): if not inner(second, first): raise ValueError() def load_from_xml(self, infile): """Loads the ignore list from a XML created with save_to_xml. infile can be a file object or a filename. """ try: root = ET.parse(infile).getroot() except Exception: return file_elems = (e for e in root if e.tag == 'file') for fn in file_elems: file_path = fn.get('path') if not file_path: continue subfile_elems = (e for e in fn if e.tag == 'file') for sfn in subfile_elems: subfile_path = sfn.get('path') if subfile_path: self.Ignore(file_path, subfile_path) def save_to_xml(self, outfile): """Create a XML file that can be used by load_from_xml. outfile can be a file object or a filename. """ root = ET.Element('ignore_list') for filename, subfiles in self._ignored.items(): file_node = ET.SubElement(root, 'file') file_node.set('path', filename) for subfilename in subfiles: subfile_node = ET.SubElement(file_node, 'file') subfile_node.set('path', subfilename) tree = ET.ElementTree(root) with FileOrPath(outfile, 'wb') as fp: tree.write(fp, encoding='utf-8')