def search_object_non_rec(obj, path, *attrs, **attrs_value): res = next(search_object(obj, path, *attrs, **attrs_value)) if res: p, e = res yield p, e # only next siblings and remaining next cousins, etc... p_cur, cur = p, e while cur and '/' in p_cur: if cur is obj: yield p_par = p_cur.rsplit('/', 1)[0] par = get_descendant(obj, p_par.split('/')) if utils.is_sequence(par): next_siblings = list(range(par.index(cur) + 1, len(par))) else: next_siblings = { k for i, k in enumerate(par.keys()) if i > list(par.keys()).index(cur) } for s in next_siblings: for ps, pe in par[s].search_non_rec(path, *attrs, **attrs_value): yield ps, pe p_cur, cur = p_par, cur._parent
def search_object(obj, path, *attrs, **attrs_value): """wrapper around dpath.util with filters on attributes presence and value""" import dpath.util, dpath.path afilter = Filter(*attrs, **attrs_value) if attrs or attrs_value else None separator = '/' globlist = dpath.util.__safe_path__(path, separator) for path in dpath.util._inner_search(obj, globlist, '/', dirs=True): val = get_descendant(obj, [p[0] for p in path]) if afilter and afilter(val): yield (separator.join(map(str, dpath.path.paths_only(path))), val)
def __call__(self, obj): test = not self.anyOf for k, v2 in self.attrs_value.items(): ks, ops, ops_negate = self.attrs_ops[k] o = get_descendant(obj, ks) if o is None: # breaking the look we never go in the for/ELSE statement where # an object is potentially yielded test = False break elif ops and utils.is_mapping(o): # check if it s not a child for op in ops: o2 = get_descendant(o, op) if o2: o = o2 ks.append(ops.pop(0)) else: test = False break ops = ops or ['eq'] v = _comparable(o) test2 = bool(_apply_ops_test(ops, ops_negate, v, v2)) test = (test or test2) if self.anyOf else (test and test2) if self.anyOf: if test2: break elif not test: break for k in self.attrs: ks = k.split('__') test2 = get_descendant(obj, ks) is not None test = (test or test2) if self.anyOf else (test and test2) if self.anyOf: if test2: break elif not test: break # todo change if test is not self.negate: return True return False
def result_cache(self): if self._result_cache is None: self._result_cache = list(self._iterable) ob = self._order_by if ob: from .utils.utils import split_path ks = split_path(ob) if isinstance(ob, str) else ob self._result_cache = sorted(self._result_cache, lambda x: get_descendant(x, ks)) if self._reverse: self._result_cache = reversed(self._result_cache) return self._result_cache
def _filter_or_exclude__(iterable, *attrs, negate=False, any_of=False, distinct=False, **attrs_value): seen = set() attrs_ops = {} for k, v2 in attrs_value.items(): ks, ops = _sort_criteria(k) ops_negate = 'not' in ops if ops_negate: ops.remove('not') attrs_ops[k] = (ks, ops, ops_negate) for obj in iterable: if not obj: continue test = not any_of for k, v2 in attrs_value.items(): ks, ops, ops_negate = attrs_ops[k] o = get_descendant(obj, ks) if o is None: # breaking the look we never go in the for/ELSE statement where # an object is potentially yielded test = False break elif ops and utils.is_mapping(o): # check if it s not a child for op in ops: o2 = get_descendant(o, op) if o2: o = o2 ks.append(ops.pop(0)) else: test = False break ops = ops or ['eq'] v = _comparable(o) test2 = bool(_apply_ops_test(ops, ops_negate, v, v2)) test = (test or test2) if any_of else (test and test2) if any_of: if test2: break elif not test: break for k in attrs: ks = k.split('__') test2 = get_descendant(obj, ks) is not None test = (test or test2) if any_of else (test and test2) if any_of: if test2: break elif not test: break if test is not negate: if distinct: comparable = _comparable(obj) if comparable not in seen: seen.add(comparable) else: continue yield obj