Hello community,

here is the log from the commit of package python-more-itertools for 
openSUSE:Factory checked in at 2020-03-08 22:21:32
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-more-itertools (Old)
 and      /work/SRC/openSUSE:Factory/.python-more-itertools.new.26092 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-more-itertools"

Sun Mar  8 22:21:32 2020 rev:9 rq:780384 version:8.2.0

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-more-itertools/python-more-itertools.changes  
    2020-01-24 13:09:52.989402235 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-more-itertools.new.26092/python-more-itertools.changes
   2020-03-08 22:21:40.179986101 +0100
@@ -1,0 +2,10 @@
+Fri Feb 28 21:37:22 UTC 2020 - Dirk Mueller <dmuel...@suse.com>
+
+- update to 8.2.0:
+   * The .pyi files for typing were updated. (thanks to blueyed and 
ilai-deutel)
+   * :func:`numeric_range` now behaves more like the built-in :func:`range`. 
(thanks to jferard)
+   * :func:`bucket` now allows for enumerating keys. (thanks to alexchandel)
+   * :func:`sliced` now should now work for numpy arrays. (thanks to sswingle)
+   * :func:`seekable` now has a ``maxlen`` parameter.
+
+-------------------------------------------------------------------

Old:
----
  more-itertools-8.1.0.tar.gz

New:
----
  more-itertools-8.2.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-more-itertools.spec ++++++
--- /var/tmp/diff_new_pack.AhbIVF/_old  2020-03-08 22:21:40.695986419 +0100
+++ /var/tmp/diff_new_pack.AhbIVF/_new  2020-03-08 22:21:40.699986422 +0100
@@ -19,7 +19,7 @@
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %define skip_python2 1
 Name:           python-more-itertools
-Version:        8.1.0
+Version:        8.2.0
 Release:        0
 Summary:        More routines for operating on iterables, beyond itertools
 License:        MIT

++++++ more-itertools-8.1.0.tar.gz -> more-itertools-8.2.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/more-itertools-8.1.0/PKG-INFO 
new/more-itertools-8.2.0/PKG-INFO
--- old/more-itertools-8.1.0/PKG-INFO   2020-01-11 19:59:22.000000000 +0100
+++ new/more-itertools-8.2.0/PKG-INFO   2020-01-29 13:52:26.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.2
 Name: more-itertools
-Version: 8.1.0
+Version: 8.2.0
 Summary: More routines for operating on iterables, beyond itertools
 Home-page: https://github.com/erikrose/more-itertools
 Author: Erik Rose
@@ -182,6 +182,18 @@
         
            :noindex:
         
+        8.2.0
+        -----
+        
+        * Bug fixes
+            * The .pyi files for typing were updated. (thanks to blueyed and 
ilai-deutel)
+        
+        * Changes to existing itertools:
+            * numeric_range now behaves more like the built-in range. (thanks 
to jferard)
+            * bucket now allows for enumerating keys. (thanks to alexchandel)
+            * sliced now should now work for numpy arrays. (thanks to sswingle)
+            * seekable now has a ``maxlen`` parameter.
+        
         8.1.0
         -----
         
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/more-itertools-8.1.0/docs/versions.rst 
new/more-itertools-8.2.0/docs/versions.rst
--- old/more-itertools-8.1.0/docs/versions.rst  2020-01-11 19:59:09.000000000 
+0100
+++ new/more-itertools-8.2.0/docs/versions.rst  2020-01-29 13:49:15.000000000 
+0100
@@ -5,6 +5,18 @@
 .. automodule:: more_itertools
    :noindex:
 
+8.2.0
+-----
+
+* Bug fixes
+    * The .pyi files for typing were updated. (thanks to blueyed and 
ilai-deutel)
+
+* Changes to existing itertools:
+    * :func:`numeric_range` now behaves more like the built-in :func:`range`. 
(thanks to jferard)
+    * :func:`bucket` now allows for enumerating keys. (thanks to alexchandel)
+    * :func:`sliced` now should now work for numpy arrays. (thanks to sswingle)
+    * :func:`seekable` now has a ``maxlen`` parameter.
+
 8.1.0
 -----
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/more-itertools-8.1.0/more_itertools/__init__.py 
new/more-itertools-8.2.0/more_itertools/__init__.py
--- old/more-itertools-8.1.0/more_itertools/__init__.py 2020-01-11 
19:59:09.000000000 +0100
+++ new/more-itertools-8.2.0/more_itertools/__init__.py 2020-01-29 
13:51:50.000000000 +0100
@@ -1,4 +1,4 @@
 from .more import *  # noqa
 from .recipes import *  # noqa
 
-__version__ = '8.1.0'
+__version__ = '8.2.0'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/more-itertools-8.1.0/more_itertools/more.py 
new/more-itertools-8.2.0/more_itertools/more.py
--- old/more-itertools-8.1.0/more_itertools/more.py     2020-01-11 
19:59:09.000000000 +0100
+++ new/more-itertools-8.2.0/more_itertools/more.py     2020-01-29 
13:49:15.000000000 +0100
@@ -1,5 +1,5 @@
 import warnings
-from collections import Counter, defaultdict, deque
+from collections import Counter, defaultdict, deque, abc
 from collections.abc import Sequence
 from functools import partial, wraps
 from heapq import merge, heapify, heapreplace, heappop
