Example #1
0
    def __getitem__(self, key):
        '''Returns a paritioned QueryObject.

        If `key` is an integer it will be treated as ``slice(key, key+1)``.

        Otherwise it must be a slice. In this case if `self` has a partition
        the returning query object will have a partition that's a mix between
        self's partition and the `key`:

        - If both current start and key's start are negative, the max it's
          taken. Otherwise they are simply added.

        - If both current stop and key's stop are non-negative, the min it's
          taken. Otherwise they are simply added.

        - If both steps are non-negative, the max it's taken. Otherwise the min
          it's taken.

        '''
        from copy import copy
        from xoutil.compat import integer
        from xoutil.objects import extract_attrs
        if isinstance(key, integer):
            key = slice(key, key+1)
        assert isinstance(key, slice)
        result = copy(self)
        partition = result.partition
        if partition:
            start, stop, step = extract_attrs(partition, 'start', 'stop', 'step')
            if not start:
                start = key.start
            elif not key.start:
                pass   # Safe-keeper: In Py3k None is not comparable
            elif start <= 0 and key.start <= 0:
                start = max(start, key.start)
            else:
                start = start + key.start
            if not stop:
                stop = key.stop
            elif not key.stop:
                pass   # Safe-keeper: In Py3k None is not comparable
            elif stop >= 0 and key.stop >= 0:
                stop = min(stop, key.stop)
            else:
                stop = stop + key.stop
            if not step:
                step = key.step
            elif not key.step:
                pass   # Safe-keeper: In Py3k None is not comparable
            elif step >= 0 and key.step >= 0:
                step = max(step, key.step)
            else:
                step = min(step, key.step)
            partition = slice(start, stop, step)
        else:
            partition = key
        result.partition = partition
        return result
def test_extract_attrs():
    from xoutil.objects import extract_attrs
    d = dict(a=(1,), b=2, c=3, x=4)
    assert extract_attrs(d, 'a') == (1,)
    assert extract_attrs(d, 'a', 'b', 'c', 'x') == ((1,), 2, 3, 4)

    with pytest.raises(AttributeError):
        assert extract_attrs(d, 'y')
    assert extract_attrs(d, 'y', default=None) is None

    class new(object):
        def __init__(self, **kw):
            self.__dict__.update(kw)

    d = new(a=(1,), b=2, c=3, x=4)
    assert extract_attrs(d, 'a') == (1,)
    assert extract_attrs(d, 'a', 'b', 'c', 'x') == ((1,), 2, 3, 4)

    with pytest.raises(AttributeError):
        assert extract_attrs(d, 'y')
    assert extract_attrs(d, 'y', default=None) is None
Example #3
0
File: py.py Project: mvaled/xotl.ql
def naive_translation(query, **kwargs):
    '''Does a naive translation to Python's VM memory.
    '''
    import functools
    from xotl.ql import translation as trans

    only = kwargs.get('only', None)

    def mix(filters, tokens):
        '''Intertwines tokens and filters.'''
        if not filters:
            return tokens
        return list(sorted(tokens + filters,
                           key=functools.cmp_to_key(trans.cmp)))

    sorted_parts = mix(query.filters, query.tokens)
    assert isinstance(sorted_parts[0], GeneratorToken), sorted_parts

    def select(sel, vm):
        from xotl.ql.expressions import _false
        result = []
        selectors = (sel, ) if not isinstance(sel, tuple) else sel
        for s in selectors:
            if isinstance(s, Term):
                result.append(var(s, vm)._get_current_value())
            else:
                result.append(vminstr(s, vm)())
        if any(res is _false for res in result):
            return _false
        if isinstance(sel, tuple):
            return tuple(result)
        else:
            assert len(result) == 1
            return result[0]

    def plan(**plan_kwargs):
        # The algorithm is simple; first we "intertwine" tokens and filters
        # using a (stable) partial order: a filter comes before a token if and
        # only if neither of it's terms is bound to the token.
        #
        # The we just build several chained generators that either produce
        # (affect the vm) or filter.
        #
        from xoutil.objects import get_first_of
        from xotl.ql.expressions import _false
        parts = list(sorted_parts[:])
        vm = get_first_of((plan_kwargs, kwargs), 'vm', default={})
        # vm = plan_kwargs.get('vm', None) or kwargs.get('vm', None) or {}
        result = vmtoken(parts.pop(0), vm, query, only=only)
        while parts:
            part = parts.pop(0)
            if isinstance(part, GeneratorToken):
                result = vmtoken(part, vm, query, only=only).chain(result)
            else:
                result = vminstr(part, vm).chain(result)
        for _ in result:
            selected = select(query.selection, vm)
            if selected is not _false:
                yield selected

    if query.ordering:
        def plan_with_ordering(**plan_kwargs):
            vm = plan_kwargs.setdefault('vm', {})
            key = lambda: tuple(vminstr(order_expr, vm=vm)() for order_expr in query.ordering)
            # XXX: Don't use sorted(plan(**plan_kwargs), key=key)
            #
            #      Since the vm is constantly being updated after each yield we
            #      must make sure, key() is called exactly when the vm has the
            #      desired state for each object; but sorted may retreive
            #      several items in chunks and call key aftewards which will
            #      not yield the right results.
            return (sel for k, sel in sorted((key(), r) for r in plan(**plan_kwargs)))
        res = plan_with_ordering
    else:
        res = plan
    if query.partition:
        from xoutil.objects import extract_attrs
        start, stop, step = extract_attrs(query.partition, 'start', 'stop',
                                          'step')
        def plan_with_partition(**kwargs):
            from itertools import islice
            return islice(res(**kwargs), start, stop, step)
        return plan_with_partition
    return res