Coverage for /opt/conda/envs/apienv/lib/python3.10/site-packages/daiquiri/core/schema/validators.py: 77%
47 statements
« prev ^ index » next coverage.py v7.6.5, created at 2024-11-15 02:12 +0000
« prev ^ index » next coverage.py v7.6.5, created at 2024-11-15 02:12 +0000
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3from marshmallow import validate, fields, ValidationError
4import bleach
6"""Custom Schema Validators
8 https://json-schema.org/understanding-json-schema/reference/string.html
9"""
12def ValidatedRegexp(pattern, **kwargs):
13 """A regexp validated fields.Str
15 Args:
16 pattern: the pattern to use from the above dictionary
17 Kwargs:
18 passed to the `field`
19 """
21 expressions = {
22 "word": "^[A-z0-9]+$",
23 "word-dash": "^[A-z0-9-]+$",
24 "word-dash-space": r"^[\w\s-]+$",
25 "word-special": r"^(\w|\s|-|%|\(|\)|,|\.)+$",
26 "saving": "^({(sample|component|subsampletype|subsampleid)}|[A-z0-9/-])+$",
27 "smiles": r"^([^J][A-Za-z0-9@+\-\[\]\(\)\\\/%=#$]+)$",
28 "path": "^/[A-z0-9-/]+$",
29 }
31 if pattern in expressions:
32 validates = kwargs.pop("validate", None)
33 if validates and not isinstance(validates, list):
34 validates = [validates]
36 metadata = kwargs.pop("metadata", {})
37 metadata["pattern"] = expressions[pattern]
39 return fields.Str(
40 validate=[
41 validate.Regexp(
42 expressions[pattern],
43 flags=0,
44 error="Input {input} does not match {regex}",
45 )
46 ]
47 + (validates if validates else []),
48 metadata=metadata,
49 **kwargs
50 )
51 else:
52 raise Exception("Cant find regular expression for {pat}".format(pat=pattern))
55class Any(fields.Field):
56 """Mixed field"""
58 def _jsonschema_type_mapping(self):
59 return {"type": "any", "title": self.name}
62class NoneValidator(validate.Validator):
63 """Validator that requires the field is None"""
65 def __call__(self, val):
66 if val is not None:
67 raise ValidationError("Field must be empty")
69 return val
72class EmptyField(fields.Field):
73 """Custom empty field type"""
75 def _jsonschema_type_mapping(self):
76 return {"type": "empty", "title": self.name}
79def RequireEmpty(**kwargs):
80 """A RequireEmpty field
82 Requires that this particular field is empty by combining NoneValidator and EmptyField
83 """
84 return EmptyField(validate=NoneValidator(), allow_none=True, **kwargs)
87def OneOf(choices, **kwargs):
88 """Single enum type validator
90 Args:
91 choices (list): List of choices
92 """
93 metadata = kwargs.pop("metadata", {})
94 metadata["enum"] = choices
96 return fields.Str(metadata=metadata, validate=validate.OneOf(choices), **kwargs)
99class SanitizedHTML(fields.Str):
100 """A Sanitised HTML string
102 bleach.cleaned HTML string field
103 """
105 def __init__(self, *args, **kwargs):
106 self._strip = kwargs.pop("strip", None)
107 self._load = kwargs.pop("load", None)
108 self._linkify = kwargs.pop("linkify", None)
110 super().__init__(*args, **kwargs)
112 def _serialize(self, value, attr, obj, **kwargs):
113 if value is None:
114 return None
116 if self._load:
117 value = bleach.clean(value, strip=self._strip)
119 if self._linkify:
120 value = bleach.linkify(value)
122 return super()._serialize(value, attr, obj, **kwargs)
124 def _deserialize(self, value, attr, data, **kwargs):
125 value = bleach.clean(value, strip=self._strip)
126 return super()._deserialize(value, attr, data, **kwargs)