def attr_value_is(msg, check_fn, subname=''):
  """Helper function for writing attr.s validators.

  Args:
    * msg (str) - The message to include in the ValueError. Should be
      the quoted part of: name is not '<msg>'.
    * check_fn (callable) - Called with 'value'; should return True iff the
      value is valid.
    * subname (str) - Some sub-element of attrib.name; e.g. if checking
      a dictionary key, this might be ' keys'.

  Returns a validator function which raises TypeError if the value doesn't match
  the value.
  """
  def inner(_self, attrib, value):
    if not check_fn(value):
      raise ValueError(
        "'{name}' is not {msg} (got {value!r})".format(
          name=attrib.name+subname,
          msg=msg,
          value=value,
        ),
        attrib,
        value,
        msg,
        subname,
      )
  return inner