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())
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)) == []
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)
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])