tests for slice objects in particular the indices method helper function to convert a slice argument to an integer and raise typeerror with a suitable message on failure reference implementation for the slice indices method compute step and length as integers raise valueerror for negative length or zero step find lower and upper bounds for start and stop compute start compute stop class providing an index method used for testing slice indices issue 3004 tests check a variety of start stop step and length values including values exceeding sys maxsize see issue 14794 negative length should raise valueerror zero step should raise valueerror using a start stop or step or length that can t be interpreted as an integer should give a typeerror but it should be fine to use a custom class that provides index corner case for mutable indices corner case for mutable indices tests for slice objects in particular the indices method helper function to convert a slice argument to an integer and raise typeerror with a suitable message on failure reference implementation for the slice indices method compute step and length as integers raise valueerror for negative length or zero step find lower and upper bounds for start and stop compute start compute stop class providing an __index__ method used for testing slice indices issue 3004 tests check a variety of start stop step and length values including values exceeding sys maxsize see issue 14794 negative length should raise valueerror zero step should raise valueerror using a start stop or step or length that can t be interpreted as an integer should give a typeerror but it should be fine to use a custom class that provides index corner case for mutable indices corner case for mutable indices
import itertools
import operator
import sys
import unittest
import weakref
import copy

from pickle import loads, dumps
from test import support


def evaluate_slice_index(arg):
    
    if hasattr(arg, '__index__'):
        return operator.index(arg)
    else:
        raise TypeError(
            "slice indices must be integers or "
            "None or have an __index__ method")

def slice_indices(slice, length):
    
    
    length = operator.index(length)
    step = 1 if slice.step is None else evaluate_slice_index(slice.step)

    
    if length < 0:
        raise ValueError("length should not be negative")
    if step == 0:
        raise ValueError("slice step cannot be zero")

    
    lower = -1 if step < 0 else 0
    upper = length - 1 if step < 0 else length

    
    if slice.start is None:
        start = upper if step < 0 else lower
    else:
        start = evaluate_slice_index(slice.start)
        start = max(start + length, lower) if start < 0 else min(start, upper)

    
    if slice.stop is None:
        stop = lower if step < 0 else upper
    else:
        stop = evaluate_slice_index(slice.stop)
        stop = max(stop + length, lower) if stop < 0 else min(stop, upper)

    return start, stop, step




class MyIndexable(object):
    def __init__(self, value):
        self.value = value

    def __index__(self):
        return self.value


