def numeric(value,
            allow_empty = False,
            minimum = None,
            maximum = None,
            **kwargs):
    """Validate that ``value`` is a numeric value.

    :param value: The value to validate.

    :param allow_empty: If ``True``, returns :obj:`None <python:None>` if ``value``
      is :obj:`None <python:None>`. If ``False``, raises an
      :class:`EmptyValueError <validator_collection.errors.EmptyValueError>` if
      ``value`` is :obj:`None <python:None>`.
      Defaults to ``False``.
    :type allow_empty: :class:`bool <python:bool>`

    :param minimum: If supplied, will make sure that ``value`` is greater than or
      equal to this value.
    :type minimum: numeric

    :param maximum: If supplied, will make sure that ``value`` is less than or
      equal to this value.
    :type maximum: numeric

    :returns: ``value`` / :obj:`None <python:None>`

    :raises EmptyValueError: if ``value`` is :obj:`None <python:None>` and
      ``allow_empty`` is ``False``
    :raises MinimumValueError: if ``minimum`` is supplied and ``value`` is less
      than the ``minimum``
    :raises MaximumValueError: if ``maximum`` is supplied and ``value`` is more
      than the ``maximum``
    :raises CannotCoerceError: if ``value`` cannot be coerced to a numeric form

    """
    if maximum is None:
        maximum = POSITIVE_INFINITY
    else:
        maximum = numeric(maximum)
    if minimum is None:
        minimum = NEGATIVE_INFINITY
    else:
        minimum = numeric(minimum)

    if value is None and not allow_empty:
        raise errors.EmptyValueError('value (%s) was empty' % value)
    elif value is not None:
        if isinstance(value, str):
            try:
                value = float_(value)
            except (ValueError, TypeError):
                raise errors.CannotCoerceError(
                    'value (%s) cannot be coerced to a numeric form' % value
                )
        elif not isinstance(value, numeric_types):
            raise errors.CannotCoerceError(
                'value (%s) is not a numeric type, was %s' % (value,
                                                              type(value))
            )

    if value is not None and value > maximum:
        raise errors.MaximumValueError(
            'value (%s) exceeds maximum (%s)' % (value, maximum)
        )

    if value is not None and value < minimum:
        raise errors.MinimumValueError(
            'value (%s) less than minimum (%s)' % (value, minimum)
        )

    return value
Validate that ``value`` is a numeric value.

    :param value: The value to validate.

    :param allow_empty: If ``True``, returns :obj:`None <python:None>` if ``value``
      is :obj:`None <python:None>`. If ``False``, raises an
      :class:`EmptyValueError <validator_collection.errors.EmptyValueError>` if
      ``value`` is :obj:`None <python:None>`.
      Defaults to ``False``.
    :type allow_empty: :class:`bool <python:bool>`

    :param minimum: If supplied, will make sure that ``value`` is greater than or
      equal to this value.
    :type minimum: numeric

    :param maximum: If supplied, will make sure that ``value`` is less than or
      equal to this value.
    :type maximum: numeric

    :returns: ``value`` / :obj:`None <python:None>`

    :raises EmptyValueError: if ``value`` is :obj:`None <python:None>` and
      ``allow_empty`` is ``False``
    :raises MinimumValueError: if ``minimum`` is supplied and ``value`` is less
      than the ``minimum``
    :raises MaximumValueError: if ``maximum`` is supplied and ``value`` is more
      than the ``maximum``
    :raises CannotCoerceError: if ``value`` cannot be coerced to a numeric form