python (3.11.7)

(root)/
lib/
python3.11/
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          # Verify clearing of SF bug #800796
      84          self.assertRaises(TypeError, hash, slice(5))
      85          with self.assertRaises(TypeError):
      86              slice(5).__hash__()
      87  
      88      def test_cmp(self):
      89          s1 = slice(1, 2, 3)
      90          s2 = slice(1, 2, 3)
      91          s3 = slice(1, 2, 4)
      92          self.assertEqual(s1, s2)
      93          self.assertNotEqual(s1, s3)
      94          self.assertNotEqual(s1, None)
      95          self.assertNotEqual(s1, (1, 2, 3))
      96          self.assertNotEqual(s1, "")
      97  
      98          class ESC[4;38;5;81mExc(ESC[4;38;5;149mException):
      99              pass
     100  
     101          class ESC[4;38;5;81mBadCmp(ESC[4;38;5;149mobject):
     102              def __eq__(self, other):
     103                  raise Exc
     104  
     105          s1 = slice(BadCmp())
     106          s2 = slice(BadCmp())
     107          self.assertEqual(s1, s1)
     108          self.assertRaises(Exc, lambda: s1 == s2)
     109  
     110          s1 = slice(1, BadCmp())
     111          s2 = slice(1, BadCmp())
     112          self.assertEqual(s1, s1)
     113          self.assertRaises(Exc, lambda: s1 == s2)
     114  
     115          s1 = slice(1, 2, BadCmp())
     116          s2 = slice(1, 2, BadCmp())
     117          self.assertEqual(s1, s1)
     118          self.assertRaises(Exc, lambda: s1 == s2)
     119  
     120      def test_members(self):
     121          s = slice(1)
     122          self.assertEqual(s.start, None)
     123          self.assertEqual(s.stop, 1)
     124          self.assertEqual(s.step, None)
     125  
     126          s = slice(1, 2)
     127          self.assertEqual(s.start, 1)
     128          self.assertEqual(s.stop, 2)
     129          self.assertEqual(s.step, None)
     130  
     131          s = slice(1, 2, 3)
     132          self.assertEqual(s.start, 1)
     133          self.assertEqual(s.stop, 2)
     134          self.assertEqual(s.step, 3)
     135  
     136          class ESC[4;38;5;81mAnyClass:
     137              pass
     138  
     139          obj = AnyClass()
     140          s = slice(obj)
     141          self.assertTrue(s.stop is obj)
     142  
     143      def check_indices(self, slice, length):
     144          try:
     145              actual = slice.indices(length)
     146          except ValueError:
     147              actual = "valueerror"
     148          try:
     149              expected = slice_indices(slice, length)
     150          except ValueError:
     151              expected = "valueerror"
     152          self.assertEqual(actual, expected)
     153  
     154          if length >= 0 and slice.step != 0:
     155              actual = range(*slice.indices(length))
     156              expected = range(length)[slice]
     157              self.assertEqual(actual, expected)
     158  
     159      def test_indices(self):
     160          self.assertEqual(slice(None           ).indices(10), (0, 10,  1))
     161          self.assertEqual(slice(None,  None,  2).indices(10), (0, 10,  2))
     162          self.assertEqual(slice(1,     None,  2).indices(10), (1, 10,  2))
     163          self.assertEqual(slice(None,  None, -1).indices(10), (9, -1, -1))
     164          self.assertEqual(slice(None,  None, -2).indices(10), (9, -1, -2))
     165          self.assertEqual(slice(3,     None, -2).indices(10), (3, -1, -2))
     166          # issue 3004 tests
     167          self.assertEqual(slice(None, -9).indices(10), (0, 1, 1))
     168          self.assertEqual(slice(None, -10).indices(10), (0, 0, 1))
     169          self.assertEqual(slice(None, -11).indices(10), (0, 0, 1))
     170          self.assertEqual(slice(None, -10, -1).indices(10), (9, 0, -1))
     171          self.assertEqual(slice(None, -11, -1).indices(10), (9, -1, -1))
     172          self.assertEqual(slice(None, -12, -1).indices(10), (9, -1, -1))
     173          self.assertEqual(slice(None, 9).indices(10), (0, 9, 1))
     174          self.assertEqual(slice(None, 10).indices(10), (0, 10, 1))
     175          self.assertEqual(slice(None, 11).indices(10), (0, 10, 1))
     176          self.assertEqual(slice(None, 8, -1).indices(10), (9, 8, -1))
     177          self.assertEqual(slice(None, 9, -1).indices(10), (9, 9, -1))
     178          self.assertEqual(slice(None, 10, -1).indices(10), (9, 9, -1))
     179  
     180          self.assertEqual(
     181              slice(-100,  100     ).indices(10),
     182              slice(None).indices(10)
     183          )
     184          self.assertEqual(
     185              slice(100,  -100,  -1).indices(10),
     186              slice(None, None, -1).indices(10)
     187          )
     188          self.assertEqual(slice(-100, 100, 2).indices(10), (0, 10,  2))
     189  
     190          self.assertEqual(list(range(10))[::sys.maxsize - 1], [0])
     191  
     192          # Check a variety of start, stop, step and length values, including
     193          # values exceeding sys.maxsize (see issue #14794).
     194          vals = [None, -2**100, -2**30, -53, -7, -1, 0, 1, 7, 53, 2**30, 2**100]
     195          lengths = [0, 1, 7, 53, 2**30, 2**100]
     196          for slice_args in itertools.product(vals, repeat=3):
     197              s = slice(*slice_args)
     198              for length in lengths:
     199                  self.check_indices(s, length)
     200          self.check_indices(slice(0, 10, 1), -3)
     201  
     202          # Negative length should raise ValueError
     203          with self.assertRaises(ValueError):
     204              slice(None).indices(-1)
     205  
     206          # Zero step should raise ValueError
     207          with self.assertRaises(ValueError):
     208              slice(0, 10, 0).indices(5)
     209  
     210          # Using a start, stop or step or length that can't be interpreted as an
     211          # integer should give a TypeError ...
     212          with self.assertRaises(TypeError):
     213              slice(0.0, 10, 1).indices(5)
     214          with self.assertRaises(TypeError):
     215              slice(0, 10.0, 1).indices(5)
     216          with self.assertRaises(TypeError):
     217              slice(0, 10, 1.0).indices(5)
     218          with self.assertRaises(TypeError):
     219              slice(0, 10, 1).indices(5.0)
     220  
     221          # ... but it should be fine to use a custom class that provides index.
     222          self.assertEqual(slice(0, 10, 1).indices(5), (0, 5, 1))
     223          self.assertEqual(slice(MyIndexable(0), 10, 1).indices(5), (0, 5, 1))
     224          self.assertEqual(slice(0, MyIndexable(10), 1).indices(5), (0, 5, 1))
     225          self.assertEqual(slice(0, 10, MyIndexable(1)).indices(5), (0, 5, 1))
     226          self.assertEqual(slice(0, 10, 1).indices(MyIndexable(5)), (0, 5, 1))
     227  
     228      def test_setslice_without_getslice(self):
     229          tmp = []
     230          class ESC[4;38;5;81mX(ESC[4;38;5;149mobject):
     231              def __setitem__(self, i, k):
     232                  tmp.append((i, k))
     233  
     234          x = X()
     235          x[1:2] = 42
     236          self.assertEqual(tmp, [(slice(1, 2), 42)])
     237  
     238      def test_pickle(self):
     239          import pickle
     240  
     241          s = slice(10, 20, 3)
     242          for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
     243              t = loads(dumps(s, protocol))
     244              self.assertEqual(s, t)
     245              self.assertEqual(s.indices(15), t.indices(15))
     246              self.assertNotEqual(id(s), id(t))
     247  
     248      def test_copy(self):
     249          s = slice(1, 10)
     250          c = copy.copy(s)
     251          self.assertIs(s, c)
     252  
     253          s = slice(1, 10, 2)
     254          c = copy.copy(s)
     255          self.assertIs(s, c)
     256  
     257          # Corner case for mutable indices:
     258          s = slice([1, 2], [3, 4], [5, 6])
     259          c = copy.copy(s)
     260          self.assertIs(s, c)
     261          self.assertIs(s.start, c.start)
     262          self.assertIs(s.stop, c.stop)
     263          self.assertIs(s.step, c.step)
     264  
     265      def test_deepcopy(self):
     266          s = slice(1, 10)
     267          c = copy.deepcopy(s)
     268          self.assertEqual(s, c)
     269  
     270          s = slice(1, 10, 2)
     271          c = copy.deepcopy(s)
     272          self.assertEqual(s, c)
     273  
     274          # Corner case for mutable indices:
     275          s = slice([1, 2], [3, 4], [5, 6])
     276          c = copy.deepcopy(s)
     277          self.assertIsNot(s, c)
     278          self.assertEqual(s, c)
     279          self.assertIsNot(s.start, c.start)
     280          self.assertIsNot(s.stop, c.stop)
     281          self.assertIsNot(s.step, c.step)
     282  
     283      def test_cycle(self):
     284          class ESC[4;38;5;81mmyobj(): pass
     285          o = myobj()
     286          o.s = slice(o)
     287          w = weakref.ref(o)
     288          o = None
     289          support.gc_collect()
     290          self.assertIsNone(w())
     291  
     292  if __name__ == "__main__":
     293      unittest.main()