Plumbing functions powering our validation facilities.
parselglossy.validation_plumbing.
check_keyword
()[source]¶Checks that a template keyword is well-formed.
In this function, a template keyword is well-formed if it has:
The two additional criteria:
can only be checked meaningfully later, as they might depend on keyword(s)/section(s) of the input that are only known after merging.
Parameters: |
|
---|---|
Returns: | errors |
Return type: | List[Error] |
parselglossy.validation_plumbing.
rec_check_predicates
()[source]¶Run predicates on input tree with fixed defaults.
Parameters: |
|
---|---|
Returns: | errors – A list of keys to access elements in the dict that raised an error. |
Return type: | List[Error] |
parselglossy.validation_plumbing.
rec_fix_defaults
()[source]¶Fix default value and perform type checking.
Parameters: |
|
---|---|
Returns: |
|
Notes
Since we allow callables to appear as defaults, we need to run them to determine the actual default values.
This operation must be done with some care, to avoid false negatives or ambiguous type checks. For example:
str
and the default a callable, the type will
match, but the default will make no sense.int
, the type will not match.However, by design the callables must refer to some other field in the input tree, hence they must contain the reserved token “user”. This allows us to disambiguate a callable as default from a value as default.
The final strategy adopted is then:
1. Perform type checking with type_matches()
. If successful, we
coerce the type.
2. If types did not match, we further check whether the value is a string,
containing the reserved token “value”. This means the default value is
actually a callable. We run the callable, which internally coerces the type
of the result to the expected one.
3. If even this check was unsuccessful, types really were unmatched. We
report the error and move on.
parselglossy.validation_plumbing.
rec_is_template_valid
()[source]¶Checks a template dict is well-formed.
A template dict is well-formed if:
All keywords have:
Note that the latter two criteria can only be checked later on.
No sections are nested under keywords.
All sections have a non-empty docstring.
Parameters: |
|
---|---|
Returns: | errors |
Return type: | List[Error] |
parselglossy.validation_plumbing.
rec_merge_ours
()[source]¶Recursively merge two dict-s with “ours” strategy.
Parameters: |
|
---|---|
Returns: |
|
Notes
The theirs dictionary is supposed to be the view by defaults of the validation specification, whereas ours is the dictionary from user input. The recursive merge action will generate a complete, but not validated, input dictionary by using default values where these are not overridden by user input, hence the naming “ours” for the merge strategy.
parselglossy.validation_plumbing.
run_callable
(f: str, d: Dict[str, Any], *, t: str) → Tuple[str, Optional[Any]][source]¶Run a callable encoded as a string.
A callable is any function of the input tree.
Parameters: |
|
---|---|
Returns: | retval – The error message, if any, and the result of the callable, if any. |
Return type: | Tuple[str, Optional[Any]] |
Notes
The input tree is called user
.
The callable is turned into a lambda function and executed using eval
,
to ensure that the syntax of callable actions is correct and that the
callable returns correctly.
We need to pass the full incoming
dictionary as argument to
eval
, because we allow indexing in the global dict
. That is,
since it is allowed to define defaults in a given section based on
defaults in other section we must be able to access the full input at
any point.
parselglossy.validation_plumbing.
run_predicate
(predicate: str, where: str, user: Dict[str, Any]) → Tuple[str, bool][source]¶Run a predicate to check whether it is satisfied.
Parameters: |
|
---|
Notes
We replace the convenience placeholder “value” with its full “address” in user
.