Exemplo n.º 1
0
 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
Exemplo n.º 2
0
 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
Exemplo n.º 3
0
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