Mercurial > repos > shellac > guppy_basecaller
diff env/lib/python3.7/site-packages/schema_salad/validate.py @ 2:6af9afd405e9 draft
"planemo upload commit 0a63dd5f4d38a1f6944587f52a8cd79874177fc1"
author | shellac |
---|---|
date | Thu, 14 May 2020 14:56:58 -0400 |
parents | 26e78fe6e8c4 |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/env/lib/python3.7/site-packages/schema_salad/validate.py Thu May 14 14:56:58 2020 -0400 @@ -0,0 +1,462 @@ +from __future__ import absolute_import + +import logging +import pprint +from typing import ( # noqa: F401 + Any, + List, + MutableMapping, + MutableSequence, + Optional, + Set, + Union, +) + +import six +from six.moves import urllib +from typing_extensions import Text # pylint: disable=unused-import + +from . import avro +from .exceptions import ( + ClassValidationException, + ValidationException, + SchemaSaladException, +) +from .avro import schema # noqa: F401 +from .avro.schema import ( # pylint: disable=unused-import, no-name-in-module, import-error + Schema, +) +from .sourceline import SourceLine + +# move to a regular typing import when Python 3.3-3.6 is no longer supported + + +_logger = logging.getLogger("salad") + + +def validate( + expected_schema, # type: Schema + datum, # type: Any + identifiers=None, # type: Optional[List[Text]] + strict=False, # type: bool + foreign_properties=None, # type: Optional[Set[Text]] +): + # type: (...) -> bool + if not identifiers: + identifiers = [] + if not foreign_properties: + foreign_properties = set() + return validate_ex( + expected_schema, + datum, + identifiers, + strict=strict, + foreign_properties=foreign_properties, + raise_ex=False, + ) + + +INT_MIN_VALUE = -(1 << 31) +INT_MAX_VALUE = (1 << 31) - 1 +LONG_MIN_VALUE = -(1 << 63) +LONG_MAX_VALUE = (1 << 63) - 1 + + +def friendly(v): # type: (Any) -> Any + if isinstance(v, avro.schema.NamedSchema): + return v.name + if isinstance(v, avro.schema.ArraySchema): + return "array of <{}>".format(friendly(v.items)) + elif isinstance(v, avro.schema.PrimitiveSchema): + return v.type + elif isinstance(v, avro.schema.UnionSchema): + return " or ".join([friendly(s) for s in v.schemas]) + else: + return v + + +def vpformat(datum): # type: (Any) -> str + a = pprint.pformat(datum) + if len(a) > 160: + a = a[0:160] + "[...]" + return a + + +def validate_ex( + expected_schema, # type: Schema + datum, # type: Any + identifiers=None, # type: Optional[List[Text]] + strict=False, # type: bool + foreign_properties=None, # type: Optional[Set[Text]] + raise_ex=True, # type: bool + strict_foreign_properties=False, # type: bool + logger=_logger, # type: logging.Logger + skip_foreign_properties=False, # type: bool +): + # type: (...) -> bool + """Determine if a python datum is an instance of a schema.""" + + if not identifiers: + identifiers = [] + + if not foreign_properties: + foreign_properties = set() + + schema_type = expected_schema.type + + if schema_type == "null": + if datum is None: + return True + else: + if raise_ex: + raise ValidationException(u"the value is not null") + else: + return False + elif schema_type == "boolean": + if isinstance(datum, bool): + return True + else: + if raise_ex: + raise ValidationException(u"the value is not boolean") + else: + return False + elif schema_type == "string": + if isinstance(datum, six.string_types): + return True + elif isinstance(datum, bytes): + datum = datum.decode(u"utf-8") + return True + else: + if raise_ex: + raise ValidationException(u"the value is not string") + else: + return False + elif schema_type == "int": + if ( + isinstance(datum, six.integer_types) + and INT_MIN_VALUE <= datum <= INT_MAX_VALUE + ): + return True + else: + if raise_ex: + raise ValidationException(u"`{}` is not int".format(vpformat(datum))) + else: + return False + elif schema_type == "long": + if ( + isinstance(datum, six.integer_types) + ) and LONG_MIN_VALUE <= datum <= LONG_MAX_VALUE: + return True + else: + if raise_ex: + raise ValidationException( + u"the value `{}` is not long".format(vpformat(datum)) + ) + else: + return False + elif schema_type in ["float", "double"]: + if isinstance(datum, six.integer_types) or isinstance(datum, float): + return True + else: + if raise_ex: + raise ValidationException( + u"the value `{}` is not float or double".format(vpformat(datum)) + ) + else: + return False + elif isinstance(expected_schema, avro.schema.EnumSchema): + if expected_schema.name == "Any": + if datum is not None: + return True + else: + if raise_ex: + raise ValidationException(u"'Any' type must be non-null") + else: + return False + if not isinstance(datum, six.string_types): + if raise_ex: + raise ValidationException( + u"value is a {} but expected a string".format( + (type(datum).__name__) + ) + ) + else: + return False + if expected_schema.name == "Expression": + if "$(" in datum or "${" in datum: + return True + if raise_ex: + raise ValidationException( + u"value `%s` does not contain an expression in the form $() or ${}" + % datum + ) + else: + return False + if datum in expected_schema.symbols: + return True + else: + if raise_ex: + raise ValidationException( + u"the value {} is not a valid {}, expected {}{}".format( + vpformat(datum), + expected_schema.name, + "one of " if len(expected_schema.symbols) > 1 else "", + "'" + "', '".join(expected_schema.symbols) + "'", + ) + ) + else: + return False + elif isinstance(expected_schema, avro.schema.ArraySchema): + if isinstance(datum, MutableSequence): + for i, d in enumerate(datum): + try: + sl = SourceLine(datum, i, ValidationException) + if not validate_ex( + expected_schema.items, + d, + identifiers, + strict=strict, + foreign_properties=foreign_properties, + raise_ex=raise_ex, + strict_foreign_properties=strict_foreign_properties, + logger=logger, + skip_foreign_properties=skip_foreign_properties, + ): + return False + except ValidationException as v: + if raise_ex: + raise ValidationException("item is invalid because", sl, [v]) + else: + return False + return True + else: + if raise_ex: + raise ValidationException( + u"the value {} is not a list, expected list of {}".format( + vpformat(datum), friendly(expected_schema.items) + ) + ) + else: + return False + elif isinstance(expected_schema, avro.schema.UnionSchema): + for s in expected_schema.schemas: + if validate_ex( + s, + datum, + identifiers, + strict=strict, + raise_ex=False, + strict_foreign_properties=strict_foreign_properties, + logger=logger, + skip_foreign_properties=skip_foreign_properties, + ): + return True + + if not raise_ex: + return False + + errors = [] # type: List[SchemaSaladException] + checked = [] + for s in expected_schema.schemas: + if isinstance(datum, MutableSequence) and not isinstance( + s, avro.schema.ArraySchema + ): + continue + elif isinstance(datum, MutableMapping) and not isinstance( + s, avro.schema.RecordSchema + ): + continue + elif isinstance( + datum, (bool, six.integer_types, float, six.string_types) + ) and isinstance(s, (avro.schema.ArraySchema, avro.schema.RecordSchema)): + continue + elif datum is not None and s.type == "null": + continue + + checked.append(s) + try: + validate_ex( + s, + datum, + identifiers, + strict=strict, + foreign_properties=foreign_properties, + raise_ex=True, + strict_foreign_properties=strict_foreign_properties, + logger=logger, + skip_foreign_properties=skip_foreign_properties, + ) + except ClassValidationException: + raise + except ValidationException as e: + errors.append(e) + if bool(errors): + raise ValidationException( + "", + None, + [ + ValidationException( + "tried {} but".format(friendly(check)), None, [err] + ) + for (check, err) in zip(checked, errors) + ], + "-", + ) + else: + raise ValidationException( + "value is a {}, expected {}".format( + type(datum).__name__, friendly(expected_schema) + ) + ) + + elif isinstance(expected_schema, avro.schema.RecordSchema): + if not isinstance(datum, MutableMapping): + if raise_ex: + raise ValidationException(u"is not a dict") + else: + return False + + classmatch = None + for f in expected_schema.fields: + if f.name in ("class",): + d = datum.get(f.name) + if not d: + if raise_ex: + raise ValidationException(u"Missing '{}' field".format(f.name)) + else: + return False + if expected_schema.name != d: + if raise_ex: + raise ValidationException( + u"Expected class '{}' but this is '{}'".format( + expected_schema.name, d + ) + ) + else: + return False + classmatch = d + break + + errors = [] + for f in expected_schema.fields: + if f.name in ("class",): + continue + + if f.name in datum: + fieldval = datum[f.name] + else: + try: + fieldval = f.default + except KeyError: + fieldval = None + + try: + sl = SourceLine(datum, f.name, six.text_type) + if not validate_ex( + f.type, + fieldval, + identifiers, + strict=strict, + foreign_properties=foreign_properties, + raise_ex=raise_ex, + strict_foreign_properties=strict_foreign_properties, + logger=logger, + skip_foreign_properties=skip_foreign_properties, + ): + return False + except ValidationException as v: + if f.name not in datum: + errors.append( + ValidationException( + u"missing required field `{}`".format(f.name) + ) + ) + else: + errors.append( + ValidationException( + u"the `{}` field is not valid because".format(f.name), + sl, + [v], + ) + ) + + for d in datum: + found = False + for f in expected_schema.fields: + if d == f.name: + found = True + if not found: + sl = SourceLine(datum, d, six.text_type) + if d is None: + err = ValidationException(u"mapping with implicit null key", sl) + if strict: + errors.append(err) + else: + logger.warning(err) + continue + if ( + d not in identifiers + and d not in foreign_properties + and d[0] not in ("@", "$") + ): + if ( + (d not in identifiers and strict) + and ( + d not in foreign_properties + and strict_foreign_properties + and not skip_foreign_properties + ) + and not raise_ex + ): + return False + split = urllib.parse.urlsplit(d) + if split.scheme: + if not skip_foreign_properties: + err = ValidationException( + u"unrecognized extension field `{}`{}.{}".format( + d, + " and strict_foreign_properties checking is enabled" + if strict_foreign_properties + else "", + "\nForeign properties from $schemas:\n {}".format( + "\n ".join(sorted(foreign_properties)) + ) + if len(foreign_properties) > 0 + else "", + ), + sl, + ) + if strict_foreign_properties: + errors.append(err) + elif len(foreign_properties) > 0: + logger.warning(err) + else: + err = ValidationException( + u"invalid field `{}`, expected one of: {}".format( + d, + ", ".join( + "'{}'".format(fn.name) + for fn in expected_schema.fields + ), + ), + sl, + ) + if strict: + errors.append(err) + else: + logger.warning(err) + + if bool(errors): + if raise_ex: + if classmatch: + raise ClassValidationException("", None, errors, "*") + else: + raise ValidationException("", None, errors, "*") + else: + return False + else: + return True + if raise_ex: + raise ValidationException(u"Unrecognized schema_type {}".format(schema_type)) + else: + return False