datalad_next.constraints.EnsureCommandParameterization
- class datalad_next.constraints.EnsureCommandParameterization(param_constraints: Dict[str, Constraint], *, validate_defaults: Container[str] | None = None, joint_constraints: Dict[ParameterConstraintContext, Callable] | None = None, tailor_for_dataset: Dict[str, str] | None = None)[source]
Bases:
ConstraintBase class for ValidatedInterface parameter validators
This class can be used as-is, by declaring individual constraints in the constructor, or it can be subclassed to consolidate all custom validation-related code for a command in a single place.
Commonly this constraint is used by declaring particular value constraints for individual parameters as a mapping. Declaring that the
pathparameter should receive something that is or can be coerced to a validPathobject looks like this:EnsureCommandParameterization({'path': EnsurePath()})
This class differs from a standard
Constraintimplementation, because its__call__()method support additional arguments that are used by the internalInterfacehandling code to control how parameters are validated.During validation, when no validator for a particular parameter is declared, any input value is passed on as-is, and otherwise an input is passed through the validator.
There is one exception to this rule: When a parameter value is identical to its default value (as declared in the command signature, and communicated via the
at_defaultargument of__call__()), this default value is also passed as-is, unless the respective parameter name is included in thevalidate_defaultsconstructor argument.An important consequence of this behavior is that validators need not cover a default value. For example, a parameter constraint for
path=None, whereNoneis a special value used to indicate an optional and unset value, but actually only paths are acceptable input values. can simply useEnsurePath()and it is not necessary to do something likeEnsurePath() | EnsureNone().However, EnsureCommandParameterization can also be specifically instructed to perform validation of defaults for individual parameters, as described above. A common use case is the auto-discovery of datasets, where often None is the default value of a dataset parameter (to make it optional), and an EnsureDataset constraint is used. This constraint can perform the auto-discovery (with the None value indicating that), but validation of defaults must be turned on for the dataset parameter in order to do that.
A second difference to a common
Constraintimplementation is the ability to perform an "exhaustive validation" on request (via__call__(on_error=...)). In this case, validation is not stopped at the first discovered violation, but all violations are collected and communicated by raising aCommandParametrizationErrorexception, which can be inspected by a caller for details on number and nature of all discovered violations.Exhaustive validation and joint reporting are only supported for individual constraint implementations that raise ConstraintError exceptions. For legacy constraints, any raised exception of another type are not caught and reraised immediately.
- __call__(kwargs, at_default=None, required=None, on_error='raise-early') Dict[source]
- Parameters:
kwargs (dict) -- Parameter name (
str)) to value (any) mapping of the parameter set.at_default (set or None) -- Set of parameter names where the respective values in
kwargsmatch their respective defaults. This is used for deciding whether or not to process them with an associated value constraint (see thevalidate_defaultsconstructor argument).required (set or None) -- Set of parameter names that are known to be required.
on_error ({'raise-early', 'raise-at-end'}) -- Flag how to handle constraint violation. By default, validation is stopped at the first error and an exception is raised. When an exhaustive validation is performed, an eventual exception contains information on all constraint violations. Regardless of this mode more than one error can be reported (in case (future) implementation perform independent validations in parallel).
- Raises:
CommandParametrizationError -- Raised whenever one (or more)
ConstraintErrorexceptions are caught during validation. Other exception types are not caught and pass through.
- joint_validation(params: Dict, on_error: str) Dict[source]
Higher-order validation considering multiple parameters at a time
This method is called with all, individually validated, command parameters in keyword-argument form in the
paramsdict argument.Arbitrary additional validation steps can be performed on the full set of parameters that may involve raising exceptions on validation errors, but also value transformation or replacements of individual parameters based on the setting of others.
The parameter values returned by the method are passed on to the respective command implementation.
The default implementation iterates over the
joint_validatorsspecification given to the constructor, in order to perform any number of validations. This is a mapping of aParameterConstraintContextinstance to a callable implementing a validation for a particular parameter set.Example:
_joint_validators_ = { ParameterConstraintContext(('p1', 'p2'), 'sum'): MyValidator._check_sum, } def _checksum(self, p1, p2): if (p1 + p2) < 3: self.raise_for( dict(p1=p1, p2=p2), 'parameter sum is too large', )
The callable will be passed the arguments named in the
ParameterConstraintContextas keyword arguments, using the same names as originally given toEnsureCommandParameterization.Any raised
ConstraintErroris caught and reported together with the respectiveParameterConstraintContext. The violating value reported in such aConstraintErrormust be a mapping of parameter name to value, comprising the full parameter set (i.e., keys matching theParameterConstraintContext). The use ofself.raise_for()is encouraged.If the callable anyhow modifies the passed arguments, it must return them as a kwargs-like mapping. If nothing is modified, it is OK to return
None.- Returns:
dict -- The returned dict must have a value for each item passed in via
params.on_error ({'raise-early', 'raise-at-end'}) -- Flag how to handle constraint violation. By default, validation is stopped at the first error and an exception is raised. When an exhaustive validation is performed, an eventual exception contains information on all constraint violations.
- Raises:
ConstraintErrors -- With on_error='raise-at-end' an implementation can choose to collect more than one higher-order violation and raise them as a ConstraintErrors exception.