class SliceTest(unittest.TestCase):

    def test_constructor(self):
        self.assertRaises(TypeError, slice)
        self.assertRaises(TypeError, slice, 1, 2, 3, 4)

    def test_repr(self):
        self.assertEqual(repr(slice(1, 2, 3)), "slice(1, 2, 3)")

    def test_hash(self):
        self.assertEqual(hash(slice(5)), slice(5).__hash__())
        self.assertEqual(hash(slice(1, 2)), slice(1, 2).__hash__())
        self.assertEqual(hash(slice(1, 2, 3)), slice(1, 2, 3).__hash__())
        self.assertNotEqual(slice(5), slice(6))

        with self.assertRaises(TypeError):
            hash(slice(1, 2, []))

        with self.assertRaises(TypeError):
            hash(slice(4, {}))

    def test_cmp(self):
        s1 = slice(1, 2, 3)
        s2 = slice(1, 2, 3)
        s3 = slice(1, 2, 4)
        self.assertEqual(s1, s2)
        self.assertNotEqual(s1, s3)
        self.assertNotEqual(s1, None)
        self.assertNotEqual(s1, (1, 2, 3))
        self.assertNotEqual(s1, "")

        class Exc(Exception):
            pass

        class BadCmp(object):
            def __eq__(self, other):
                raise Exc

        s1 = slice(BadCmp())
        s2 = slice(BadCmp())
        self.assertEqual(s1, s1)
        self.assertRaises(Exc, lambda: s1 == s2)

        s1 = slice(1, BadCmp())
        s2 = slice(1, BadCmp())
        self.assertEqual(s1, s1)
        self.assertRaises(Exc, lambda: s1 == s2)

        s1 = slice(1, 2, BadCmp())
        s2 = slice(1, 2, BadCmp())
        self.assertEqual(s1, s1)
        self.assertRaises(Exc, lambda: s1 == s2)

    def test_members(self):
        s = slice(1)
        self.assertEqual(s.start, None)
        self.assertEqual(s.stop, 1)
        self.assertEqual(s.step, None)

        s = slice(1, 2)
        self.assertEqual(s.start, 1)
        self.assertEqual(s.stop, 2)
        self.assertEqual(s.step, None)

        s = slice(1, 2, 3)
        self.assertEqual(s.start, 1)
        self.assertEqual(s.stop, 2)
        self.assertEqual(s.step, 3)

        class AnyClass:
            pass

        obj = AnyClass()
        s = slice(obj)
        self.assertTrue(s.stop is obj)

    def check_indices(self, slice, length):
        try:
            actual = slice.indices(length)
        except ValueError:
            actual = "valueerror"
        try:
            expected = slice_indices(slice, length)
        except ValueError:
            expected = "valueerror"
        self.assertEqual(actual, expected)

        if length >= 0 and slice.step != 0:
            actual = range(*slice.indices(length))
            expected = range(length)[slice]
            self.assertEqual(actual, expected)

    def test_indices(self):
        self.assertEqual(slice(None           ).indices(10), (0, 10,  1))
        self.assertEqual(slice(None,  None,  2).indices(10), (0, 10,  2))
        self.assertEqual(slice(1,     None,  2).indices(10), (1, 10,  2))
        self.assertEqual(slice(None,  None, -1).indices(10), (9, -1, -1))
        self.assertEqual(slice(None,  None, -2).indices(10), (9, -1, -2))
        self.assertEqual(slice(3,     None, -2).indices(10), (3, -1, -2))
        
        self.assertEqual(slice(None, -9).indices(10), (0, 1, 1))
        self.assertEqual(slice(None, -10).indices(10), (0, 0, 1))
        self.assertEqual(slice(None, -11).indices(10), (0, 0, 1))
        self.assertEqual(slice(None, -10, -1).indices(10), (9, 0, -1))
        self.assertEqual(slice(None, -11, -1).indices(10), (9, -1, -1))
        self.assertEqual(slice(None, -12, -1).indices(10), (9, -1, -1))
        self.assertEqual(slice(None, 9).indices(10), (0, 9, 1))
        self.assertEqual(slice(None, 10).indices(10), (0, 10, 1))
        self.assertEqual(slice(None, 11).indices(10), (0, 10, 1))
        self.assertEqual(slice(None, 8, -1).indices(10), (9, 8, -1))
        self.assertEqual(slice(None, 9, -1).indices(10), (9, 9, -1))
        self.assertEqual(slice(None, 10, -1).indices(10), (9, 9, -1))

        self.assertEqual(
            slice(-100,  100     ).indices(10),
            slice(None).indices(10)
        )
        self.assertEqual(
            slice(100,  -100,  -1).indices(10),
            slice(None, None, -1).indices(10)
        )
        self.assertEqual(slice(-100, 100, 2).indices(10), (0, 10,  2))

        self.assertEqual(list(range(10))[::sys.maxsize - 1], [0])

        
        
        vals = [None, -2**100, -2**30, -53, -7, -1, 0, 1, 7, 53, 2**30, 2**100]
        lengths = [0, 1, 7, 53, 2**30, 2**100]
        for slice_args in itertools.product(vals, repeat=3):
            s = slice(*slice_args)
            for length in lengths:
                self.check_indices(s, length)
        self.check_indices(slice(0, 10, 1), -3)

        
        with self.assertRaises(ValueError):
            slice(None).indices(-1)

        
        with self.assertRaises(ValueError):
            slice(0, 10, 0).indices(5)

        
        
        with self.assertRaises(TypeError):
            slice(0.0, 10, 1).indices(5)
        with self.assertRaises(TypeError):
            slice(0, 10.0, 1).indices(5)
        with self.assertRaises(TypeError):
            slice(0, 10, 1.0).indices(5)
        with self.assertRaises(TypeError):
            slice(0, 10, 1).indices(5.0)

        
        self.assertEqual(slice(0, 10, 1).indices(5), (0, 5, 1))
        self.assertEqual(slice(MyIndexable(0), 10, 1).indices(5), (0, 5, 1))
        self.assertEqual(slice(0, MyIndexable(10), 1).indices(5), (0, 5, 1))
        self.assertEqual(slice(0, 10, MyIndexable(1)).indices(5), (0, 5, 1))
        self.assertEqual(slice(0, 10, 1).indices(MyIndexable(5)), (0, 5, 1))

    def test_setslice_without_getslice(self):
        tmp = []
        class X(object):
            def __setitem__(self, i, k):
                tmp.append((i, k))

        x = X()
        x[1:2] = 42
        self.assertEqual(tmp, [(slice(1, 2), 42)])

    def test_pickle(self):
        import pickle

        s = slice(10, 20, 3)
        for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
            t = loads(dumps(s, protocol))
            self.assertEqual(s, t)
            self.assertEqual(s.indices(15), t.indices(15))
            self.assertNotEqual(id(s), id(t))

    def test_copy(self):
        s = slice(1, 10)
        c = copy.copy(s)
        self.assertIs(s, c)

        s = slice(1, 10, 2)
        c = copy.copy(s)
        self.assertIs(s, c)

        
        s = slice([1, 2], [3, 4], [5, 6])
        c = copy.copy(s)
        self.assertIs(s, c)
        self.assertIs(s.start, c.start)
        self.assertIs(s.stop, c.stop)
        self.assertIs(s.step, c.step)

    def test_deepcopy(self):
        s = slice(1, 10)
        c = copy.deepcopy(s)
        self.assertEqual(s, c)

        s = slice(1, 10, 2)
        c = copy.deepcopy(s)
        self.assertEqual(s, c)

        
        s = slice([1, 2], [3, 4], [5, 6])
        c = copy.deepcopy(s)
        self.assertIsNot(s, c)
        self.assertEqual(s, c)
        self.assertIsNot(s.start, c.start)
        self.assertIsNot(s.stop, c.stop)
        self.assertIsNot(s.step, c.step)

    def test_cycle(self):
        class myobj(): pass
        o = myobj()
        o.s = slice(o)
        w = weakref.ref(o)
        o = None
        support.gc_collect()
        self.assertIsNone(w())

if __name__ == "__main__":
    unittest.main()