code: """
  Tests for Series cumulative operations.
  
  See also
  --------
  tests.frame.test_cumulative
  """
  from itertools import product
  
  import numpy as np
  import pytest
  
  import pandas as pd
  import pandas.util.testing as tm
  
  
  def _check_accum_op(name, series, check_dtype=True):
      func = getattr(np, name)
      tm.assert_numpy_array_equal(
          func(series).values, func(np.array(series)), check_dtype=check_dtype,
      )
  
      # with missing values
      ts = series.copy()
      ts[::2] = np.NaN
  
      result = func(ts)[1::2]
      expected = func(np.array(ts.dropna()))
  
      tm.assert_numpy_array_equal(result.values, expected, check_dtype=False)
  
  
  class TestSeriesCumulativeOps:
      def test_cumsum(self, datetime_series):
          _check_accum_op("cumsum", datetime_series)
  
      def test_cumprod(self, datetime_series):
          _check_accum_op("cumprod", datetime_series)
  
      def test_cummin(self, datetime_series):
          tm.assert_numpy_array_equal(
              datetime_series.cummin().values,
              np.minimum.accumulate(np.array(datetime_series)),
          )
          ts = datetime_series.copy()
          ts[::2] = np.NaN
          result = ts.cummin()[1::2]
          expected = np.minimum.accumulate(ts.dropna())
  
          tm.assert_series_equal(result, expected)
  
      def test_cummax(self, datetime_series):
          tm.assert_numpy_array_equal(
              datetime_series.cummax().values,
              np.maximum.accumulate(np.array(datetime_series)),
          )
          ts = datetime_series.copy()
          ts[::2] = np.NaN
          result = ts.cummax()[1::2]
          expected = np.maximum.accumulate(ts.dropna())
  
          tm.assert_series_equal(result, expected)
  
      @pytest.mark.parametrize("tz", [None, "US/Pacific"])
      def test_cummin_datetime64(self, tz):
          s = pd.Series(
              pd.to_datetime(
                  ["NaT", "2000-1-2", "NaT", "2000-1-1", "NaT", "2000-1-3"]
              ).tz_localize(tz)
          )
  
          expected = pd.Series(
              pd.to_datetime(
                  ["NaT", "2000-1-2", "NaT", "2000-1-1", "NaT", "2000-1-1"]
              ).tz_localize(tz)
          )
          result = s.cummin(skipna=True)
          tm.assert_series_equal(expected, result)
  
          expected = pd.Series(
              pd.to_datetime(
                  ["NaT", "2000-1-2", "2000-1-2", "2000-1-1", "2000-1-1", "2000-1-1"]
              ).tz_localize(tz)
          )
          result = s.cummin(skipna=False)
          tm.assert_series_equal(expected, result)
  
      @pytest.mark.parametrize("tz", [None, "US/Pacific"])
      def test_cummax_datetime64(self, tz):
          s = pd.Series(
              pd.to_datetime(
                  ["NaT", "2000-1-2", "NaT", "2000-1-1", "NaT", "2000-1-3"]
              ).tz_localize(tz)
          )
  
          expected = pd.Series(
              pd.to_datetime(
                  ["NaT", "2000-1-2", "NaT", "2000-1-2", "NaT", "2000-1-3"]
              ).tz_localize(tz)
          )
          result = s.cummax(skipna=True)
          tm.assert_series_equal(expected, result)
  
          expected = pd.Series(
              pd.to_datetime(
                  ["NaT", "2000-1-2", "2000-1-2", "2000-1-2", "2000-1-2", "2000-1-3"]
              ).tz_localize(tz)
          )
          result = s.cummax(skipna=False)
          tm.assert_series_equal(expected, result)
  
      def test_cummin_timedelta64(self):
          s = pd.Series(pd.to_timedelta(["NaT", "2 min", "NaT", "1 min", "NaT", "3 min"]))
  
          expected = pd.Series(
              pd.to_timedelta(["NaT", "2 min", "NaT", "1 min", "NaT", "1 min"])
          )
          result = s.cummin(skipna=True)
          tm.assert_series_equal(expected, result)
  
          expected = pd.Series(
              pd.to_timedelta(["NaT", "2 min", "2 min", "1 min", "1 min", "1 min"])
          )
          result = s.cummin(skipna=False)
          tm.assert_series_equal(expected, result)
  
      def test_cummax_timedelta64(self):
          s = pd.Series(pd.to_timedelta(["NaT", "2 min", "NaT", "1 min", "NaT", "3 min"]))
  
          expected = pd.Series(
              pd.to_timedelta(["NaT", "2 min", "NaT", "2 min", "NaT", "3 min"])
          )
          result = s.cummax(skipna=True)
          tm.assert_series_equal(expected, result)
  
          expected = pd.Series(
              pd.to_timedelta(["NaT", "2 min", "2 min", "2 min", "2 min", "3 min"])
          )
          result = s.cummax(skipna=False)
          tm.assert_series_equal(expected, result)
  
      def test_cummethods_bool(self):
          # GH#6270
  
          a = pd.Series([False, False, False, True, True, False, False])
          b = ~a
          c = pd.Series([False] * len(b))
          d = ~c
          methods = {
              "cumsum": np.cumsum,
              "cumprod": np.cumprod,
              "cummin": np.minimum.accumulate,
              "cummax": np.maximum.accumulate,
          }
          args = product((a, b, c, d), methods)
          for s, method in args:
              expected = pd.Series(methods[method](s.values))
              result = getattr(s, method)()
              tm.assert_series_equal(result, expected)
  
          e = pd.Series([False, True, np.nan, False])
          cse = pd.Series([0, 1, np.nan, 1], dtype=object)
          cpe = pd.Series([False, 0, np.nan, 0])
          cmin = pd.Series([False, False, np.nan, False])
          cmax = pd.Series([False, True, np.nan, True])
          expecteds = {"cumsum": cse, "cumprod": cpe, "cummin": cmin, "cummax": cmax}
  
          for method in methods:
              res = getattr(e, method)()
              tm.assert_series_equal(res, expecteds[method])
   """
  Low-dependency indexing utilities.
  """
  import numpy as np
  
  from pandas.core.dtypes.common import is_list_like
  from pandas.core.dtypes.generic import ABCIndexClass, ABCSeries
  
  # -----------------------------------------------------------
  # Indexer Identification
  
  
  def is_list_like_indexer(key) -> bool:
      """
      Check if we have a list-like indexer that is *not* a NamedTuple.
  
      Parameters
      ----------
      key : object
  
      Returns
      -------
      bool
      """
      # allow a list_like, but exclude NamedTuples which can be indexers
      return is_list_like(key) and not (isinstance(key, tuple) and type(key) is not tuple)
  
  
  def is_scalar_indexer(indexer, arr_value) -> bool:
      """
      Return True if we are all scalar indexers.
  
      Returns
      -------
      bool
      """
      if arr_value.ndim == 1:
          if not isinstance(indexer, tuple):
              indexer = tuple([indexer])
              return any(isinstance(idx, np.ndarray) and len(idx) == 0 for idx in indexer)
      return False
  
  
  def is_empty_indexer(indexer, arr_value: np.ndarray) -> bool:
      """
      Check if we have an empty indexer.
  
      Parameters
      ----------
      indexer : object
      arr_value : np.ndarray
  
      Returns
      -------
      bool
      """
      if is_list_like(indexer) and not len(indexer):
          return True
      if arr_value.ndim == 1:
          if not isinstance(indexer, tuple):
              indexer = tuple([indexer])
          return any(isinstance(idx, np.ndarray) and len(idx) == 0 for idx in indexer)
      return False
  
  
  # -----------------------------------------------------------
  # Indexer Validation
  
  
  def check_setitem_lengths(indexer, value, values) -> None:
      """
      Validate that value and indexer are the same length.
  
      An special-case is allowed for when the indexer is a boolean array
      and the number of true values equals the length of ``value``. In
      this case, no exception is raised.
  
      Parameters
      ----------
      indexer : sequence
          Key for the setitem.
      value : array-like
          Value for the setitem.
      values : array-like
          Values being set into.
  
      Returns
      -------
      None
  
      Raises
      ------
      ValueError
          When the indexer is an ndarray or list and the lengths don't match.
      """
      # boolean with truth values == len of the value is ok too
      if isinstance(indexer, (np.ndarray, list)):
          if is_list_like(value) and len(indexer) != len(value):
              if not (
                  isinstance(indexer, np.ndarray)
                  and indexer.dtype == np.bool_
                  and len(indexer[indexer]) == len(value)
              ):
                  raise ValueError(
                      "cannot set using a list-like indexer "
                      "with a different length than the value"
                  )
  
      elif isinstance(indexer, slice):
          # slice
          if is_list_like(value) and len(values):
              if len(value) != length_of_indexer(indexer, values):
                  raise ValueError(
                      "cannot set using a slice indexer with a "
                      "different length than the value"
                  )
  
  
  def validate_indices(indices: np.ndarray, n: int) -> None:
      """
      Perform bounds-checking for an indexer.
  
      -1 is allowed for indicating missing values.
  
      Parameters
      ----------
      indices : ndarray
      n : int
          Length of the array being indexed.
  
      Raises
      ------
      ValueError
  
      Examples
      --------
      >>> validate_indices([1, 2], 3)
      # OK
      >>> validate_indices([1, -2], 3)
      ValueError
      >>> validate_indices([1, 2, 3], 3)
      IndexError
      >>> validate_indices([-1, -1], 0)
      # OK
      >>> validate_indices([0, 1], 0)
      IndexError
      """
      if len(indices):
          min_idx = indices.min()
          if min_idx < -1:
              msg = f"'indices' contains values less than allowed ({min_idx} < -1)"
              raise ValueError(msg)
  
          max_idx = indices.max()
          if max_idx >= n:
              raise IndexError("indices are out-of-bounds")
  
  
  # -----------------------------------------------------------
  # Indexer Conversion
  
  
  def maybe_convert_indices(indices, n: int):
      """
      Attempt to convert indices into valid, positive indices.
  
      If we have negative indices, translate to positive here.
      If we have indices that are out-of-bounds, raise an IndexError.
  
      Parameters
      ----------
      indices : array-like
          Array of indices that we are to convert.
      n : int
          Number of elements in the array that we are indexing.
  
      Returns
      -------
      array-like
          An array-like of positive indices that correspond to the ones
          that were passed in initially to this function.
  
      Raises
      ------
      IndexError
          One of the converted indices either exceeded the number of,
          elements (specified by `n`), or was still negative.
      """
      if isinstance(indices, list):
          indices = np.array(indices)
          if len(indices) == 0:
              # If `indices` is empty, np.array will return a float,
              # and will cause indexing errors.
              return np.empty(0, dtype=np.intp)
  
      mask = indices < 0
      if mask.any():
          indices = indices.copy()
          indices[mask] += n
  
      mask = (indices >= n) | (indices < 0)
      if mask.any():
          raise IndexError("indices are out-of-bounds")
      return indices
  
  
  # -----------------------------------------------------------
  # Unsorted
  
  
  def length_of_indexer(indexer, target=None) -> int:
      """
      Return the length of a single non-tuple indexer which could be a slice.
  
      Returns
      -------
      int
      """
      if target is not None and isinstance(indexer, slice):
          target_len = len(target)
          start = indexer.start
          stop = indexer.stop
          step = indexer.step
          if start is None:
              start = 0
          elif start < 0:
              start += target_len
          if stop is None or stop > target_len:
              stop = target_len
          elif stop < 0:
              stop += target_len
          if step is None:
              step = 1
          elif step < 0:
              start, stop = stop + 1, start + 1
              step = -step
          return (stop - start + step - 1) // step
      elif isinstance(indexer, (ABCSeries, ABCIndexClass, np.ndarray, list)):
          return len(indexer)
      elif not is_list_like_indexer(indexer):
          return 1
      raise AssertionError("cannot find the length of the indexer")
  
apis: pandas.Series pandas.util.testing.assert_numpy_array_equal pandas.to_datetime pandas.util.testing.assert_series_equal numpy.array pandas.to_timedelta
apis: numpy.array pandas.core.dtypes.common.is_list_like numpy.empty