@@ -18,8 +18,8 @@
     zip_longest,
 )
 from math import exp, floor, log
-from operator import gt, itemgetter, lt, sub
 from random import random, randrange, uniform
+from operator import itemgetter, sub, gt, lt
 from sys import maxsize
 from time import monotonic
 
@@ -772,7 +772,9 @@
     child iterables based on a *key* function.
 
         >>> iterable = ['a1', 'b1', 'c1', 'a2', 'b2', 'c2', 'b3']
-        >>> s = bucket(iterable, key=lambda x: x[0])
+        >>> s = bucket(iterable, key=lambda x: x[0])  # Bucket by 1st character
+        >>> sorted(list(s))  # Get the keys
+        ['a', 'b', 'c']
         >>> a_iterable = s['a']
         >>> next(a_iterable)
         'a1'
@@ -846,6 +848,14 @@
                     elif self._validator(item_value):
                         self._cache[item_value].append(item)
 
+    def __iter__(self):
+        for item in self._it:
+            item_value = self._key(item)
+            if self._validator(item_value):
+                self._cache[item_value].append(item)
+
+        yield from self._cache.keys()
+
     def __getitem__(self, value):
         if not self._validator(value):
             return iter(())
@@ -1051,7 +1061,7 @@
     For non-sliceable iterables, see :func:`chunked`.
 
     """
-    return takewhile(bool, (seq[i : i + n] for i in count(0, n)))
+    return takewhile(len, (seq[i : i + n] for i in count(0, n)))
 
 
 def split_at(iterable, pred):
@@ -1610,7 +1620,7 @@
     return ((k, map(valuefunc, g)) for k, g in res) if valuefunc else res
 
 
-def numeric_range(*args):
+class numeric_range(abc.Sequence, abc.Hashable):
     """An extension of the built-in ``range()`` function whose arguments can
     be any orderable numeric type.
 
@@ -1654,35 +1664,165 @@
         >>> start = datetime.datetime(2019, 1, 1)
         >>> stop = datetime.datetime(2019, 1, 3)
         >>> step = datetime.timedelta(days=1)
