Apply only the args that the phase knows.

  If the phase has a **kwargs-style argument, it counts as knowing all args.

  Args:
    phase: phase_descriptor.PhaseDescriptor or PhaseGroup or callable, or
        iterable of those, the phase or phase group (or iterable) to apply
        with_args to.
    **kwargs: arguments to apply to the phase.

  Returns:
    phase_descriptor.PhaseDescriptor or PhaseGroup or iterable with the updated
    args.

def optionally_with_args(phase, **kwargs):
  """Apply only the args that the phase knows.

  If the phase has a **kwargs-style argument, it counts as knowing all args.

  Args:
    phase: phase_descriptor.PhaseDescriptor or PhaseGroup or callable, or
        iterable of those, the phase or phase group (or iterable) to apply
        with_args to.
    **kwargs: arguments to apply to the phase.

  Returns:
    phase_descriptor.PhaseDescriptor or PhaseGroup or iterable with the updated
    args.
  """
  if isinstance(phase, PhaseGroup):
    return phase.with_args(**kwargs)
  if isinstance(phase, collections.Iterable):
    return [optionally_with_args(p, **kwargs) for p in phase]

  if not isinstance(phase, phase_descriptor.PhaseDescriptor):
    phase = phase_descriptor.PhaseDescriptor.wrap_or_copy(phase)
  return phase.with_known_args(**kwargs)