def interval_validator(compiler, min='0s', max='365d'): """Time interval validator, convert value to seconds Supported time units: s: seconds, eg: 10s m: minutes, eg: 10m h: hours, eg: 1h d: days, eg: 7d """ try: min = parse_interval(min) except (IndexError, KeyError, ValueError): raise SchemaError('invalid min value') from None try: max = parse_interval(max) except (IndexError, KeyError, ValueError): raise SchemaError('invalid max value') from None def validate(value): try: value = parse_interval(value) except (IndexError, KeyError, ValueError): raise Invalid("invalid interval") from None if value < min: raise Invalid("interval must >= {}".format(min)) if value > max: raise Invalid("interval must <= {}".format(max)) return value return validate
def _parse_fields(fields, extra_fields): """ >>> fields, extra_fields = _parse_fields('a,b', ''' c d ... e''') >>> fields == {'a', 'b'} True >>> extra_fields == {'c', 'd', 'e'} True >>> _parse_fields('a,b', 'b,c,d') Traceback (most recent call last): ... validr._exception_c.SchemaError: duplicated fields b """ def _parse_one(text, error_message): if not text: return set() try: text = text.strip() except (TypeError, AttributeError): raise SchemaError(error_message) from None return set(text.replace(',', ' ').split()) fields = _parse_one(fields, 'invalid fields') extra_fields = _parse_one(extra_fields, 'invalid extra_fields') if (not fields) and (not extra_fields): raise SchemaError("no fields provided") duplicated_fields = ','.join(fields & extra_fields) if duplicated_fields: raise SchemaError(f"duplicated fields {duplicated_fields}") return fields, extra_fields
def url_validator(compiler, scheme='http https', default_schema=None, maxlen=1024, relaxed=False): """ Args: default_schema: 接受没有scheme的url并尝试修正 relaxed: accept not strict url """ if relaxed: return Compiler().compile(T.url.maxlen(maxlen).scheme(scheme)) schemes = set(scheme.replace(',', ' ').split(' ')) if default_schema and default_schema not in schemes: raise SchemaError('invalid default_schema {}'.format(default_schema)) _django_validate_url = URLValidator(schemes=schemes) def validate(value): if default_schema: value = coerce_url(value, default_schema=default_schema) try: _django_validate_url(value) except ValidationError: # TODO: access ValidationError.messages will cause error when # django/i18n not setup, maybe use validators package instead # raise Invalid(','.join(ex.messages).rstrip('.')) raise Invalid('invalid or incorrect url format') if len(value) > maxlen: raise Invalid(f'url length must <= {maxlen}') return value return validate
def cursor_validator(compiler, keys=None, output_object=False, base64=False): """Cursor: k1:v1,k2:v2""" if keys: try: keys = set(keys.strip().replace(',', ' ').split()) except (TypeError, ValueError): raise SchemaError('invalid cursor keys') def validate(value): try: if not isinstance(value, Cursor): if base64: value = urlsafe_b64decode(value.encode('ascii')).decode('utf-8') value = Cursor.from_string(value, keys) else: value._check_missing_keys(keys) except (UnicodeEncodeError, UnicodeDecodeError, ValueError) as ex: raise Invalid(str(ex)) from None if output_object: return value value = str(value) if base64: value = urlsafe_b64encode(value.encode('utf-8')).decode() return value return validate
def _parse_doc(doc, mark): """ Parse YAML syntax data from doc if doc is None, return ('', OrderedDict()) if doc has no YAML data, return (doc, OrderedDict()) else, parse YAML data, return (doc, data) Args: doc (str): doc to be parsed mark (Regex): which marks the start position of data Returns: tuple(desc, data): data is an OrderedDict contains information of doc """ if doc is None: return '', OrderedDict() match = mark.search(doc) if not match: return textwrap.dedent(doc).strip(), OrderedDict() start = match.start() yamltext = textwrap.dedent(doc[start:]) try: data = yaml.load(yamltext) except yaml.parser.ParserError as ex: raise SchemaError(str(ex)) from None return textwrap.dedent(doc[:start]).strip(), data
def _parse_one(text, error_message): if not text: return set() try: text = text.strip() except (TypeError, AttributeError): raise SchemaError(error_message) from None return set(text.replace(',', ' ').split())