-        >>> items = numeric_range(start, stop, step)
+        >>> items = iter(numeric_range(start, stop, step))
         >>> next(items)
         datetime.datetime(2019, 1, 1, 0, 0)
         >>> next(items)
         datetime.datetime(2019, 1, 2, 0, 0)
 
     """
-    argc = len(args)
-    if argc == 1:
-        stop, = args
-        start = type(stop)(0)
-        step = 1
-    elif argc == 2:
-        start, stop = args
-        step = 1
-    elif argc == 3:
-        start, stop, step = args
-    else:
-        err_msg = 'numeric_range takes at most 3 arguments, got {}'
-        raise TypeError(err_msg.format(argc))
+    _EMPTY_HASH = hash(range(0, 0))
 
-    values = (start + (step * n) for n in count())
-    zero = type(step)(0)
-    if step > zero:
-        return takewhile(partial(gt, stop), values)
-    elif step < zero:
-        return takewhile(partial(lt, stop), values)
-    else:
-        raise ValueError('numeric_range arg 3 must not be zero')
+    def __init__(self, *args):
+        argc = len(args)
+        if argc == 1:
+            self._stop, = args
+            self._start = type(self._stop)(0)
+            self._step = type(self._stop - self._start)(1)
+        elif argc == 2:
+            self._start, self._stop = args
+            self._step = type(self._stop - self._start)(1)
+        elif argc == 3:
+            self._start, self._stop, self._step = args
+        elif argc == 0:
+            raise TypeError('numeric_range expected at least '
+                            '1 argument, got {}'.format(argc))
+        else:
+            raise TypeError('numeric_range expected at most '
+                            '3 arguments, got {}'.format(argc))
+
+        self._zero = type(self._step)(0)
+        if self._step == self._zero:
+            raise ValueError('numeric_range() arg 3 must not be zero')
+        self._growing = self._step > self._zero
+        self._init_len()
+
+    def __bool__(self):
+        if self._growing:
+            return self._start < self._stop
+        else:
+            return self._start > self._stop
+
+    def __contains__(self, elem):
+        if self._growing:
+            if self._start <= elem < self._stop:
+                return (elem - self._start) % self._step == self._zero
+        else:
+            if self._start >= elem > self._stop:
+                return (self._start - elem) % (-self._step) == self._zero
+
+        return False
+
+    def __eq__(self, other):
+        if isinstance(other, numeric_range):
+            empty_self = not bool(self)
+            empty_other = not bool(other)
+            if empty_self or empty_other:
+                return empty_self and empty_other  # True if both empty
+            else:
+                return (self._start == other._start
+                        and self._step == other._step
+                        and self._get_by_index(-1) == other._get_by_index(-1))
+        else:
+            return False
+
+    def __getitem__(self, key):
+        if isinstance(key, int):
+            return self._get_by_index(key)
+        elif isinstance(key, slice):
+            step = self._step if key.step is None else key.step * self._step
+
+            if key.start is None or key.start <= -self._len:
+                start = self._start
+            elif key.start >= self._len:
+                start = self._stop
+            else:  # -self._len < key.start < self._len
+                start = self._get_by_index(key.start)
+
+            if key.stop is None or key.stop >= self._len:
+                stop = self._stop
+            elif key.stop <= -self._len:
+                stop = self._start
+            else:  # -self._len < key.stop < self._len
+                stop = self._get_by_index(key.stop)
+
+            return numeric_range(start, stop, step)
+        else:
+            raise TypeError(
+                'numeric range indices must be '
+                'integers or slices, not {}'.format(type(key).__name__))
+
+    def __hash__(self):
+        if self:
+            return hash((self._start, self._get_by_index(-1), self._step))
+        else:
+            return self._EMPTY_HASH
+
+    def __iter__(self):
+        values = (self._start + (n * self._step) for n in count())
+        if self._growing:
+            return takewhile(partial(gt, self._stop), values)
+        else:
+            return takewhile(partial(lt, self._stop), values)
+
+    def __len__(self):
+        return self._len
+
+    def _init_len(self):
+        if self._growing:
+            start = self._start
+            stop = self._stop
+            step = self._step
+        else:
+            start = self._stop
+            stop = self._start
+            step = -self._step
+        distance = stop - start
+        if distance <= self._zero:
+            self._len = 0
+        else:  # distance > 0 and step > 0: regular euclidean division
+            q, r = divmod(distance, step)
+            self._len = int(q) + int(r != self._zero)
+
+    def __reduce__(self):
+        return numeric_range, (self._start, self._stop, self._step)
+
+    def __repr__(self):
+        if self._step == 1:
+            return "numeric_range({}, {})".format(repr(self._start),
+                                                  repr(self._stop))
+        else:
+            return "numeric_range({}, {}, {})".format(repr(self._start),
+                                                      repr(self._stop),
+                                                      repr(self._step))
+
+    def __reversed__(self):
+        return iter(numeric_range(self._get_by_index(-1),
+                                  self._start - self._step, -self._step))
+
+    def count(self, value):
+        return int(value in self)
+
+    def index(self, value):
+        if self._growing:
+            if self._start <= value < self._stop:
+                q, r = divmod(value - self._start, self._step)
+                if r == self._zero:
+                    return int(q)
+        else:
+            if self._start >= value > self._stop:
+                q, r = divmod(self._start - value, -self._step)
+                if r == self._zero:
+                    return int(q)
+
+        raise ValueError("{} is not in numeric range".format(value))
+
+    def _get_by_index(self, i):
+        if i < 0:
+            i += self._len
+        if i < 0 or i >= self._len:
+            raise IndexError("numeric range object index out of range")
+        return self._start + i * self._step
 
 
 def count_cycle(iterable, n=None):
@@ -2121,9 +2261,6 @@
         >>> next(it), next(it), next(it)
         ('0', '1', '2')
 
-    The cache grows as the source iterable progresses, so beware of wrapping
-    very large or infinite iterables.
-
     You may view the contents of the cache with the :meth:`elements` method.
     That returns a :class:`SequenceView`, a view that updates automatically:
 
@@ -2138,11 +2275,30 @@
         >>> elements
         SequenceView(['0', '1', '2', '3'])
 
+    By default, the cache grows as the source iterable progresses, so beware of
+    wrapping very large or infinite iterables. Supply *maxlen* to limit the
+    size of the cache (this of course limits how far back you can seek).
+
+        >>> from itertools import count
+        >>> it = seekable((str(n) for n in count()), maxlen=2)
+        >>> next(it), next(it), next(it), next(it)
+        ('0', '1', '2', '3')
+        >>> list(it.elements())
+        ['2', '3']
+        >>> it.seek(0)
+        >>> next(it), next(it), next(it), next(it)
+        ('2', '3', '4', '5')
+        >>> next(it)
+        '6'
+
     """
 
-    def __init__(self, iterable):
+    def __init__(self, iterable, maxlen=None):
         self._source = iter(iterable)
-        self._cache = []
+        if maxlen is None:
+            self._cache = []
+        else:
+            self._cache = deque([], maxlen)
         self._index = None
 
     def __iter__(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/more-itertools-8.1.0/more_itertools.egg-info/PKG-INFO 
new/more-itertools-8.2.0/more_itertools.egg-info/PKG-INFO
--- old/more-itertools-8.1.0/more_itertools.egg-info/PKG-INFO   2020-01-11 
19:59:22.000000000 +0100
+++ new/more-itertools-8.2.0/more_itertools.egg-info/PKG-INFO   2020-01-29 
13:52:26.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.2
 Name: more-itertools
-Version: 8.1.0
+Version: 8.2.0
 Summary: More routines for operating on iterables, beyond itertools
 Home-page: https://github.com/erikrose/more-itertools
 Author: Erik Rose
@@ -182,6 +182,18 @@
         
            :noindex:
         
+        8.2.0
+        -----
+        
+        * Bug fixes
+            * The .pyi files for typing were updated. (thanks to blueyed and 
ilai-deutel)
+        
+        * Changes to existing itertools:
+            * numeric_range now behaves more like the built-in range. (thanks 
to jferard)
+            * bucket now allows for enumerating keys. (thanks to alexchandel)
+            * sliced now should now work for numpy arrays. (thanks to sswingle)
+            * seekable now has a ``maxlen`` parameter.
+        
         8.1.0
         -----
         
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/more-itertools-8.1.0/setup.cfg 
new/more-itertools-8.2.0/setup.cfg
--- old/more-itertools-8.1.0/setup.cfg  2020-01-11 19:59:22.000000000 +0100
+++ new/more-itertools-8.2.0/setup.cfg  2020-01-29 13:52:26.000000000 +0100
@@ -1,5 +1,5 @@
 [bumpversion]
-current_version = 8.1.0
+current_version = 8.2.0
 commit = True
 tag = False
 files = more_itertools/__init__.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/more-itertools-8.1.0/tests/test_more.py 
new/more-itertools-8.2.0/tests/test_more.py
--- old/more-itertools-8.1.0/tests/test_more.py 2020-01-11 19:59:09.000000000 
+0100
+++ new/more-itertools-8.2.0/tests/test_more.py 2020-01-29 13:49:15.000000000 
+0100
@@ -1,4 +1,4 @@
-from collections import OrderedDict, Counter
+from collections import OrderedDict, Counter, abc
 from collections.abc import Set
 from datetime import datetime, timedelta
 from decimal import Decimal
@@ -19,6 +19,7 @@
     repeat,
 )
 from operator import add, mul, itemgetter
