# Created By: Virgil Dupras # Created On: 2006/05/02 # Copyright 2015 Hardcoded Software (http://www.hardcoded.net) # # This software is licensed under the "GPLv3" License as described in the "LICENSE" file, # which should be included with this package. The terms are also available at # http://www.gnu.org/licenses/gpl-3.0.html 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.clear() 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 are_ignored(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.are_ignored(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) and 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")