(root)/
Python-3.12.0/
Lib/
test/
test_slice.py
       1  # tests for slice objects; in particular the indices method.
       2  
       3  import itertools
       4  import operator
       5  import sys
       6  import unittest
       7  import weakref
       8  import copy
       9  
      10  from pickle import loads, dumps
      11  from test import support
      12  
      13  
      14  def evaluate_slice_index(arg):
      15      """
      16      Helper function to convert a slice argument to an integer, and raise
      17      TypeError with a suitable message on failure.
      18  
      19      """
      20      if hasattr(arg, '__index__'):
      21          return operator.index(arg)
      22      else:
      23          raise TypeError(
      24              "slice indices must be integers or "
      25              "None or have an __index__ method")
      26  
      27  def slice_indices(slice, length):
      28      """
      29      Reference implementation for the slice.indices method.
      30  
      31      """
      32      # Compute step and length as integers.
      33      length = operator.index(length)
      34      step = 1 if slice.step is None else evaluate_slice_index(slice.step)
      35  
      36      # Raise ValueError for negative length or zero step.
      37      if length < 0:
      38          raise ValueError("length should not be negative")
      39      if step == 0:
      40          raise ValueError("slice step cannot be zero")
      41  
      42      # Find lower and upper bounds for start and stop.
      43      lower = -1 if step < 0 else 0
      44      upper = length - 1 if step < 0 else length
      45  
      46      # Compute start.
      47      if slice.start is None:
      48          start = upper if step < 0 else lower
      49      else:
      50          start = evaluate_slice_index(slice.start)
      51          start = max(start + length, lower) if start < 0 else min(start, upper)
      52  
      53      # Compute stop.
      54      if slice.stop is None:
      55          stop = lower if step < 0 else upper
      56      else:
      57          stop = evaluate_slice_index(slice.stop)
      58          stop = max(stop + length, lower) if stop < 0 else min(stop, upper)
      59  
      60      return start, stop, step
      61  
      62  
      63  # Class providing an __index__ method.  Used for testing slice.indices.
      64  
      65  class ESC[4;38;5;81mMyIndexable(ESC[4;38;5;149mobject):
      66      def __init__(self, value):
      67          self.value = value
      68  
      69      def __index__(self):
      70          return self.value
      71  
      72  
      73  class ESC[4;38;5;81mSliceTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
      74  
      75      def test_constructor(self):
      76          self.assertRaises(TypeError, slice)
      77          self.assertRaises(TypeError, slice, 1, 2, 3, 4)
      78  
      79      def test_repr(self):
      80          self.assertEqual(repr(slice(1, 2, 3)), "slice(1, 2, 3)")
      81  
      82      def test_hash(self):
      83          self.assertEqual(hash(slice(5)), slice(5).__hash__())
      84          self.assertEqual(hash(slice(1, 2)), slice(1, 2).__hash__())
      85          self.assertEqual(hash(slice(1, 2, 3)), slice(1, 2, 3).__hash__())
      86          self.assertNotEqual(slice(5), slice(6))
      87  
      88          with self.assertRaises(TypeError):
      89              hash(slice(1, 2, []))
      90  
      91          with self.assertRaises(TypeError):
      92              hash(slice(4, {}))
      93  
      94      def test_cmp(self):
      95          s1 = slice(1, 2, 3)
      96          s2 = slice(1, 2, 3)
      97          s3 = slice(1, 2, 4)
      98          self.assertEqual(s1, s2)
      99          self.assertNotEqual(s1, s3)
     100          self.assertNotEqual(s1, None)
     101          self.assertNotEqual(s1, (1, 2, 3))
     102          self.assertNotEqual(s1, "")
     103  
     104          class ESC[4;38;5;81mExc(ESC[4;38;5;149mException):
     105              pass
     106  
     107          class ESC[4;38;5;81mBadCmp(ESC[4;38;5;149mobject):
     108              def __eq__(self, other):
     109                  raise Exc
     110  
     111          s1 = slice(BadCmp())
     112          s2 = slice(BadCmp())
     113          self.assertEqual(s1, s1)
     114          self.assertRaises(Exc, lambda: s1 == s2)
     115  
     116          s1 = slice(1, BadCmp())
     117          s2 = slice(1, BadCmp())
     118          self.assertEqual(s1, s1)
     119          self.assertRaises(Exc, lambda: s1 == s2)
     120  
     121          s1 = slice(1, 2, BadCmp())
     122          s2 = slice(1, 2, BadCmp())
     123          self.assertEqual(s1, s1)
     124          self.assertRaises(Exc, lambda: s1 == s2)
     125  
     126      def test_members(self):
     127          s = slice(1)
     128          self.assertEqual(s.start, None)
     129          self.assertEqual(s.stop, 1)
     130          self.assertEqual(s.step, None)
     131  
     132          s = slice(1, 2)
     133          self.assertEqual(s.start, 1)
     134          self.assertEqual(s.stop, 2)
     135          self.assertEqual(s.step, None)
     136  
     137          s = slice(1, 2, 3)
     138          self.assertEqual(s.start, 1)
     139          self.assertEqual(s.stop, 2)
     140          self.assertEqual(s.step, 3)
     141  
     142          class ESC[4;38;5;81mAnyClass:
     143              pass
     144  
     145          obj = AnyClass()
     146          s = slice(obj)
     147          self.assertTrue(s.stop is obj)
     148  
     149      def check_indices(self, slice, length):
     150          try:
     151              actual = slice.indices(length)
     152          except ValueError:
     153              actual = "valueerror"
     154          try:
     155              expected = slice_indices(slice, length)
     156          except ValueError:
     157              expected = "valueerror"
     158          self.assertEqual(actual, expected)
     159  
     160          if length >= 0 and slice.step != 0:
     161              actual = range(*slice.indices(length))
     162              expected = range(length)[slice]
     163              self.assertEqual(actual, expected)
     164  
     165      def test_indices(self):
     166          self.assertEqual(slice(None           ).indices(10), (0, 10,  1))
     167          self.assertEqual(slice(None,  None,  2).indices(10), (0, 10,  2))
     168          self.assertEqual(slice(1,     None,  2).indices(10), (1, 10,  2))
     169          self.assertEqual(slice(None,  None, -1).indices(10), (9, -1, -1))
     170          self.assertEqual(slice(None,  None, -2).indices(10), (9, -1, -2))
     171          self.assertEqual(slice(3,     None, -2).indices(10), (3, -1, -2))
     172          # issue 3004 tests
     173          self.assertEqual(slice(None, -9).indices(10), (0, 1, 1))
     174          self.assertEqual(slice(None, -10).indices(10), (0, 0, 1))
     175          self.assertEqual(slice(None, -11).indices(10), (0, 0, 1))
     176          self.assertEqual(slice(None, -10, -1).indices(10), (9, 0, -1))
     177          self.assertEqual(slice(None, -11, -1).indices(10), (9, -1, -1))
     178          self.assertEqual(slice(None, -12, -1).indices(10), (9, -1, -1))
     179          self.assertEqual(slice(None, 9).indices(10), (0, 9, 1))
     180          self.assertEqual(slice(None, 10).indices(10), (0, 10, 1))
     181          self.assertEqual(slice(None, 11).indices(10), (0, 10, 1))
     182          self.assertEqual(slice(None, 8, -1).indices(10), (9, 8, -1))
     183          self.assertEqual(slice(None, 9, -1).indices(10), (9, 9, -1))
     184          self.assertEqual(slice(None, 10, -1).indices(10), (9, 9, -1))
     185  
     186          self.assertEqual(
     187              slice(-100,  100     ).indices(10),
     188              slice(None).indices(10)
     189          )
     190          self.assertEqual(
     191              slice(100,  -100,  -1).indices(10),
     192              slice(None, None, -1).indices(10)
     193          )
     194          self.assertEqual(slice(-100, 100, 2).indices(10), (0, 10,  2))
     195  
     196          self.assertEqual(list(range(10))[::sys.maxsize - 1], [0])
     197  
     198          # Check a variety of start, stop, step and length values, including
     199          # values exceeding sys.maxsize (see issue #14794).
     200          vals = [None, -2**100, -2**30, -53, -7, -1, 0, 1, 7, 53, 2**30, 2**100]
     201          lengths = [0, 1, 7, 53, 2**30, 2**100]
     202          for slice_args in itertools.product(vals, repeat=3):
     203              s = slice(*slice_args)
     204              for length in lengths:
     205                  self.check_indices(s, length)
     206          self.check_indices(slice(0, 10, 1), -3)
     207  
     208          # Negative length should raise ValueError
     209          with self.assertRaises(ValueError):
     210              slice(None).indices(-1)
     211  
     212          # Zero step should raise ValueError
     213          with self.assertRaises(ValueError):
     214              slice(0, 10, 0).indices(5)
     215  
     216          # Using a start, stop or step or length that can't be interpreted as an
     217          # integer should give a TypeError ...
     218          with self.assertRaises(TypeError):
     219              slice(0.0, 10, 1).indices(5)
     220          with self.assertRaises(TypeError):
     221              slice(0, 10.0, 1).indices(5)
     222          with self.assertRaises(TypeError):
     223              slice(0, 10, 1.0).indices(5)
     224          with self.assertRaises(TypeError):
     225              slice(0, 10, 1).indices(5.0)
     226  
     227          # ... but it should be fine to use a custom class that provides index.
     228          self.assertEqual(slice(0, 10, 1).indices(5), (0, 5, 1))
     229          self.assertEqual(slice(MyIndexable(0), 10, 1).indices(5), (0, 5, 1))
     230          self.assertEqual(slice(0, MyIndexable(10), 1).indices(5), (0, 5, 1))
     231          self.assertEqual(slice(0, 10, MyIndexable(1)).indices(5), (0, 5, 1))
     232          self.assertEqual(slice(0, 10, 1).indices(MyIndexable(5)), (0, 5, 1))
     233  
     234      def test_setslice_without_getslice(self):
     235          tmp = []
     236          class ESC[4;38;5;81mX(ESC[4;38;5;149mobject):
     237              def __setitem__(self, i, k):
     238                  tmp.append((i, k))
     239  
     240          x = X()
     241          x[1:2] = 42
     242          self.assertEqual(tmp, [(slice(1, 2), 42)])
     243  
     244      def test_pickle(self):
     245          import pickle
     246  
     247          s = slice(10, 20, 3)
     248          for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
     249              t = loads(dumps(s, protocol))
     250              self.assertEqual(s, t)
     251              self.assertEqual(s.indices(15), t.indices(15))
     252              self.assertNotEqual(id(s), id(t))
     253  
     254      def test_copy(self):
     255          s = slice(1, 10)
     256          c = copy.copy(s)
     257          self.assertIs(s, c)
     258  
     259          s = slice(1, 10, 2)
     260          c = copy.copy(s)
     261          self.assertIs(s, c)
     262  
     263          # Corner case for mutable indices:
     264          s = slice([1, 2], [3, 4], [5, 6])
     265          c = copy.copy(s)
     266          self.assertIs(s, c)
     267          self.assertIs(s.start, c.start)
     268          self.assertIs(s.stop, c.stop)
     269          self.assertIs(s.step, c.step)
     270  
     271      def test_deepcopy(self):
     272          s = slice(1, 10)
     273          c = copy.deepcopy(s)
     274          self.assertEqual(s, c)
     275  
     276          s = slice(1, 10, 2)
     277          c = copy.deepcopy(s)
     278          self.assertEqual(s, c)
     279  
     280          # Corner case for mutable indices:
     281          s = slice([1, 2], [3, 4], [5, 6])
     282          c = copy.deepcopy(s)
     283          self.assertIsNot(s, c)
     284          self.assertEqual(s, c)
     285          self.assertIsNot(s.start, c.start)
     286          self.assertIsNot(s.stop, c.stop)
     287          self.assertIsNot(s.step, c.step)
     288  
     289      def test_cycle(self):
     290          class ESC[4;38;5;81mmyobj(): pass
     291          o = myobj()
     292          o.s = slice(o)
     293          w = weakref.ref(o)
     294          o = None
     295          support.gc_collect()
     296          self.assertIsNone(w())
     297  
     298  if __name__ == "__main__":
     299      unittest.main()