def test_traverse():
    """To test the traverse implementation we call gc.collect() while instances
    of all the C objects are still valid."""
    acc = iteration_utilities.accumulate([])
    app = iteration_utilities.applyfunc(lambda x: x, 1)
    cha = iteration_utilities.chained(int, float)
    cla = iteration_utilities.clamp([], 0, 1)
    com = iteration_utilities.complement(int)
    con = iteration_utilities.constant(1)
    dee = iteration_utilities.deepflatten([])
    dup = iteration_utilities.duplicates([])
    fli = iteration_utilities.flip(int)
    gro = iteration_utilities.grouper([], 2)
    ine = iteration_utilities.intersperse([], 1)
    iik = iteration_utilities.ItemIdxKey(10, 2)
    ite = iteration_utilities.iter_except(int, TypeError)
    mer = iteration_utilities.merge([])
    nth = iteration_utilities.nth(1)
    pac = iteration_utilities.packed(int)
    par = iteration_utilities.partial(int, 10)
    rep = iteration_utilities.replicate([], 3)
    rou = iteration_utilities.roundrobin([])
    see = iteration_utilities.Seen()
    sid = iteration_utilities.sideeffects([], lambda x: x)
    spl = iteration_utilities.split([], lambda x: True)
    sta = iteration_utilities.starfilter(lambda x: True, [])
    suc = iteration_utilities.successive([])
    tab = iteration_utilities.tabulate(int)
    une = iteration_utilities.unique_everseen([])
    unj = iteration_utilities.unique_justseen([])
    gc.collect()
def test_unique_justseen_attributes1():
    it = unique_justseen(toT([1, 1, 2, 2, 3, 3]), None)
    assert it.key is None
    with pytest.raises(AttributeError):
        it.lastseen

    next(it)

    assert it.lastseen == T(1)
def test_unique_justseen_failure4():
    # Test that a failing iterator doesn't raise a SystemError
    with pytest.raises(_hf.FailNext.EXC_TYP, match=_hf.FailNext.EXC_MSG):
        next(unique_justseen(_hf.FailNext()))
def test_unique_justseen_failure3():
    # objects do not support eq or ne
    with pytest.raises(TypeError):
        list(unique_justseen([T2(1), T2(2)]))
def test_unique_justseen_failure2():
    with pytest.raises(TypeError):  # function call fails
        list(unique_justseen([T(1), T(2), T(3)], key=lambda x: x + 'a'))
def test_unique_justseen_failure1():
    with pytest.raises(_hf.FailIter.EXC_TYP, match=_hf.FailIter.EXC_MSG):
        unique_justseen(_hf.FailIter())
Example #7
0
def getitem(iterable, idx=None, start=None, stop=None, step=None):
    """Get the item at `idx` or the items specified by `start`, `stop` and
    `step`.

    Parameters
    ----------
    iterable : iterable
        The iterable from which to extract the items.

    idx : positive :py:class:`int`, -1, tuple/list thereof, or None, optional
        If not ``None``, get the item at `idx`. If it's a tuple or list get
        all the items specified in the tuple (they will be sorted so the
        specified indices are retrieved).
        Default is ``None``.

        .. note::
           This parameter must not be ``None`` if also `start`, `stop` and
           `step` are ``None``.

    start : :py:class:`int` or None, optional
        If ``None`` then take all items before `stop`, otherwise take only
        the items starting by `start`.
        Default is ``None``.

        .. note::
           This parameter is ignored if `idx` is not ``None``.

    stop : :py:class:`int` or None, optional
        If ``None`` then take all items starting by `start`, otherwise only
        take the items before `stop`.
        Default is ``None``.

        .. note::
           This parameter is ignored if `idx` is not ``None``.

    step : positive :py:class:`int` or None, optional
        If ``None`` then take all items seperated by `step`, otherwise take
        successive items.
        Default is ``None``.

        .. note::
           This parameter is ignored if `idx` is not ``None``.

    Returns
    -------
    items : any type or generator
        If `idx` was not ``None`` then it returns the item, otherwise it
        returns the items specified by `start`, `stop` and `step`.

    Examples
    --------
    The main bulk of examples is in
    :py:meth:`~iteration_utilities.Iterable.getitem` because that's where
    this function was originally implemented.
    """
    if idx is None and start is None and stop is None and step is None:
        raise TypeError('one of "idx", "start" or "stop" must be given.')

    it = iter(iterable)

    if idx is not None:
        if not isinstance(idx, (tuple, list)):
            if idx < -1:
                raise ValueError('index must be -1 or bigger.')
            return nth(idx)(iterable)
        elif not idx:
            return []
        else:
            # A list of indices, we sort it (insert -1 at the end because it's
            # the last one) and then extract all the values.
            idx = sorted(idx, key=lambda x: x if x != -1 else float('inf'))
            if idx[0] < -1:
                raise ValueError('index must be -1 or bigger.')
            current = 0
            ret = []
            for i in unique_justseen(idx):
                ret.append(nth(i - current)(it))
                current = i + 1
            return ret

    start_gt_0 = start is None or start > 0
    step_gt_0 = step is None or step > 0

    start_lt_0 = start is not None and start < 0
    stop_lt_0 = stop is not None and stop < 0
    step_lt_0 = step is not None and step < 0

    # Several possibilities:

    # - start None, stop None, step None = self
    # if start is None and stop is None and step is None:
    #     return iterable

    # - start None or > 0, stop None, step None or > 0 = islice
    if start_gt_0 and stop is None and step_gt_0:
        return islice(iterable, start, stop, step)

    # - start None or > 0, stop > 0, step None or > 0 = finite islice
    elif start_gt_0 and stop is not None and stop > 0 and step_gt_0:
        return islice(iterable, start, stop, step)

    # There could be valid cases with negative steps, for example if
    # reversed can be applied. But I won't go down that road!
    elif step_lt_0:
        raise ValueError('negative "step" is not possible.')

    # Any other combination requires the start to be not None and
    # negative.
    elif start_lt_0:
        # - start < 0, stop < 0, step None or > 0 = tail then islice.
        if stop_lt_0 and step_gt_0:
            it = tail(iterable, -start)
            it = islice(it, 0, stop - start, step)
            return it
        # - start < 0, stop None, step None = tail
        elif stop is None and step is None:
            it = tail(iterable, -start)
            return it
        # - start < 0, stop None, step > 0 = tail and islice
        elif stop is None and step > 0:
            it = tail(iterable, -start)
            it = islice(it, 0, None, step)
            return it
    else:
        raise ValueError('{0} cannot be subscripted with any '
                         'combination of negative "start", "stop" or '
                         '"step". This combination wasn\'t allowed.')
