Add porting guide and documentation for changes to argument spec validation (#74268)

* Add ArgumentSpecValidator to docs
* Improve docs for ArgumentSpecValidator
* Document removal of private methods

* Update module_utils documentation
    - Add docs for argument spec classes as well as validation and parameters files.
    - preserve the order in the source for errors.py
    - document DEFAULT_TYPE_VALIDATORS so it can be referenced elsewhere
    - fix automodule directive for validation.py

* Update docs in arg_spec and paremeters
    - This improves the generated documentation.

* Document breaking changes in porting guide.
* Update formatting in porting guide and add a Deprecated section
* Fine tune module_utils documentation


* Move instance docstring to the __init__ method
  Remove optional description since it fails the sanity test and I am not 100% it is valid anyway.

* Remoe incorrect parameter from docstring
  This was changed a while ago but wasn't removed from the docstring.

* Use attr rather than attribute
  The py:attribute: domain only exists in newer Sphinx >= 3.1.

* Improve documentation on exceptions
* Final pass
    - use args/kwargs instead of param
    - fix formatting errors that didn't display examples correctly
    - format TypeErrors so they are referenced as classes
    - specify complex types
This commit is contained in:
Sam Doran 2021-04-20 15:40:53 -04:00 committed by GitHub
parent 6e56e72d99
commit 2cbfd1e350
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 284 additions and 126 deletions

View file

@ -29,22 +29,71 @@ Command Line
* The ``ansible-galaxy login`` command has been removed, as the underlying API it used for GitHub auth has been shut down. Publishing roles or collections to Galaxy with ``ansible-galaxy`` now requires that a Galaxy API token be passed to the CLI using a token file (default location ``~/.ansible/galaxy_token``) or (insecurely) with the ``--token`` argument to ``ansible-galaxy``.
Other:
Deprecated
==========
The constant ``ansible.module_utils.basic._CHECK_ARGUMENT_TYPES_DISPATCHER`` is deprecated. Use :const:`ansible.module_utils.common.parameters.DEFAULT_TYPE_VALIDATORS` instead.
Breaking Changes
================
Changes to ``AnsibleModule``
----------------------------
With the move to :class:`ArgumentSpecValidator <ansible.module_utils.common.arg_spec.ArgumentSpecValidator>` for performing argument spec validation, the following private methods in :class:`AnsibleModule <ansible.module_utils.basic.AnsibleModule>` have been removed:
- ``_check_argument_types()``
- ``_check_argument_values()``
- ``_check_arguments()``
- ``_check_mutually_exclusive()`` --> :func:`ansible.module_utils.common.validation.check_mutually_exclusive`
- ``_check_required_arguments()`` --> :func:`ansible.module_utils.common.validation.check_required_arguments`
- ``_check_required_by()`` --> :func:`ansible.module_utils.common.validation.check_required_by`
- ``_check_required_if()`` --> :func:`ansible.module_utils.common.validation.check_required_if`
- ``_check_required_one_of()`` --> :func:`ansible.module_utils.common.validation.check_required_one_of`
- ``_check_required_together()`` --> :func:`ansible.module_utils.common.validation.check_required_together`
- ``_check_type_bits()`` --> :func:`ansible.module_utils.common.validation.check_type_bits`
- ``_check_type_bool()`` --> :func:`ansible.module_utils.common.validation.check_type_bool`
- ``_check_type_bytes()`` --> :func:`ansible.module_utils.common.validation.check_type_bytes`
- ``_check_type_dict()`` --> :func:`ansible.module_utils.common.validation.check_type_dict`
- ``_check_type_float()`` --> :func:`ansible.module_utils.common.validation.check_type_float`
- ``_check_type_int()`` --> :func:`ansible.module_utils.common.validation.check_type_int`
- ``_check_type_jsonarg()`` --> :func:`ansible.module_utils.common.validation.check_type_jsonarg`
- ``_check_type_list()`` --> :func:`ansible.module_utils.common.validation.check_type_list`
- ``_check_type_path()`` --> :func:`ansible.module_utils.common.validation.check_type_path`
- ``_check_type_raw()`` --> :func:`ansible.module_utils.common.validation.check_type_raw`
- ``_check_type_str()`` --> :func:`ansible.module_utils.common.validation.check_type_str`
- ``_count_terms()`` --> :func:`ansible.module_utils.common.validation.count_terms`
- ``_get_wanted_type()``
- ``_handle_aliases()``
- ``_handle_no_log_values()``
- ``_handle_options()``
- ``_set_defaults()``
- ``_set_fallbacks()``
Modules or plugins using these private methods should use the public functions in :mod:`ansible.module_utils.common.validation` or :meth:`ArgumentSpecValidator.validate() <ansible.module_utils.common.arg_spec.ArgumentSpecValidator.validate>` if no public function was listed above.
Changes to :mod:`ansible.module_utils.common.parameters`
--------------------------------------------------------
The following functions in :mod:`ansible.module_utils.common.parameters` are now private and should not be used directly. Use :meth:`ArgumentSpecValidator.validate() <ansible.module_utils.common.arg_spec.ArgumentSpecValidator.validate>` instead.
- ``list_no_log_values``
- ``list_deprecations``
- ``handle_aliases``
Other
======
* **Upgrading**: If upgrading from ``ansible < 2.10`` or from ``ansible-base`` and using pip, you must ``pip uninstall ansible`` or ``pip uninstall ansible-base`` before installing ``ansible-core`` to avoid conflicts.
* Python 3.8 on the controller node is a soft requirement for this release. ``ansible-core`` 2.11 still works with the same versions of Python that ``ansible-base`` 2.10 worked with, however 2.11 emits a warning when running on a controller node with a Python version less than 3.8. This warning can be disabled by setting ``ANSIBLE_CONTROLLER_PYTHON_WARNING=False`` in your environment. ``ansible-core`` 2.12 will require Python 3.8 or greater.
* The configuration system now validates the ``choices`` field, so any settings that violate it and were ignored in 2.10 cause an error in 2.11. For example, `ANSIBLE_COLLECTIONS_ON_ANSIBLE_VERSION_MISMATCH=0` now causes an error (valid choices are ``ignore``, ``warn`` or ``error``).
* The configuration system now validates the ``choices`` field, so any settings that violate it and were ignored in 2.10 cause an error in 2.11. For example, ``ANSIBLE_COLLECTIONS_ON_ANSIBLE_VERSION_MISMATCH=0`` now causes an error (valid choices are ``ignore``, ``warn`` or ``error``).
* The ``ansible-galaxy`` command now uses ``resolvelib`` for resolving dependencies. In most cases this should not make a user-facing difference beyond being more performant, but we note it here for posterity and completeness.
* If you import Python ``module_utils`` into any modules you maintain, you may now mark the import as optional during the module payload build by wrapping the ``import`` statement in a ``try`` or ``if`` block. This allows modules to use ``module_utils`` that may not be present in all versions of Ansible or a collection, and to perform arbitrary recovery or fallback actions during module runtime.
Deprecated
==========
No notable changes
Modules
=======

View file

@ -25,3 +25,50 @@ To use this functionality, include ``import ansible.module_utils.basic`` in your
.. automodule:: ansible.module_utils.basic
:members:
Argument Spec
---------------------
Classes and functions for validating parameters against an argument spec.
ArgumentSpecValidator
=====================
.. autoclass:: ansible.module_utils.common.arg_spec.ArgumentSpecValidator
:members:
ValidationResult
================
.. autoclass:: ansible.module_utils.common.arg_spec.ValidationResult
:members:
:member-order: bysource
:private-members: _no_log_values # This only works in sphinx >= 3.2. Otherwise it shows all private members with doc strings.
Parameters
==========
.. automodule:: ansible.module_utils.common.parameters
:members:
.. py:data:: DEFAULT_TYPE_VALIDATORS
:class:`dict` of type names, such as ``'str'``, and the default function
used to check that type, :func:`~ansible.module_utils.common.validation.check_type_str` in this case.
Validation
==========
Standalone functions for validating various parameter types.
.. automodule:: ansible.module_utils.common.validation
:members:
Errors
------
.. automodule:: ansible.module_utils.errors
:members:
:member-order: bysource

View file

@ -50,29 +50,45 @@ from ansible.module_utils.errors import (
class ValidationResult:
"""Result of argument spec validation.
:param parameters: Terms to be validated and coerced to the correct type.
:type parameters: dict
This is the object returned by :func:`ArgumentSpecValidator.validate()
<ansible.module_utils.common.arg_spec.ArgumentSpecValidator.validate()>`
containing the validated parameters and any errors.
"""
def __init__(self, parameters):
"""
:arg parameters: Terms to be validated and coerced to the correct type.
:type parameters: dict
"""
self._no_log_values = set()
""":class:`set` of values marked as ``no_log`` in the argument spec. This
is a temporary holding place for these values and may move in the future.
"""
self._unsupported_parameters = set()
self._validated_parameters = deepcopy(parameters)
self._deprecations = []
self._warnings = []
self.errors = AnsibleValidationErrorMultiple()
"""
:class:`~ansible.module_utils.errors.AnsibleValidationErrorMultiple` containing all
:class:`~ansible.module_utils.errors.AnsibleValidationError` objects if there were
any failures during validation.
"""
@property
def validated_parameters(self):
"""Validated and coerced parameters."""
return self._validated_parameters
@property
def unsupported_parameters(self):
""":class:`set` of unsupported parameter names."""
return self._unsupported_parameters
@property
def error_messages(self):
""":class:`list` of all error messages from each exception in :attr:`errors`."""
return self.errors.messages
@ -80,30 +96,7 @@ class ArgumentSpecValidator:
"""Argument spec validation class
Creates a validator based on the ``argument_spec`` that can be used to
validate a number of parameters using the ``validate()`` method.
:param argument_spec: Specification of valid parameters and their type. May
include nested argument specs.
:type argument_spec: dict
:param mutually_exclusive: List or list of lists of terms that should not
be provided together.
:type mutually_exclusive: list, optional
:param required_together: List of lists of terms that are required together.
:type required_together: list, optional
:param required_one_of: List of lists of terms, one of which in each list
is required.
:type required_one_of: list, optional
:param required_if: List of lists of ``[parameter, value, [parameters]]`` where
one of [parameters] is required if ``parameter`` == ``value``.
:type required_if: list, optional
:param required_by: Dictionary of parameter names that contain a list of
parameters required by each key in the dictionary.
:type required_by: dict, optional
validate a number of parameters using the :meth:`validate` method.
"""
def __init__(self, argument_spec,
@ -114,6 +107,31 @@ class ArgumentSpecValidator:
required_by=None,
):
"""
:arg argument_spec: Specification of valid parameters and their type. May
include nested argument specs.
:type argument_spec: dict[str, dict]
:kwarg mutually_exclusive: List or list of lists of terms that should not
be provided together.
:type mutually_exclusive: list[str] or list[list[str]]
:kwarg required_together: List of lists of terms that are required together.
:type required_together: list[list[str]]
:kwarg required_one_of: List of lists of terms, one of which in each list
is required.
:type required_one_of: list[list[str]]
:kwarg required_if: List of lists of ``[parameter, value, [parameters]]`` where
one of ``[parameters]`` is required if ``parameter == value``.
:type required_if: list
:kwarg required_by: Dictionary of parameter names that contain a list of
parameters required by each key in the dictionary.
:type required_by: dict[str, list[str]]
"""
self._mutually_exclusive = mutually_exclusive
self._required_together = required_together
self._required_one_of = required_one_of
@ -130,30 +148,37 @@ class ArgumentSpecValidator:
self._valid_parameter_names.update([key])
def validate(self, parameters, *args, **kwargs):
"""Validate module parameters against argument spec. Returns a
ValidationResult object.
"""Validate ``parameters`` against argument spec.
Error messages in the ValidationResult may contain no_log values and should be
sanitized before logging or displaying.
Error messages in the :class:`ValidationResult` may contain no_log values and should be
sanitized with :func:`~ansible.module_utils.common.parameters.sanitize_keys` before logging or displaying.
:Example:
:arg parameters: Parameters to validate against the argument spec
:type parameters: dict[str, dict]
validator = ArgumentSpecValidator(argument_spec)
result = validator.validate(parameters)
:return: :class:`ValidationResult` containing validated parameters.
if result.error_messages:
sys.exit("Validation failed: {0}".format(", ".join(result.error_messages))
:Simple Example:
valid_params = result.validated_parameters
.. code-block:: text
:param argument_spec: Specification of parameters, type, and valid values
:type argument_spec: dict
argument_spec = {
'name': {'type': 'str'},
'age': {'type': 'int'},
}
:param parameters: Parameters provided to the role
:type parameters: dict
parameters = {
'name': 'bo',
'age': '42',
}
:return: Object containing validated parameters.
:rtype: ValidationResult
validator = ArgumentSpecValidator(argument_spec)
result = validator.validate(parameters)
if result.error_messages:
sys.exit("Validation failed: {0}".format(", ".join(result.error_messages))
valid_params = result.validated_parameters
"""
result = ValidationResult(parameters)
@ -238,6 +263,12 @@ class ArgumentSpecValidator:
class ModuleArgumentSpecValidator(ArgumentSpecValidator):
"""Argument spec validation class used by :class:`AnsibleModule`.
This is not meant to be used outside of :class:`AnsibleModule`. Use
:class:`ArgumentSpecValidator` instead.
"""
def __init__(self, *args, **kwargs):
super(ModuleArgumentSpecValidator, self).__init__(*args, **kwargs)

View file

@ -131,7 +131,7 @@ def _get_type_validator(wanted):
of the wanted type.
"""
# Use one our our builtin validators.
# Use one of our builtin validators.
if not callable(wanted):
if wanted is None:
# Default type for parameters
@ -249,9 +249,18 @@ def _list_deprecations(argument_spec, parameters, prefix=''):
:arg parameters: Dictionary of parameters
:returns: List of dictionaries containing a message and version in which
the deprecated parameter will be removed, or an empty list::
the deprecated parameter will be removed, or an empty list.
[{'msg': "Param 'deptest' is deprecated. See the module docs for more information", 'version': '2.9'}]
:Example return:
.. code-block:: python
[
{
'msg': "Param 'deptest' is deprecated. See the module docs for more information",
'version': '2.9'
}
]
"""
deprecations = []
@ -293,9 +302,7 @@ def _list_no_log_values(argument_spec, params):
:arg argument_spec: An argument spec dictionary
:arg params: Dictionary of all parameters
:returns: Set of strings that should be hidden from output::
{'secret_dict_value', 'secret_list_item_one', 'secret_list_item_two', 'secret_string'}
:returns: :class:`set` of strings that should be hidden from output:
"""
no_log_values = set()
@ -374,10 +381,13 @@ def _remove_values_conditions(value, no_log_strings, deferred_removals):
a container type. The format of each entry is a 2-tuple where the first
element is the ``value`` parameter and the second value is a new
container to copy the elements of ``value`` into once iterated.
:returns: if ``value`` is a scalar, returns ``value`` with two exceptions:
1. :class:`~datetime.datetime` objects which are changed into a string representation.
2. objects which are in no_log_strings are replaced with a placeholder
so that no sensitive data is leaked.
2. objects which are in ``no_log_strings`` are replaced with a placeholder
so that no sensitive data is leaked.
If ``value`` is a container type, returns a new empty container.
``deferred_removals`` is added to as a side-effect of this function.
@ -458,13 +468,13 @@ def _set_defaults(argument_spec, parameters, set_default=True):
Modifies parameters directly.
:param argument_spec: Argument spec
:arg argument_spec: Argument spec
:type argument_spec: dict
:param parameters: Parameters to evaluate
:arg parameters: Parameters to evaluate
:type parameters: dict
:param set_default: Whether or not to set the default values
:kwarg set_default: Whether or not to set the default values
:type set_default: bool
:returns: Set of strings that should not be logged.
@ -491,7 +501,7 @@ def _set_defaults(argument_spec, parameters, set_default=True):
def _sanitize_keys_conditions(value, no_log_strings, ignore_keys, deferred_removals):
""" Helper method to sanitize_keys() to build deferred_removals and avoid deep recursion. """
""" Helper method to :func:`sanitize_keys` to build ``deferred_removals`` and avoid deep recursion. """
if isinstance(value, (text_type, binary_type)):
return value
@ -564,16 +574,16 @@ def _validate_argument_types(argument_spec, parameters, prefix='', options_conte
functions are returned. If any parameter fails to validate, it will not
be in the returned parameters.
:param argument_spec: Argument spec
:arg argument_spec: Argument spec
:type argument_spec: dict
:param parameters: Parameters
:arg parameters: Parameters
:type parameters: dict
:param prefix: Name of the parent key that contains the spec. Used in the error message
:kwarg prefix: Name of the parent key that contains the spec. Used in the error message
:type prefix: str
:param options_context: List of contexts?
:kwarg options_context: List of contexts?
:type options_context: list
:returns: Two item tuple containing validated and coerced parameters
@ -680,7 +690,10 @@ def _validate_argument_values(argument_spec, parameters, options_context=None, e
def _validate_sub_spec(argument_spec, parameters, prefix='', options_context=None, errors=None, no_log_values=None, unsupported_parameters=None):
"""Validate sub argument spec. This function is recursive."""
"""Validate sub argument spec.
This function is recursive.
"""
if options_context is None:
options_context = []
@ -811,15 +824,15 @@ def set_fallbacks(argument_spec, parameters):
def sanitize_keys(obj, no_log_strings, ignore_keys=frozenset()):
""" Sanitize the keys in a container object by removing no_log values from key names.
"""Sanitize the keys in a container object by removing ``no_log`` values from key names.
This is a companion function to the `remove_values()` function. Similar to that function,
we make use of deferred_removals to avoid hitting maximum recursion depth in cases of
This is a companion function to the :func:`remove_values` function. Similar to that function,
we make use of ``deferred_removals`` to avoid hitting maximum recursion depth in cases of
large data structures.
:param obj: The container object to sanitize. Non-container objects are returned unmodified.
:param no_log_strings: A set of string values we do not want logged.
:param ignore_keys: A set of string values of keys to not sanitize.
:arg obj: The container object to sanitize. Non-container objects are returned unmodified.
:arg no_log_strings: A set of string values we do not want logged.
:kwarg ignore_keys: A set of string values of keys to not sanitize.
:returns: An object with sanitized keys.
"""
@ -855,12 +868,13 @@ def sanitize_keys(obj, no_log_strings, ignore_keys=frozenset()):
def remove_values(value, no_log_strings):
""" Remove strings in no_log_strings from value. If value is a container
type, then remove a lot more.
"""Remove strings in ``no_log_strings`` from value.
Use of deferred_removals exists, rather than a pure recursive solution,
If value is a container type, then remove a lot more.
Use of ``deferred_removals`` exists, rather than a pure recursive solution,
because of the potential to hit the maximum recursion depth when dealing with
large amounts of data (see issue #24560).
large amounts of data (see `issue #24560 <https://github.com/ansible/ansible/issues/24560>`_).
"""
deferred_removals = deque()

View file

@ -76,7 +76,7 @@ def check_mutually_exclusive(terms, parameters, options_context=None):
:arg terms: List of mutually exclusive parameters
:arg parameters: Dictionary of parameters
:returns: Empty list or raises TypeError if the check fails.
:returns: Empty list or raises :class:`TypeError` if the check fails.
"""
results = []
@ -107,8 +107,10 @@ def check_required_one_of(terms, parameters, options_context=None):
:arg terms: List of lists of terms to check. For each list of terms, at
least one is required.
:arg parameters: Dictionary of parameters
:kwarg options_context: List of strings of parent key names if ``terms`` are
in a sub spec.
:returns: Empty list or raises TypeError if the check fails.
:returns: Empty list or raises :class:`TypeError` if the check fails.
"""
results = []
@ -132,16 +134,16 @@ def check_required_one_of(terms, parameters, options_context=None):
def check_required_together(terms, parameters, options_context=None):
"""Check each list of terms to ensure every parameter in each list exists
in the given parameters
in the given parameters.
Accepts a list of lists or tuples
Accepts a list of lists or tuples.
:arg terms: List of lists of terms to check. Each list should include
parameters that are all required when at least one is specified
in the parameters.
:arg parameters: Dictionary of parameters
:returns: Empty list or raises TypeError if the check fails.
:returns: Empty list or raises :class:`TypeError` if the check fails.
"""
results = []
@ -166,14 +168,14 @@ def check_required_together(terms, parameters, options_context=None):
def check_required_by(requirements, parameters, options_context=None):
"""For each key in requirements, check the corresponding list to see if they
exist in parameters
exist in parameters.
Accepts a single string or list of values for each key
Accepts a single string or list of values for each key.
:arg requirements: Dictionary of requirements
:arg parameters: Dictionary of parameters
:returns: Empty dictionary or raises TypeError if the
:returns: Empty dictionary or raises :class:`TypeError` if the
"""
result = {}
@ -203,16 +205,16 @@ def check_required_by(requirements, parameters, options_context=None):
def check_required_arguments(argument_spec, parameters, options_context=None):
"""Check all paramaters in argument_spec and return a list of parameters
that are required but not present in parameters
"""Check all parameters in argument_spec and return a list of parameters
that are required but not present in parameters.
Raises TypeError if the check fails
Raises :class:`TypeError` if the check fails
:arg argument_spec: Argument spec dicitionary containing all parameters
:arg argument_spec: Argument spec dictionary containing all parameters
and their specification
:arg module_paramaters: Dictionary of parameters
:arg parameters: Dictionary of parameters
:returns: Empty list or raises TypeError if the check fails.
:returns: Empty list or raises :class:`TypeError` if the check fails.
"""
missing = []
@ -236,32 +238,38 @@ def check_required_arguments(argument_spec, parameters, options_context=None):
def check_required_if(requirements, parameters, options_context=None):
"""Check parameters that are conditionally required
Raises TypeError if the check fails
Raises :class:`TypeError` if the check fails
:arg requirements: List of lists specifying a parameter, value, parameters
required when the given parameter is the specified value, and optionally
a boolean indicating any or all parameters are required.
Example:
required_if=[
['state', 'present', ('path',), True],
['someint', 99, ('bool_param', 'string_param')],
]
:Example:
:arg module_paramaters: Dictionary of parameters
.. code-block:: python
:returns: Empty list or raises TypeError if the check fails.
required_if=[
['state', 'present', ('path',), True],
['someint', 99, ('bool_param', 'string_param')],
]
:arg parameters: Dictionary of parameters
:returns: Empty list or raises :class:`TypeError` if the check fails.
The results attribute of the exception contains a list of dictionaries.
Each dictionary is the result of evaluting each item in requirements.
Each dictionary is the result of evaluating each item in requirements.
Each return dictionary contains the following keys:
:key missing: List of parameters that are required but missing
:key requires: 'any' or 'all'
:key paramater: Parameter name that has the requirement
:key value: Original value of the paramater
:key parameter: Parameter name that has the requirement
:key value: Original value of the parameter
:key requirements: Original required parameters
Example:
:Example:
.. code-block:: python
[
{
'parameter': 'someint',
@ -321,13 +329,12 @@ def check_missing_parameters(parameters, required_parameters=None):
"""This is for checking for required params when we can not check via
argspec because we need more information than is simply given in the argspec.
Raises TypeError if any required parameters are missing
Raises :class:`TypeError` if any required parameters are missing
:arg module_paramaters: Dictionary of parameters
:arg required_parameters: List of parameters to look for in the given module
parameters
:arg parameters: Dictionary of parameters
:arg required_parameters: List of parameters to look for in the given parameters.
:returns: Empty list or raises TypeError if the check fails.
:returns: Empty list or raises :class:`TypeError` if the check fails.
"""
missing_params = []
if required_parameters is None:
@ -374,13 +381,13 @@ def check_type_str(value, allow_conversion=True, param=None, prefix=''):
def check_type_list(value):
"""Verify that the value is a list or convert to a list
A comma separated string will be split into a list. Rases a TypeError if
unable to convert to a list.
A comma separated string will be split into a list. Raises a :class:`TypeError`
if unable to convert to a list.
:arg value: Value to validate or convert to a list
:returns: Original value if it is already a list, single item list if a
float, int or string without commas, or a multi-item list if a
float, int, or string without commas, or a multi-item list if a
comma-delimited string.
"""
if isinstance(value, list):
@ -397,9 +404,9 @@ def check_type_list(value):
def check_type_dict(value):
"""Verify that value is a dict or convert it to a dict and return it.
Raises TypeError if unable to convert to a dict
Raises :class:`TypeError` if unable to convert to a dict
:arg value: Dict or string to convert to a dict. Accepts 'k1=v2, k2=v2'.
:arg value: Dict or string to convert to a dict. Accepts ``k1=v2, k2=v2``.
:returns: value converted to a dictionary
"""
@ -451,7 +458,7 @@ def check_type_dict(value):
def check_type_bool(value):
"""Verify that the value is a bool or convert it to a bool and return it.
Raises TypeError if unable to convert to a bool
Raises :class:`TypeError` if unable to convert to a bool
:arg value: String, int, or float to convert to bool. Valid booleans include:
'1', 'on', 1, '0', 0, 'n', 'f', 'false', 'true', 'y', 't', 'yes', 'no', 'off'
@ -471,11 +478,11 @@ def check_type_int(value):
"""Verify that the value is an integer and return it or convert the value
to an integer and return it
Raises TypeError if unable to convert to an int
Raises :class:`TypeError` if unable to convert to an int
:arg value: String or int to convert of verify
:return: Int of given value
:return: int of given value
"""
if isinstance(value, integer_types):
return value
@ -492,11 +499,11 @@ def check_type_int(value):
def check_type_float(value):
"""Verify that value is a float or convert it to a float and return it
Raises TypeError if unable to convert to a float
Raises :class:`TypeError` if unable to convert to a float
:arg value: Float, int, str, or bytes to verify or convert and return.
:arg value: float, int, str, or bytes to verify or convert and return.
:returns: Float of given value.
:returns: float of given value.
"""
if isinstance(value, float):
return value
@ -519,15 +526,14 @@ def check_type_path(value,):
def check_type_raw(value):
"""Returns the raw value
"""
"""Returns the raw value"""
return value
def check_type_bytes(value):
"""Convert a human-readable string value to bytes
Raises TypeError if unable to covert the value
Raises :class:`TypeError` if unable to covert the value
"""
try:
return human_to_bytes(value)
@ -538,9 +544,9 @@ def check_type_bytes(value):
def check_type_bits(value):
"""Convert a human-readable string bits value to bits in integer.
Example: check_type_bits('1Mb') returns integer 1048576.
Example: ``check_type_bits('1Mb')`` returns integer 1048576.
Raises TypeError if unable to covert the value.
Raises :class:`TypeError` if unable to covert the value.
"""
try:
return human_to_bytes(value, isbits=True)
@ -552,7 +558,7 @@ def check_type_jsonarg(value):
"""Return a jsonified string. Sometimes the controller turns a json string
into a dict/list so transform it back into json here
Raises TypeError if unable to covert the value
Raises :class:`TypeError` if unable to covert the value
"""
if isinstance(value, (text_type, binary_type)):

View file

@ -16,9 +16,11 @@ class AnsibleValidationError(Exception):
def __init__(self, message):
super(AnsibleValidationError, self).__init__(message)
self.error_message = message
"""The error message passed in when the exception was raised."""
@property
def msg(self):
"""The error message passed in when the exception was raised."""
return self.args[0]
@ -27,6 +29,7 @@ class AnsibleValidationErrorMultiple(AnsibleValidationError):
def __init__(self, errors=None):
self.errors = errors[:] if errors else []
""":class:`list` of :class:`AnsibleValidationError` objects"""
def __getitem__(self, key):
return self.errors[key]
@ -39,16 +42,24 @@ class AnsibleValidationErrorMultiple(AnsibleValidationError):
@property
def msg(self):
"""The first message from the first error in ``errors``."""
return self.errors[0].args[0]
@property
def messages(self):
""":class:`list` of each error message in ``errors``."""
return [err.msg for err in self.errors]
def append(self, error):
"""Append a new error to ``self.errors``.
Only :class:`AnsibleValidationError` should be added.
"""
self.errors.append(error)
def extend(self, errors):
"""Append each item in ``errors`` to ``self.errors``. Only :class:`AnsibleValidationError` should be added."""
self.errors.extend(errors)