def delete(self): try: self.delete_value() except Exception: utils.add_exception_info("Path: %s \n " "Value: %s" % (self.__str__(), utils.truncate(self.value))) raise
def delete_value(self): try: del self.parent.value[self.key] except Exception: utils.add_exception_info("This value was obtained by direct iteration, " "so there may be no easy way to delete it.") raise
def search(search_value, iterator=None, contains=True, ignore_case=True, fuzzy=None, strings_only=True, ignore_str_errors=False, search_items="both"): """ :type search_value: basestring :type iterator: collections.Iterable[Path] :rtype: collections.Iterable[Path] """ if search_items not in ("keys", "values", "both"): raise ValueError("search_items must be 'keys', 'values', or 'both' (default).") if fuzzy is not None and not (isinstance(fuzzy, float) and 0 <= fuzzy <= 1): raise ValueError("fuzzy must either be None or a float between 0 and 1.") if not isinstance(search_value, basestring): raise TypeError("The search_value must be a basestring.") if ignore_case: search_value = search_value.lower() if fuzzy: sequence_matcher = SequenceMatcher(b=search_value) substr_cache = {} if not iterator: frame = inspect.stack()[1][0] iterator = Recursor(Variables(frame.f_locals, frame.f_globals)) if search_items == "keys": items = lambda p: (p.key,) elif search_items == "values": items = lambda p: (p.value,) else: items = lambda p: (p.key, p.value) for path in iterator: for item in items(path): if not isinstance(item, basestring): if strings_only: continue # noinspection PyBroadException try: item = str(item) except Exception: if not ignore_str_errors: utils.add_exception_info("You can supress exceptions raised by calls to str with " "the argument ignore_str_errors=True.") raise if ignore_case: item = item.lower() matches = False if fuzzy: sequence_matcher.set_seq1(item) if contains: # Algorithm adapted from the fuzzywuzzy library # each block represents a sequence of matching characters in a string # of the form (idx_1, idx_2, len) # the best partial match will block align with at least one of those blocks # e.g. shorter = "abcd", longer = XXXbcdeEEE # block = (1,3,3) # best score === ratio("abcd", "Xbcd") # TODO test case where value is shorter than item # e.g. does fuzzy search for example match exmple? # TODO handle unicode for block in sequence_matcher.get_matching_blocks()[:-1]: item_start = block[0] - block[1] if block[0] - block[1] > 0 else 0 substr = item[item_start:item_start + len(search_value)] result = substr_cache.get(substr) if result is None: sequence_matcher.set_seq1(substr) result = sequence_matcher.quick_ratio() >= fuzzy and sequence_matcher.ratio() >= fuzzy substr_cache[substr] = result if result: matches = True break else: matches = (sequence_matcher.real_quick_ratio() >= fuzzy and sequence_matcher.quick_ratio() >= fuzzy and sequence_matcher.ratio() >= fuzzy) else: if contains: matches = search_value in item else: matches = search_value == item if matches: yield path break