def test_unique_justseen_failure_setstate2():
    _hf.iterator_setstate_empty_fail(unique_justseen(toT([1, 2, 3])))
def test_unique_justseen_normal2():
    assert list(unique_justseen('aAabBb')) == ['a', 'A', 'a', 'b', 'B', 'b']
def test_unique_justseen_normal1():
    assert list(unique_justseen(toT([1, 1, 2, 2, 3, 3]))) == toT([1, 2, 3])
def test_unique_justseen_empty1():
    assert list(unique_justseen([])) == [] == []
def test_unique_justseen_pickle4(protocol):
    ujs = unique_justseen(['a', 'A', 'a'], key=str.lower)
    assert next(ujs) == 'a'
    x = pickle.dumps(ujs, protocol=protocol)
    assert list(pickle.loads(x)) == []
Example #13
0
def remove(iterable, idx=None, start=None, stop=None):
    """Removes the item at `idx` or from `start` (inclusive) to `stop`
    (exclusive).

    Parameters
    ----------
    iterable : iterable
        The iterable in which to remove the item(s).

    idx : positive :py:class:`int`, list/tuple thereof, None, optional
        If not ``None``, remove the item at `idx`. If it's a tuple or list then
        replace all the present indices (they will be sorted so only the
        specified indices are removed).
        Default is ``None``.

        .. note::
           This parameter must not be ``None`` if also `start` and `stop` are
           ``None``.

    start : positive :py:class:`int` or None, optional
        If ``None`` then remove all items before `stop`, otherwise remove only
        the items starting by `start`.
        Default is ``None``.

        .. note::
           This parameter is ignored if `idx` is not ``None``.

    stop : positive :py:class:`int` or None, optional
        If ``None`` then remove all items starting by `start`, otherwise only
        remove the items before `stop`.
        Default is ``None``.

        .. note::
           This parameter is ignored if `idx` is not ``None``.

    Returns
    -------
    replaced : generator
        The `iterable` with the specified items removed.

    Examples
    --------
    To remove one item::

        >>> from iteration_utilities import remove
        >>> list(remove(range(10), idx=2))
        [0, 1, 3, 4, 5, 6, 7, 8, 9]

    To remove several items just provide a tuple as idx (the values are sorted,
    so exactly the specified elements are removed)::

        >>> list(remove(range(10), (4, 6, 8, 5, 1)))
        [0, 2, 3, 7, 9]

    To remove a slice::

        >>> list(remove(range(10), start=2))
        [0, 1]

        >>> list(remove(range(10), stop=2))
        [2, 3, 4, 5, 6, 7, 8, 9]

        >>> list(remove(range(10), start=2, stop=5))
        [0, 1, 5, 6, 7, 8, 9]
    """
    if idx is None and start is None and stop is None:
        raise TypeError('one of "idx", "start" or "stop" must be given.')

    it = iter(iterable)

    if idx is not None:
        if not isinstance(idx, (list, tuple)):
            return chain(islice(it, idx), islice(it, 1, None))
        elif not idx:
            return iterable
        else:
            idx = sorted(idx)
            ret = []
            current = 0
            for num, i in enumerate(unique_justseen(idx)):
                if not num:
                    ret.append(islice(it, i))
                else:
                    ret.append(islice(it, 1, i - current))
                current = i
            ret.append(islice(it, 1, None))
            return chain.from_iterable(ret)

    if start is not None and stop is not None:
        range_ = stop - start
        if range_ < 0:
            raise ValueError('"stop" must be greater than or equal to '
                             '"start".')
        return chain(islice(it, start), islice(it, range_, None))
    elif start is not None:
        return islice(it, start)
    else:
        return islice(it, stop, None)
