def test_multiple(self):
     result = list(utils.lookahead([1, 2, 3]))
     self.assertListEqual(result, [
         (1, True),
         (2, True),
         (3, False),
     ])
Example #2
0
def decode_complex_ops(encoded_querystring, operators=None, negation=True):
    """
    Returns a list of (querystring, negate, op) tuples that represent complex operations.

    This function will raise a `ValidationError`s if:
    - the individual querystrings are not wrapped in parentheses
    - the set operators do not match the provided `operators`
    - there is trailing content after the ending querysting

    Ex::

        # unencoded query: (a=1) & (b=2) | ~(c=3)
        >>> s = '%28a%253D1%29%20%26%20%28b%253D2%29%20%7C%20%7E%28c%253D3%29'
        >>> decode_querystring_ops(s)
        [
            ('a=1', False, QuerySet.__and__),
            ('b=2', False, QuerySet.__or__),
            ('c=3', True, None),
        ]
    """
    complex_op_re = COMPLEX_OP_NEG_RE if negation else COMPLEX_OP_RE
    if operators is None:
        operators = COMPLEX_OPERATORS

    # decode into: (a%3D1) & (b%3D2) | ~(c%3D3)
    decoded_querystring = unquote(encoded_querystring)
    matches = [m for m in complex_op_re.finditer(decoded_querystring)]

    if not matches:
        msg = _("Unable to parse querystring. Decoded: '%(decoded)s'.")
        raise ValidationError(msg % {'decoded': decoded_querystring})

    results, errors = [], []
    for match, has_next in lookahead(matches):
        negate, querystring, op = match.groups()

        negate = negate == '~'
        querystring = unquote(querystring)
        op_func = operators.get(op.strip()) if op else None
        if op_func is None and has_next:
            msg = _("Invalid querystring operator. Matched: '%(op)s'.")
            errors.append(msg % {'op': op})

        results.append(ComplexOp(querystring, negate, op_func))

    trailing_chars = decoded_querystring[matches[-1].end():]
    if trailing_chars:
        msg = _(
            "Ending querystring must not have trailing characters. Matched: '%(chars)s'."
        )
        errors.append(msg % {'chars': trailing_chars})

    if errors:
        raise ValidationError(errors)

    return results
 def test_single(self):
     result = list(utils.lookahead([1]))
     self.assertListEqual(result, [(1, False)])
 def test_empty(self):
     result = list(utils.lookahead([]))
     self.assertListEqual(result, [])