+from pickle import loads, dumps
 from random import seed
 from statistics import mean
 from sys import version_info
@@ -821,8 +822,6 @@
 
 
 class BucketTests(TestCase):
-    """Tests for ``bucket()``"""
-
     def test_basic(self):
         iterable = [10, 20, 30, 11, 21, 31, 12, 22, 23, 33]
         D = mi.bucket(iterable, key=lambda x: 10 * (x // 10))
@@ -858,6 +857,24 @@
         self.assertNotIn(0, D._cache)  # Don't store non-valid entries
         self.assertEqual(list(D[0]), [])
 
+    def test_list(self):
+        iterable = [10, 20, 30, 11, 21, 31, 12, 22, 23, 33]
+        D = mi.bucket(iterable, key=lambda x: 10 * (x // 10))
+        self.assertEqual(list(D[10]), [10, 11, 12])
+        self.assertEqual(list(D[20]), [20, 21, 22, 23])
+        self.assertEqual(list(D[30]), [30, 31, 33])
+        self.assertEqual(set(D), {10, 20, 30})
+
+    def test_list_validator(self):
+        iterable = [10, 20, 30, 11, 21, 31, 12, 22, 23, 33]
+        key = lambda x: 10 * (x // 10)
+        validator = lambda x: x != 20
+        D = mi.bucket(iterable, key, validator=validator)
+        self.assertEqual(set(D), {10, 30})
+        self.assertEqual(list(D[10]), [10, 11, 12])
+        self.assertEqual(list(D[20]), [])
+        self.assertEqual(list(D[30]), [30, 31, 33])
+
 
 class SpyTests(TestCase):
     """Tests for ``spy()``"""
@@ -1059,6 +1076,26 @@
         with self.assertRaises(TypeError):
             list(mi.sliced(seq, 3))
 
+    def test_numpy_like_array(self):
+        # Numpy arrays don't behave like Python lists - calling bool()
+        # on them doesn't return False for empty lists and True for non-empty
+        # ones. Emulate that behavior.
+        class FalseList(list):
+            def __getitem__(self, key):
+                ret = super().__getitem__(key)
+                if isinstance(key, slice):
+                    return FalseList(ret)
+
+                return ret
+
+            def __bool__(self):
+                return False
+
+        seq = FalseList(range(9))
+        actual = list(mi.sliced(seq, 3))
+        expected = [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
+        self.assertEqual(actual, expected)
+
 
 class SplitAtTests(TestCase):
     """Tests for ``split()``"""
@@ -1724,6 +1761,12 @@
         str_expected = list(str_obj)
         self.assertEqual(str_actual, str_expected)
 
+        # base_type handles nested tuple (via isinstance).
+        base_type = ((dict,),)
+        custom_actual = list(mi.always_iterable(dict_obj, base_type=base_type))
+        custom_expected = [dict_obj]
+        self.assertEqual(custom_actual, custom_expected)
+
     def test_iterables(self):
         self.assertEqual(list(mi.always_iterable([0, 1])), [0, 1])
         self.assertEqual(
@@ -1948,7 +1991,7 @@
             ((4,), [0, 1, 2, 3]),
             ((4.0,), [0.0, 1.0, 2.0, 3.0]),
             ((1.0, 4), [1.0, 2.0, 3.0]),
-            ((1, 4.0), [1, 2, 3]),
+            ((1, 4.0), [1.0, 2.0, 3.0]),
             ((1.0, 5), [1.0, 2.0, 3.0, 4.0]),
             ((0, 20, 5), [0, 5, 10, 15]),
             ((0, 20, 5.0), [0.0, 5.0, 10.0, 15.0]),
@@ -1961,6 +2004,12 @@
             ((0.0,), []),
             ((1, 0), []),
             ((1.0, 0.0), []),
+            ((0.1, 0.30000000000000001, 0.2), [0.1]),   # IEE 754 !
+            ((Decimal("0.1"), Decimal("0.30000000000000001"), Decimal("0.2")),
+             [Decimal("0.1"), Decimal("0.3")]),         # okay with Decimal
+            ((Fraction(1, 10), Fraction(30000000000000001, 100000000000000000),
+              Fraction(2, 10)),
+             [Fraction(1, 10), Fraction(3, 10)]),       # okay with Fraction
             ((Fraction(2, 1),), [Fraction(0, 1), Fraction(1, 1)]),
             ((Decimal('2.0'),), [Decimal('0.0'), Decimal('1.0')]),
             (
@@ -1977,16 +2026,18 @@
             ),
         ]:
             actual = list(mi.numeric_range(*args))
-            self.assertEqual(actual, expected)
+            self.assertEqual(expected, actual)
             self.assertTrue(
                 all(type(a) == type(e) for a, e in zip(actual, expected))
             )
 
     def test_arg_count(self):
-        self.assertRaises(TypeError, lambda: list(mi.numeric_range()))
-        self.assertRaises(
-            TypeError, lambda: list(mi.numeric_range(0, 1, 2, 3))
-        )
+        for args, message in [
+            ((), 'numeric_range expected at least 1 argument, got 0'),
+            ((0, 1, 2, 3), 'numeric_range expected at most 3 arguments, got 4')
+        ]:
+            with self.assertRaisesRegex(TypeError, message):
+                mi.numeric_range(*args)
 
     def test_zero_step(self):
         for args in [
@@ -1996,10 +2047,322 @@
                 datetime(2019, 3, 29, 12, 37, 55),
                 timedelta(minutes=0),
             ),
+            (1.0, 2.0, 0.0),
+            (Decimal("1.0"), Decimal("2.0"), Decimal("0.0")),
+            (Fraction(2, 2), Fraction(4, 2), Fraction(0, 2)),
         ]:
             with self.assertRaises(ValueError):
                 list(mi.numeric_range(*args))
 
+    def test_bool(self):
+        for args, expected in [
+            ((1.0, 3.0, 1.5), True),
+            ((1.0, 2.0, 1.5), True),
+            ((1.0, 1.0, 1.5), False),
+            ((1.0, 0.0, 1.5), False),
+            ((3.0, 1.0, -1.5), True),
+            ((2.0, 1.0, -1.5), True),
+            ((1.0, 1.0, -1.5), False),
+            ((0.0, 1.0, -1.5), False),
+            ((Decimal("1.0"), Decimal("2.0"), Decimal("1.5")), True),
+            ((Decimal("1.0"), Decimal("0.0"), Decimal("1.5")), False),
+            ((Fraction(2, 2), Fraction(4, 2), Fraction(3, 2)), True),
+            ((Fraction(2, 2), Fraction(0, 2), Fraction(3, 2)), False),
+            ((datetime(2019, 3, 29), datetime(2019, 3, 30),
+              timedelta(hours=1)), True),
+            ((datetime(2019, 3, 29), datetime(2019, 3, 28),
+              timedelta(hours=1)), False),
+        ]:
+            self.assertEqual(expected, bool(mi.numeric_range(*args)))
+
+    def test_contains(self):
+        for args, expected_in, expected_not_in in [
+            ((10,), range(10), (0.5,)),
+            ((1.0, 9.9, 1.5), (1.0, 2.5, 4.0, 5.5, 7.0, 8.5), (0.9,)),
+            ((9.0, 1.0, -1.5), (1.5, 3.0, 4.5, 6.0, 7.5, 9.0), (0.0, 0.9)),
+            ((Decimal("1.0"), Decimal("9.9"), Decimal("1.5")),
+             (Decimal("1.0"), Decimal("2.5"), Decimal("4.0"), Decimal("5.5"),
+              Decimal("7.0"), Decimal("8.5"),),
+             (Decimal("0.9"),)),
+            ((Fraction(0, 1), Fraction(5, 1), Fraction(1, 2)),
+             (Fraction(0, 1), Fraction(1, 2), Fraction(9, 2)),
+             (Fraction(10, 2),)),
+            ((datetime(2019, 3, 29), datetime(2019, 3, 30),
+              timedelta(hours=1)),
+             (datetime(2019, 3, 29, 15),), (datetime(2019, 3, 29, 15, 30),))
+        ]:
+            r = mi.numeric_range(*args)
+            for v in expected_in:
+                self.assertTrue(v in r)
+                self.assertFalse(v not in r)
+
+            for v in expected_not_in:
+                self.assertFalse(v in r)
+                self.assertTrue(v not in r)
+
+    def test_eq(self):
+        for args1, args2 in [
+            ((0, 5, 2), (0, 6, 2)),
+            ((1.0, 9.9, 1.5), (1.0, 8.6, 1.5)),
+            ((8.5, 0.0, -1.5), (8.5, 0.7, -1.5)),
+            ((7.0, 0.0, 1.0), (17.0, 7.0, 0.5)),
+            ((Decimal("1.0"), Decimal("9.9"), Decimal("1.5")),
+             (Decimal("1.0"), Decimal("8.6"), Decimal("1.5"))),
+            ((Fraction(1, 1), Fraction(10, 1), Fraction(3, 2)),
+             (Fraction(1, 1), Fraction(9, 1), Fraction(3, 2))),
+            ((datetime(2019, 3, 29), datetime(2019, 3, 30),
+              timedelta(hours=10)),
+             (datetime(2019, 3, 29), datetime(2019, 3, 30, 1),
+              timedelta(hours=10)))
+        ]:
+            self.assertEqual(mi.numeric_range(*args1),
+                             mi.numeric_range(*args2))
+
+        for args1, args2 in [
+            ((0, 5, 2), (0, 7, 2)),
+            ((1.0, 9.9, 1.5), (1.2, 9.9, 1.5)),
+            ((1.0, 9.9, 1.5), (1.0, 10.3, 1.5)),
+            ((1.0, 9.9, 1.5), (1.0, 9.9, 1.4)),
+            ((8.5, 0.0, -1.5), (8.4, 0.0, -1.5)),
+            ((8.5, 0.0, -1.5), (8.5, -0.7, -1.5)),
+            ((8.5, 0.0, -1.5), (8.5, 0.0, -1.4)),
+            ((0.0, 7.0, 1.0), (7.0, 0.0, 1.0)),
+            ((Decimal("1.0"), Decimal("10.0"), Decimal("1.5")),
+             (Decimal("1.0"), Decimal("10.5"), Decimal("1.5"))),
+            ((Fraction(1, 1), Fraction(10, 1), Fraction(3, 2)),
+             (Fraction(1, 1), Fraction(21, 2), Fraction(3, 2))),
+            ((datetime(2019, 3, 29), datetime(2019, 3, 30),
+              timedelta(hours=10)),
+             (datetime(2019, 3, 29), datetime(2019, 3, 30, 15),
+              timedelta(hours=10)))
+        ]:
+            self.assertNotEqual(mi.numeric_range(*args1),
+                                mi.numeric_range(*args2))
+
+        self.assertNotEqual(mi.numeric_range(7.0), 1)
+        self.assertNotEqual(mi.numeric_range(7.0), "abc")
+
+    def test_get_item_by_index(self):
+        for args, index, expected in [
+            ((1, 6), 2, 3),
+            ((1.0, 6.0, 1.5), 0, 1.0),
+            ((1.0, 6.0, 1.5), 1, 2.5),
+            ((1.0, 6.0, 1.5), 2, 4.0),
+            ((1.0, 6.0, 1.5), 3, 5.5),
+            ((1.0, 6.0, 1.5), -1, 5.5),
+            ((1.0, 6.0, 1.5), -2, 4.0),
+            ((Decimal("1.0"), Decimal("9.0"), Decimal("1.5")),
+             -1, Decimal("8.5")),
+            ((Fraction(1, 1), Fraction(10, 1), Fraction(3, 2)),
+             2, Fraction(4, 1)),
+            ((datetime(2019, 3, 29), datetime(2019, 3, 30),
+              timedelta(hours=10)),
+             1, datetime(2019, 3, 29, 10))
+        ]:
+            self.assertEqual(expected, mi.numeric_range(*args)[index])
+
+        for args, index in [
+            ((1.0, 6.0, 1.5), 4),
+            ((1.0, 6.0, 1.5), -5),
+            ((6.0, 1.0, 1.5), 0),
+            ((6.0, 1.0, 1.5), -1),
+            ((Decimal("1.0"), Decimal("9.0"), Decimal("-1.5")), -1),
+            ((Fraction(1, 1), Fraction(2, 1), Fraction(3, 2)), 2),
+            ((datetime(2019, 3, 29), datetime(2019, 3, 30),
+              timedelta(hours=10)), 8)
+        ]:
+            with self.assertRaises(IndexError):
+                mi.numeric_range(*args)[index]
+
+    def test_get_item_by_slice(self):
+        for args, sl, expected_args in [
+            ((1.0, 9.0, 1.5), slice(None, None, None), (1.0, 9.0, 1.5)),
+            ((1.0, 9.0, 1.5), slice(None, 1, None), (1.0, 2.5, 1.5)),
+            ((1.0, 9.0, 1.5), slice(None, None, 2), (1.0, 9.0, 3.0)),
+            ((1.0, 9.0, 1.5), slice(None, 2, None), (1.0, 4.0, 1.5)),
+            ((1.0, 9.0, 1.5), slice(1, 2, None), (2.5, 4.0, 1.5)),
+            ((1.0, 9.0, 1.5), slice(1, -1, None), (2.5, 8.5, 1.5)),
+            ((1.0, 9.0, 1.5), slice(10, None, 3), (9.0, 9.0, 4.5)),
+            ((1.0, 9.0, 1.5), slice(-10, None, 3), (1.0, 9.0, 4.5)),
+            ((1.0, 9.0, 1.5), slice(None, -10, 3), (1.0, 1.0, 4.5)),
+            ((1.0, 9.0, 1.5), slice(None, 10, 3), (1.0, 9.0, 4.5)),
+            ((Decimal("1.0"), Decimal("9.0"), Decimal("1.5")),
+             slice(1, -1, None),
+             (Decimal("2.5"), Decimal("8.5"), Decimal("1.5"))),
+            ((Fraction(1, 1), Fraction(5, 1), Fraction(3, 2)),
+             slice(1, -1, None),
+             (Fraction(5, 2), Fraction(4, 1), Fraction(3, 2))),
+            ((datetime(2019, 3, 29), datetime(2019, 3, 30),
+              timedelta(hours=10)),
+             slice(1, -1, None),
+             (datetime(2019, 3, 29, 10), datetime(2019, 3, 29, 20),
+              timedelta(hours=10)))
+        ]:
+            self.assertEqual(mi.numeric_range(*expected_args),
+                             mi.numeric_range(*args)[sl])
+
+    def test_hash(self):
+        for args, expected in [
+            ((1.0, 6.0, 1.5), hash((1.0, 5.5, 1.5))),
+            ((1.0, 7.0, 1.5), hash((1.0, 5.5, 1.5))),
+            ((1.0, 7.5, 1.5), hash((1.0, 7.0, 1.5))),
+            ((1.0, 1.5, 1.5), hash((1.0, 1.0, 1.5))),
+            ((1.5, 1.0, 1.5), hash(range(0, 0))),
+            ((1.5, 1.5, 1.5), hash(range(0, 0))),
+            ((Decimal("1.0"), Decimal("9.0"), Decimal("1.5")),
+             hash((Decimal("1.0"), Decimal("8.5"), Decimal("1.5")))),
+            ((Fraction(1, 1), Fraction(5, 1), Fraction(3, 2)),
+             hash((Fraction(1, 1), Fraction(4, 1), Fraction(3, 2)))),
+            ((datetime(2019, 3, 29), datetime(2019, 3, 30),
+              timedelta(hours=10)),
+             hash((datetime(2019, 3, 29), datetime(2019, 3, 29, 20),
+                   timedelta(hours=10))))
+
+        ]:
+            self.assertEqual(expected, hash(mi.numeric_range(*args)))
+
+    def test_iter_twice(self):
+        r1 = mi.numeric_range(1.0, 9.9, 1.5)
+        r2 = mi.numeric_range(8.5, 0.0, -1.5)
+        self.assertEqual([1.0, 2.5, 4.0, 5.5, 7.0, 8.5], list(r1))
+        self.assertEqual([1.0, 2.5, 4.0, 5.5, 7.0, 8.5], list(r1))
+        self.assertEqual([8.5, 7.0, 5.5, 4.0, 2.5, 1.0], list(r2))
+        self.assertEqual([8.5, 7.0, 5.5, 4.0, 2.5, 1.0], list(r2))
+
+    def test_len(self):
+        for args, expected in [
+            ((1.0, 7.0, 1.5), 4),
+            ((1.0, 7.01, 1.5), 5),
+            ((7.0, 1.0, -1.5), 4),
+            ((7.01, 1.0, -1.5), 5),
+            ((0.1, 0.30000000000000001, 0.2), 1),  # IEE 754 !
+            ((Decimal("0.1"), Decimal("0.30000000000000001"),
+              Decimal("0.2")), 2),  # works with Decimal
+            ((Decimal("1.0"), Decimal("9.0"), Decimal("1.5")), 6),
+            ((Fraction(1, 1), Fraction(5, 1), Fraction(3, 2)), 3),
+            ((datetime(2019, 3, 29), datetime(2019, 3, 30),
+              timedelta(hours=10)), 3)
+        ]:
+            self.assertEqual(expected, len(mi.numeric_range(*args)))
+
+    def test_repr(self):
+        for args, *expected in [
+            ((7.0,), "numeric_range(0.0, 7.0)"),
+            ((1.0, 7.0), "numeric_range(1.0, 7.0)"),
+            ((7.0, 1.0, -1.5), "numeric_range(7.0, 1.0, -1.5)"),
+            ((Decimal("1.0"), Decimal("9.0"), Decimal("1.5")),
+             "numeric_range(Decimal('1.0'), Decimal('9.0'), Decimal('1.5'))"),
+            ((Fraction(7, 7), Fraction(10, 2), Fraction(3, 2)),
+             "numeric_range(Fraction(1, 1), Fraction(5, 1), Fraction(3, 2))"),
+            ((datetime(2019, 3, 29), datetime(2019, 3, 30),
+              timedelta(hours=10)),
+             "numeric_range(datetime.datetime(2019, 3, 29, 0, 0), "
+             "datetime.datetime(2019, 3, 30, 0, 0), "
+             "datetime.timedelta(seconds=36000))",
+             "numeric_range(datetime.datetime(2019, 3, 29, 0, 0), "
+             "datetime.datetime(2019, 3, 30, 0, 0), "
+             "datetime.timedelta(0, 36000))")
+        ]:
+            self.assertIn(repr(mi.numeric_range(*args)), expected)
+
+    def test_reversed(self):
+        for args, expected in [
+            ((7.0,), [6.0, 5.0, 4.0, 3.0, 2.0, 1.0, 0.0]),
+            ((1.0, 7.0), [6.0, 5.0, 4.0, 3.0, 2.0, 1.0]),
+            ((7.0, 1.0, -1.5), [2.5, 4.0, 5.5, 7.0]),
+            ((7.0, 0.9, -1.5), [1.0, 2.5, 4.0, 5.5, 7.0]),
+            ((Decimal("1.0"), Decimal("5.0"), Decimal("1.5")),
+             [Decimal('4.0'), Decimal('2.5'), Decimal('1.0')]),
+            ((Fraction(1, 1), Fraction(5, 1), Fraction(3, 2)),
+             [Fraction(4, 1), Fraction(5, 2), Fraction(1, 1)]),
+            ((datetime(2019, 3, 29), datetime(2019, 3, 30),
+              timedelta(hours=10)), [datetime(2019, 3, 29, 20),
+             datetime(2019, 3, 29, 10), datetime(2019, 3, 29)]),
+        ]:
+            self.assertEqual(expected, list(reversed(mi.numeric_range(*args))))
+
+    def test_count(self):
+        for args, v, c in [
+            ((7.0,), 0.0, 1),
+            ((7.0,), 0.5, 0),
+            ((7.0,), 6.0, 1),
+            ((7.0,), 7.0, 0),
+            ((7.0,), 10.0, 0),
+            ((Decimal("1.0"), Decimal("5.0"), Decimal("1.5")),
+             Decimal('4.0'), 1),
+            ((Fraction(1, 1), Fraction(5, 1), Fraction(3, 2)),
+             Fraction(5, 2), 1),
+            ((datetime(2019, 3, 29), datetime(2019, 3, 30),
+              timedelta(hours=10)), datetime(2019, 3, 29, 20), 1),
+        ]:
+            self.assertEqual(c, mi.numeric_range(*args).count(v))
+
+    def test_index(self):
+        for args, v, i in [
+            ((7.0,), 0.0, 0),
+            ((7.0,), 6.0, 6),
+            ((7.0, 0.0, -1.0), 7.0, 0),
+            ((7.0, 0.0, -1.0), 1.0, 6),
+            ((Decimal("1.0"), Decimal("5.0"), Decimal("1.5")),
+             Decimal('4.0'), 2),
+            ((Fraction(1, 1), Fraction(5, 1), Fraction(3, 2)),
+             Fraction(5, 2), 1),
+            ((datetime(2019, 3, 29), datetime(2019, 3, 30),
+              timedelta(hours=10)), datetime(2019, 3, 29, 20), 2),
+        ]:
+            self.assertEqual(i, mi.numeric_range(*args).index(v))
+
+        for args, v in [
+            ((0.7,), 0.5),
+            ((0.7,), 7.0),
+            ((0.7,), 10.0),
+            ((7.0, 0.0, -1.0), 0.5),
+            ((7.0, 0.0, -1.0), 0.0),
+            ((7.0, 0.0, -1.0), 10.0),
+            ((7.0, 0.0), 5.0),
+            ((Decimal("1.0"), Decimal("5.0"), Decimal("1.5")),
+             Decimal('4.5')),
+            ((Fraction(1, 1), Fraction(5, 1), Fraction(3, 2)),
+             Fraction(5, 3)),
+            ((datetime(2019, 3, 29), datetime(2019, 3, 30),
+              timedelta(hours=10)), datetime(2019, 3, 30)),
+        ]:
+            with self.assertRaises(ValueError):
+                mi.numeric_range(*args).index(v)
+
+    def test_parent_classes(self):
+        r = mi.numeric_range(7.0)
+        self.assertTrue(isinstance(r, abc.Iterable))
+        self.assertFalse(isinstance(r, abc.Iterator))
+        self.assertTrue(isinstance(r, abc.Sequence))
+        self.assertTrue(isinstance(r, abc.Hashable))
+
+    def test_bad_key(self):
+        r = mi.numeric_range(7.0)
+        for arg, message in [
+            ('a', 'numeric range indices must be integers or slices, not str'),
+            ((),
+             'numeric range indices must be integers or slices, not tuple'),
+        ]:
+            with self.assertRaisesRegex(TypeError, message):
+                r[arg]
+
+    def test_pickle(self):
+        for args in [
+            (7.0,),
+            (5.0, 7.0),
+            (5.0, 7.0, 3.0),
+            (7.0, 5.0),
+            (7.0, 5.0, 4.0),
+            (7.0, 5.0, -1.0),
+            (Decimal("1.0"), Decimal("5.0"), Decimal("1.5")),
+            (Fraction(1, 1), Fraction(5, 1), Fraction(3, 2)),
+            (datetime(2019, 3, 29), datetime(2019, 3, 30)),
+        ]:
+            r = mi.numeric_range(*args)
+            self.assertTrue(dumps(r))  # assert not empty
+            self.assertEqual(r, loads(dumps(r)))
+
 
 class CountCycleTests(TestCase):
     def test_basic(self):
@@ -2244,6 +2607,23 @@
         mi.take(10, s)
         self.assertEqual(list(elements), [str(n) for n in range(20)])
 
+    def test_maxlen(self):
+        iterable = map(str, count())
+
+        s = mi.seekable(iterable, maxlen=4)
+        self.assertEqual(mi.take(10, s), [str(n) for n in range(10)])
+        self.assertEqual(list(s.elements()), ['6', '7', '8', '9'])
+
+        s.seek(0)
+        self.assertEqual(mi.take(14, s), [str(n) for n in range(6, 20)])
+        self.assertEqual(list(s.elements()), ['16', '17', '18', '19'])
+
+    def test_maxlen_zero(self):
+        iterable = [str(x) for x in range(5)]
+        s = mi.seekable(iterable, maxlen=0)
+        self.assertEqual(list(s), iterable)
+        self.assertEqual(list(s.elements()), [])
+
 
 class SequenceViewTests(TestCase):
     def test_init(self):


Reply via email to