Source code for kerno.colander

"""Convenience to use colander with kerno."""

import colander as c

from kerno.state import MalbonaRezulto
from kerno.typing import DictStr

_ = str  # TODO add i18n


[docs]def validate_schema( schema: c.SchemaType, adict: DictStr, mal_title: str = _("Validation error"), mal_plain: str = _("The data do not pass server validation."), ) -> DictStr: """Conveniently validate a colander schema and return the clean dict. But if colander.Invalid is raised, put it inside a MalbonaRezulto. """ try: return schema.deserialize(adict) except c.Invalid as e: malbona = MalbonaRezulto() malbona.add_toast(title=mal_title, plain=mal_plain) malbona.invalid = e.asdict() raise malbona
[docs]class InvalidToMalbona: """Context manager that wraps colander's Invalid in a MalbonaRezulto.""" def __init__( self, title: str = _("Validation error"), plain: str = _("The data do not pass server validation."), html: str = "", ) -> None: # noqa self.title = title self.plain = plain self.html = html def __enter__(self): pass def __exit__(self, exc_type, exc_val, exc_tb): if isinstance(exc_val, c.Invalid): malbona = MalbonaRezulto() malbona.add_toast( title=self.title, plain=self.plain, html=self.html ) malbona.invalid = exc_val.asdict() raise malbona
[docs]class NumLines: """Colander validator that checks the number of lines in text.""" def __init__( self, min: int = 0, max: int = -1, min_err: str = "Not enough lines (minimum {min})", max_err: str = "Too many lines (maximum {max})", ) -> None: # noqa self.min = min self.max = max self.min_err = min_err self.max_err = max_err def __call__(self, node, value) -> None: # noqa num_lines = value.count("\n") + 1 if self.min > 0 and num_lines < self.min: # err = _(self.min_err, mapping={"min": self.min}) raise c.Invalid(node, self.min_err.format(min=self.min)) if self.max > -1 and num_lines > self.max: # err = _(self.max_err, mapping={"max": self.max}) raise c.Invalid(node, self.max_err.format(max=self.max))
[docs]class IsWeb: """Colander validator: ensure starts with "http://" or "https://".""" def __init__(self, msg: str = 'Must start with "http://" or "https://".'): self.msg = msg def __call__(self, node, value) -> None: # noqa if not (value.startswith("http://") or value.startswith("https://")): raise c.Invalid(node, self.msg)
[docs]def no_scripts(node, val: str) -> None: """Colander validator: forbid script tags in the value.""" if "<script" in val: raise c.Invalid(node=node, value=val, msg="No scripts are allowed!")