Example #14
0
def replace(iterable, element, idx=None, start=None, stop=None, unpack=False):
    """Removes the item at `idx` or from `start` (inclusive) to `stop`
    (exclusive) and then inserts the `element` there.

    Parameters
    ----------
    iterable : iterable
        The iterable in which to replace the item(s).

    element : any type
        The element to insert after removing.

    idx : positive :py:class:`int`, list/tuple thereof, None, optional
        If not ``None``, remove the item at `idx` and insert `element` there.
        If it's a tuple or list the `element` is inserted at each of the
        indices in the `idx` (the values are sorted before, so the element is
        always inserted at the given indices).
        Default is ``None``.

        .. note::
           This parameter must not be ``None`` if also `start` and `stop` are
           ``None``.

    start : positive :py:class:`int` or None, optional
        If ``None`` then remove all items before `stop`, otherwise remove only
        the items starting by `start`.
        Default is ``None``.

        .. note::
           This parameter is ignored if `idx` is not ``None``.

    stop : positive :py:class:`int` or None, optional
        If ``None`` then remove all items starting by `start`, otherwise only
        remove the items before `stop`.
        Default is ``None``.

        .. note::
           This parameter is ignored if `idx` is not ``None``.

    unpack : :py:class:`bool`, optional
        If ``False`` the `element` is inserted as it is. If ``True`` then the
        `element` must be an iterable and it is unpacked into the `iterable`.
        Default is ``False``.

    Returns
    -------
    replaced : generator
        The `iterable` with the specified items removed and `element` inserted
        in their place.

    Examples
    --------
    To replace one item::

        >>> from iteration_utilities import replace
        >>> list(replace(range(10), 100, idx=2))
        [0, 1, 100, 3, 4, 5, 6, 7, 8, 9]

    To replace multiple items::

        >>> list(replace(range(10), 100, (3, 5, 1)))
        [0, 100, 2, 100, 4, 100, 6, 7, 8, 9]

    To replace slices::

        >>> list(replace(range(10), 100, start=2))
        [0, 1, 100]

        >>> list(replace(range(10), 100, stop=2))
        [100, 2, 3, 4, 5, 6, 7, 8, 9]

        >>> list(replace(range(10), 100, start=2, stop=5))
        [0, 1, 100, 5, 6, 7, 8, 9]
    """
    if idx is None and start is None and stop is None:
        raise TypeError('one of "idx", "start" or "stop" must be given.')

    if not unpack:
        element = [element]

    it = iter(iterable)

    if idx is not None:
        if not isinstance(idx, (list, tuple)):
            return chain(islice(it, idx), element, islice(it, 1, None))
        elif not idx:
            return iterable
        else:
            idx = sorted(idx)
            ret = []
            current = 0
            for num, i in enumerate(unique_justseen(idx)):
                if not num:
                    ret.append(islice(it, i))
                else:
                    ret.append(islice(it, 1, i - current))
                ret.append(element)
                current = i
            ret.append(islice(it, 1, None))
            return chain.from_iterable(ret)

    if start is not None and stop is not None:
        range_ = stop - start
        if range_ <= 0:
            raise ValueError('"stop" must be greater than "start".')
        return chain(islice(it, start), element, islice(it, range_, None))
    elif start is not None:
        return chain(islice(it, start), element)
    else:  # elif stop is not None!
        return chain(element, islice(it, stop, None))
def test_unique_justseen_failure5():
    # Too few arguments
    with pytest.raises(TypeError):
        unique_justseen()
def test_unique_justseen_copy1():
    _hf.iterator_copy(unique_justseen([T(1), T(2), T(3)]))
def test_unique_justseen_normal3():
    assert list(unique_justseen('aAabBb', key=str.lower)) == ['a', 'b']
def test_unique_justseen_pickle1(protocol):
    ujs = unique_justseen([T(1), T(2), T(3)])
    x = pickle.dumps(ujs, protocol=protocol)
    assert list(pickle.loads(x)) == toT([1, 2, 3])
def test_unique_justseen_normal4():
    # key=None is identical to no key
    assert list(unique_justseen(toT([1, 1, 2, 2, 3, 3]),
                                None)) == toT([1, 2, 3])