def _shift_negative_indices(
    indices: Iterable[int], shift: int
) -> tuple[int, ...]:
  """Adds `shift` to negative indices and leaves non-negative indices unchanged

  Can be used to handle negative indices. For example, if we expect indices in
  `r = range(6)` and we get `[0, 3, -2]` as input, we can use ::

    shift_negative_indices([0, 3, -2], len(r))

  to get `(0, 3, 4)`. The same can be achieved in more generality with ::

    pz.select((0, 3, -2))
      .at_instances_of(int)
      .where(lambda i: i < 0)
      .apply(lambda i: i + shift)

  which is why this method is private to this module

  Args:
    indices: The integers to shift
    shift: The offset to add to negative indices. Usually, this is the largest
      index + 1, i.e. the length of the range of indices

  Returns:
    The indices as a tuple, with negative indices increased by `shift`
  """
  maybe_shifted_indices = []
  for index in indices:
    if index < 0:
      maybe_shifted_indices.append(index + shift)
    else:
      maybe_shifted_indices.append(index)
  return tuple(maybe_shifted_indices)
Adds `shift` to negative indices and leaves non-negative indices unchanged

  Can be used to handle negative indices. For example, if we expect indices in
  `r = range(6)` and we get `[0, 3, -2]` as input, we can use ::

    shift_negative_indices([0, 3, -2], len(r))

  to get `(0, 3, 4)`. The same can be achieved in more generality with ::

    pz.select((0, 3, -2))
      .at_instances_of(int)
      .where(lambda i: i < 0)
      .apply(lambda i: i + shift)

  which is why this method is private to this module

  Args:
    indices: The integers to shift
    shift: The offset to add to negative indices. Usually, this is the largest
      index + 1, i.e. the length of the range of indices

  Returns:
    The indices as a tuple, with negative indices increased by `shift`
  
penzai/core/selectors.py