def validate(self, value: str | None, path: list[str], **kwargs: Any) -> str | None: """ Currently only validates by running urlparse against it and checking that a scheme and netloc is set - and if a list of allowed schemes is provide that the scheme is valid against that list TODO: may want something more sophisticated than that - could look at django's url validator """ value = super().validate(value, path, **kwargs) if value == "" and self.blank: return value if value is None and self.default_is_none: return value try: result = urlparse(value) except ValueError: raise ValidationError(self, path, value, "url expected") if not result.scheme: raise ValidationError(self, path, value, "no url scheme specified") if not result.netloc: raise ValidationError(self, path, value, "no url netloc specified") if self.schemes and result.scheme not in self.schemes: raise ValidationError(self, path, value, f"invalid url scheme: {result.scheme}") return value
def validate(self, value: Any, path: list[str], **kwargs: Any) -> Any: """ Validate a value for this attribute Will raise a `ValidationError` or `ValidationWarning` exception on validation failure **Arguments** - value (`mixed`): the value to validate - path (`list`): current path in the config schema, this is mostly used to identify where an error occured when validating against config data, you can pass an empty list to it when calling this manually """ if not self.container and not self.name: raise ValidationError( self, path, value, "attribute at top level defined without a name") if self.choices_handler: if value not in self.choices: raise ValidationError(self, path, value, "invalid choice") return value
def validate(self, config, path=None, errors=None, warnings=None): """ Validate config data against this schema **Attributes** - config (`dict`): config to validate **Keyword Attributes** - path (`list`): current path in the config data, this can be ignored on the initial call and will be set automatically on any subsequent calls (nested schemas) - errors (`ValidationErrorProcessor`) - warnigns (`ValidationErrorProcessor`) """ if path is None: path = [] if errors is None: errors = ValidationErrorProcessor() if warnings is None: warnings = ValidationErrorProcessor() # munge Config support without having to import munge if isinstance(config, collections.MutableMapping) and hasattr( config, "data"): config = config.data elif isinstance(config, configparser.ConfigParser): config = config_parser_dict(config) if not isinstance(config, dict): return errors.error( ValidationError(path[-1], path, config, "dictionary expected")) for key, value in config.items(): try: attribute = self._attr.get(key, self.item) if attribute is None: raise ValidationWarning( key, path, value, "unknown attribute '{}'".format(key)) else: config[key] = attribute.validate(value, path + [key], errors=errors, warnings=warnings) except ValidationError as error: errors.error(error) except ValidationWarning as warning: warnings.warning(warning) for name, attribute in self.attributes(): if name not in config and not attribute.has_default: errors.error( ValidationError(attribute, path + [name], None, "missing")) return config
def validate(self, value, path, **kwargs): if not isinstance(value, six.string_types) and not self.default_is_none: raise ValidationError(self, path, value, "string expected") if value == "" and not self.blank: raise ValidationError(self, path, value, "cannot be blank") return super(Str, self).validate(value, path, **kwargs)
def validate( self, value: str | None, path: list[str], **kwargs: Any, ) -> str | None: if not isinstance(value, str) and not self.default_is_none: raise ValidationError(self, path, value, "string expected") if value == "" and not self.blank: raise ValidationError(self, path, value, "cannot be blank") return super().validate(value, path, **kwargs)
def validate( self, value: list | str, path: list[str], **kwargs: Any, ) -> Any: if isinstance(value, str): value = value.split(",") if not isinstance(value, list): raise ValidationError(self, path, value, "list expected") errors = kwargs.get("errors", ValidationErrorProcessor()) warnings = kwargs.get("warnings", ValidationErrorProcessor()) validated = [] idx = 0 for item in value: try: if isinstance(self.item, Schema): validated.append( self.item.validate(item, path + [idx], errors=errors, warnings=warnings)) else: validated.append(self.item.validate(item, path + [idx])) idx += 1 except ValidationError as error: errors.error(error) except ValidationWarning as warning: warnings.warning(warning) return super().validate(validated, path, **kwargs)
def validate(self, value, path, **kwargs): value = super(Directory, self).validate(value, path, **kwargs) if value is None and self.default_is_none: return value # make sure env vars get expanded value = os.path.expandvars(value) # if value is blank, and validation was not caught by `blank` validation # of Str we forfeit validation and it is assume that the application # will validate manually once the path is set. if value == "": return value # make sure user vars get expanded value = os.path.expanduser(value) # expand to absolute path value = os.path.abspath(value) if self.create is not None and not os.path.exists(value): self.makedir(value, path) if self.require_exist: valid = os.path.exists(value) and os.path.isdir(value) else: valid = True if not valid: raise ValidationError( self, path, value, "valid path to directory expected: {}".format(value)) return value
def validate(self, value: str | None, path: list[str], **kwargs: Any) -> str | None: value = super().validate(value, path, **kwargs) if value is None and self.default_is_none: return value if value == "" and self.blank: return value # make sure env vars get expanded value = os.path.expandvars(value) # make sure user vars get expanded value = os.path.expanduser(value) # expand to absolute path value = os.path.abspath(value) valid = (os.path.exists(value) or not self.require_exist) and not os.path.isdir(value) if not valid: raise ValidationError(self, path, value, "file does not exist") return value
def validate(self, value, path, **kwargs): if value is None and self.default_is_none: return value try: value = float(value) except (TypeError, ValueError): raise ValidationError(self, path, value, "float expected") return super(Float, self).validate(value, path, **kwargs)
def validate(self, value: float | str | None, path: list[str], **kwargs: Any) -> float | None: if value is None and self.default_is_none: return value try: value = float(value) except (TypeError, ValueError): raise ValidationError(self, path, value, "float expected") return super().validate(value, path, **kwargs)
def validate(self, value, path, **kwargs): if isinstance(value, str): if value.lower() in self.true_values: value = True elif value.lower() in self.false_values: value = False else: raise ValidationError(self, path, value, "boolean expected") return super(Bool, self).validate(bool(value), path, **kwargs)
def validate(self, value: int | str, path: list[str], **kwargs: Any) -> bool: if isinstance(value, str): if value.lower() in self.true_values: value = True elif value.lower() in self.false_values: value = False else: raise ValidationError(self, path, value, "boolean expected") return super().validate(bool(value), path, **kwargs)
def validate(self, value: str | None, path: list[str], **kwargs: Any) -> Any: value = super().validate(value, path, **kwargs) if value is None and self.default_is_none: return value if self.blank and value == "": return value value = f"{value}" value_v4 = self.validate_v4(value, path, **kwargs) value_v6 = self.validate_v6(value, path, **kwargs) if self.protocol == 4 and not value_v4: raise ValidationError(self, path, value, "invalid ip (v4)") elif self.protocol == 6 and not value_v6: raise ValidationError(self, path, value, "invalid ip (v6)") elif self.protocol is None and not value_v4 and not value_v6: raise ValidationError(self, path, value, "invalid ip (v4 or v6)") return value_v4 or value_v6
def makedir(self, value: str, config_path: list[str]) -> None: try: os.makedirs(value, self.create) except Exception as err: raise ValidationError( self, config_path, value, "tried to create directory but failed with error" ": {}".format(err), )
def validate( self, value: types.TimeDuration | float | str | None, path: list[str], **kwargs: Any, ) -> TimeDuration: if value is None and self.default_is_none: return value try: value = types.TimeDuration(value) except (TypeError, ValueError): raise ValidationError(self, path, value, "TimeDuration expected") return super().validate(value, path, **kwargs)
def validate(self, value: str | None, path: list[str], **kwargs: Any) -> str | None: value = super().validate(value, path, **kwargs) if value == "" and self.blank: return value if value is None and self.default_is_none: return value # TODO: any reason to get more sophisticated than this? if not re.match(r"[^@\s]+@[^@\s]+", value): raise ValidationError(self, path, value, "email address expected") return value
def test_attribute(Class, value_pass, validated, value_fail, init): attribute = Class("test", **init) assert attribute.validate(value_pass, []) == validated if value_fail is not None: with pytest.raises(ValidationError): attribute.validate(value_fail, []) @pytest.mark.parametrize( "SchemaClass,config_pass,config_fail,error", [ ( Schema_01, "nesting/success.json", "nesting/failure01.json", ValidationError(None, ["nested", "int_attr"], "test", "integer expected"), ), ( Schema_01, "nesting/success.json", "nesting/failure02.json", ValidationError(None, ["nested"], [1, 2, 3], "dictionary expected"), ), ( Schema_01, "nesting/success.json", "nesting/failure03.json", ValidationError(None, ["list_attr", 0], 1, "dictionary expected"), ), (