1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
|
Extensions
==========
It is possible to extend the validation of each of the three basic types, ``map`` & ``seq`` & ``scalar``.
Extensions can be used to do more complex validation that is not natively supported by the core pykwalify lib.
Loading extensions
------------------
There are 2 ways to load extensions into a schema.
First you can specify any ``*.py`` file via the cli via the ``-e FILE`` or ``--extension FILE`` flag. If you would do this when using pykwalify as a library you should pass in a list of files to the ``extensions`` variable to the ``Core`` class.
The second way is to specify a list of files in the keyword ``extensions`` that can only be specified at the top level of the schema. The files can be either relative or absolute.
How custom validation works
---------------------------
Each function defined inside the extension must be defined with a globally unique method name and the following variables
.. code-block:: python
def method_name(value, rule_obj, path):
pass
To raise a validation error, you can either raise any exception (which will propagate up to the caller), or you can return ``True`` or ``False``. Any value/object interpreted as ``False`` inside an if check will cause a ``CoreError`` validation error to be raised. If you return anything other than ``True`` or ``False``, the return value will be interpreted as as string using the ``unicode()`` function and formatted as a parse error in the list of errors given at the end of the schema check.
When using a validation function on a ``sequence``, the method will be called with the entire list content as the value.
When using a validation function on a ``mapping``, the method will be called with the entire dict content as the value.
When using a validation function on any ``scalar`` type value, the method will be called with the scalar value.
This is a example of how to use extensions inside a simple schema
.. code-block:: yaml
# Schema
extensions:
- e.py
type: map
func: ext_map
mapping:
foo:
type: seq
func: ext_list
sequence:
- type: str
func: ext_str
.. code-block:: yaml
# Data
foo:
- foo
- bar
This is the extension file named ``ext.py`` that is located in the same directory as the schema file.
.. code-block:: python
# -*- coding: utf-8 -*-
import logging
log = logging.getLogger(__name__)
def ext_str(value, rule_obj, path):
log.debug("value: %s", value)
log.debug("rule_obj: %s", rule_obj)
log.debug("path: %s", path)
# Either raise some exception that you have defined your self
# raise AssertionError('Custom assertion error in jinja_function()')
# Or you should return True/False that will tell if it validated
return True
def ext_list(value, rule_obj, path):
log.debug("value: %s", value)
log.debug("rule_obj: %s", rule_obj)
log.debug("path: %s", path)
# Either raise some exception that you have defined your self
# raise AssertionError('Custom assertion error in jinja_function()')
# Or you should return True/False that will tell if it validated
return True
def ext_map(value, rule_obj, path):
log.debug("value: %s", value)
log.debug("rule_obj: %s", rule_obj)
log.debug("path: %s", path)
# Either raise some exception that you have defined your self
# raise AssertionError('Custom assertion error in jinja_function()')
# Or you should return True/False that will tell if it validated
return True
|