import six


def load_from_hparams_overrides(params, params_source, hparams_overrides):
  """Given a dictionary of hyperparameters and a list of overrides, merge them.

  Args:
    params: Python dict containing a base hyperparameters set.
    params_source: Python dictionary to record source of hyperparameters.
    hparams_overrides: Python list of strings. This is a set of k=v overrides
      for the hyperparameters in `params`; if `k=v1` in `params` but `k=v2` in
      `hparams_overrides`, the second value wins and the value for `k` is `v2`.

  Returns:
    Python dict of hyperparameters.
  """
  if params is None:
    raise ValueError(
        'Input dictionary is empty. It is expected to be loaded with default '
        'values')

  if not isinstance(params, dict):
    raise ValueError(
        'The base hyperparameters set must be a Python dict, was: {}'.format(
            type(params)))

  if hparams_overrides is None:
    return params, params_source

  if isinstance(hparams_overrides, six.string_types):
    hparams_overrides = [hparams_overrides]

  if not isinstance(hparams_overrides, list):
    raise ValueError(
        'Expected that hparams_overrides would be `None`, a single string, or a'
        ' list of strings, was: {}'.format(type(hparams_overrides)))

  for kv_pair in hparams_overrides:
    if not isinstance(kv_pair, six.string_types):
      raise ValueError(
          'Expected that hparams_overrides would contain Python list of strings,'
          ' but encountered an item: {}'.format(type(kv_pair)))
    key, value = kv_pair.split('=')
    parser = type(params[key])
    if parser is bool:
      params[key] = value not in ('0', 'False', 'false')
    else:
      params[key] = parser(value)
    params_source[key] = 'Command-line `hparams` flag'

  return params, params_source