Ejemplo n.º 1
0
def required_draft4(validator, required, instance, schema):
    if not validator.is_type(instance, "object"):
        return
    for property in required:
        if property not in instance:
            error = ValidationError("%r is a required property" % property)
            error._set(validator="required", validator_value=required, instance=instance, schema=schema)
            error.path.appendleft(property)
            error.schema_path.extend([property, "required"])
            yield error
Ejemplo n.º 2
0
def properties_draft3(validator, properties, instance, schema):
    if not validator.is_type(instance, "object"):
        return

    for property, subschema in iteritems(properties):
        if property in instance:
            for error in validator.descend(instance[property], subschema, path=property, schema_path=property):
                yield error
        elif subschema.get("required", False):
            error = ValidationError("%r is a required property" % property)
            error._set(validator="required", validator_value=subschema["required"], instance=instance, schema=schema)
            error.path.appendleft(property)
            error.schema_path.extend([property, "required"])
            yield error
Ejemplo n.º 3
0
def type(validator, data_type, instance, schema):
    if instance is None:
        return

    if not validator.is_type(instance, data_type):
        yield ValidationError("%r is not of type %s" % (instance, data_type))
Ejemplo n.º 4
0
def is_date(validator, value, instance, schema_profile_data):
    try:
        datetime.datetime.strptime(instance, '%Y-%m-%d')
    except ValueError:
        yield ValidationError("%r incorrect birth date format" % (instance))
Ejemplo n.º 5
0
def not_draft4(validator, not_schema, instance, schema):
    if validator.is_valid(instance, not_schema):
        yield ValidationError("%r is not allowed for %r" %
                              (not_schema, instance))
Ejemplo n.º 6
0
def minProperties_draft4(validator, mP, instance, schema):
    if validator.is_type(instance, "object") and len(instance) < mP:
        yield ValidationError("%r does not have enough properties" %
                              (instance, ))
Ejemplo n.º 7
0
def type_draft4(validator, types, instance, schema):
    types = _utils.ensure_list(types)

    if not any(validator.is_type(instance, type) for type in types):
        yield ValidationError(_utils.types_msg(instance, types))
Ejemplo n.º 8
0
def enum(validator, enums, instance, schema):
    if instance not in enums:
        yield ValidationError("%r is not one of %r" % (instance, enums))
Ejemplo n.º 9
0
def minLength(validator, mL, instance, schema):
    if validator.is_type(instance, "string") and len(instance) < mL:
        yield ValidationError("%r is too short" % (instance, ))
Ejemplo n.º 10
0
def getValidatedValue(token, value, **kwargs):
    '''
    Returns the provided value if it passed a validation laboratory against the token's
    model schema or ``None`` if the laboratory failed. Please refer to 
    http://json-schema.org/documentation.html or 
    https://spacetelescope.github.io/understanding-json-schema for more insights on JSON schema.
    :param str token: The token
    :param value: The value
    :returns value: The provided value if valid or ``None`` if validation failed
    '''
    # Only for private functions that require an exception instead of ``None`` as return value
    exception = bool(kwargs.get('exception')) or False

    try:
        # This will be a temporarily copy of the value to validate (in a prepared form)
        dataobject = None

        # Get the domain and key from the provided token
        try:
            domain, key = str(token).split('.', 1)
        except ValueError:
            domain = str(token).split('.', 1)[0]
            key = False

        # Get the default class
        cls = locate(f'{__package__}.{domain}')

        # Validate a value against a sub-schema (of a schema module in freedm.models)
        if cls and key:
            tokens = key.split('.')

            # In case of the following tokens: "model.+"
            if len(tokens) >= 1 and tokens[0] == '+':
                # Recursively check the values with a token where '+' is substituted
                checks = []
                for v in value:
                    k = next(iter(v))
                    checks.append(
                        getValidatedValue(f'{domain}.{k}',
                                          v[k],
                                          exception=True))
                # Check for an exception
                if any(isinstance(e, Exception) for e in checks):
                    value = ([e for e in checks if isinstance(e, Exception)]
                             if exception else None)

            # In case of the following tokens: "model.property"
            elif len(tokens) >= 1 and tokens[0] in (
                (cls.get('properties') or cls)
                    if isinstance(cls, dict) else cls.__dict__):
                # Get data schema
                schema = (cls.get('properties')
                          or cls)[tokens.pop(0)] if isinstance(
                              cls, dict) else getattr(cls, tokens.pop(0))

                # Traverse through subschemas for each token
                for i, t in enumerate(tokens):
                    # Get index position
                    last = (len(tokens) - i) == 1

                    # Try to find a sub-schema definition for current key token
                    try:
                        # 1st possibility: Value is member of a collection
                        if (t.isdigit() or t
                                == '[]') and schema.get('type') == 'array':
                            # We use the previous schema again
                            if last and schema.get('type') == 'array':
                                obj = schema
                            # Try to find the correct items or properties sub-schema
                            else:
                                obj = schema.get('items')

                        # 2nd possibility: Value is a wildcard collection. Iteratively check each item
                        elif t == '+':
                            # Recursively check the values with a token where '+' is substituted
                            checks = []
                            token_prev_part = f'{domain}.{".".join(key.split(".")[:i+1])}'
                            token_next_part = '.'.join(
                                key.split('.')[i + 2:] if not last else '')
                            token_placeholder = '.'.join([
                                p for p in
                                [token_prev_part, '{}', token_next_part]
                                if p != ''
                            ])

                            if hasattr(value, '__iter__'):
                                for v in value:
                                    # If the values are dictionaries
                                    if isinstance(v, dict):
                                        # If the "+" was the last key token and the dictionary has more than one key like {a:1, b:2,...},
                                        # then we should not substitute the "+" but rather remove and check the whole structure
                                        if last and len(v.keys()) > 1:
                                            checks.append(
                                                getValidatedValue(
                                                    token_placeholder.replace(
                                                        '.{}', ''),
                                                    v,
                                                    exception=True))
                                        # Do a normal check by substituting the "+ for instance by "[]" or the one and only key in the dictionary
                                        else:
                                            # Get the key of the value
                                            value_key = next(iter(v))
                                            # 1st check: Assume we can replace "+" by the value key
                                            check_token = token_placeholder.format(
                                                value_key)
                                            check_result = getValidatedValue(
                                                check_token,
                                                v[value_key],
                                                exception=True)
                                            # 2nd check: Assume we must replace "+" by a collection "[]"
                                            if (isinstance(check_result, list)
                                                    and any(
                                                        isinstance(
                                                            r, Exception)
                                                        for r in check_result)
                                                ) or isinstance(
                                                    check_result, Exception):
                                                check_token = token_placeholder.format(
                                                    '[]')
                                                # Save 2nd check result
                                                checks.append(
                                                    getValidatedValue(
                                                        check_token, [v],
                                                        exception=True))
                                            # 1st check has succeeded
                                            else:
                                                checks.append(check_result)
                                    # If the values are lists
                                    elif isinstance(v, list):
                                        check_token = token_placeholder.format(
                                            '[]')
                                        checks.append(
                                            getValidatedValue(check_token,
                                                              v,
                                                              exception=True))
                                    # If the values are for instance strings
                                    else:
                                        check_token = token_placeholder.format(
                                            '[]')
                                        check_result = getValidatedValue(
                                            check_token, v, exception=True)
                                        checks.append(check_result)
                                        if isinstance(check_result, Exception):
                                            break  # Do not check more than one single character of a string when the token already fails
                            else:
                                check_token = token_placeholder.format('[]')
                                checks.append(
                                    getValidatedValue(check_token,
                                                      value,
                                                      exception=True))

                            # Check for an exception
                            if any(isinstance(e, Exception) for e in checks):
                                value = ([
                                    e for e in checks
                                    if isinstance(e, Exception)
                                ] if exception else None)
                            # We stop at this moment as we just validated the wildcard results separately in recursive steps
                            return

                        # 3rd possibility: Value refers to a single property, and is not member of a collection
                        else:
                            # Try to get sub-schema
                            obj = schema.get(t)
                            # Did not work? Try sub-schema definitions (properties/items)
                            if obj is None:
                                p = schema.get('properties')
                                i = schema.get('items')
                                if p:
                                    obj = p.get(t)
                                elif i:
                                    if isinstance(i, dict):
                                        obj = i.get('properties').get(t)

                            # This is a last check for special situation where we refer to one item in a previous collection "[]"
                            # The key token also must be a digit number and no schema found yet.
                            if obj is None and '[]' in token and t.isdigit():
                                obj = schema

                        # Set found schema or raise an exception
                        if obj is not None:
                            schema = obj
                        else:
                            raise Exception

                    # Or try using the last schema we found for the previous token
                    except:
                        if schema.__contains__(
                                'additionalProperties'
                        ) and schema.get('additionalProperties') is False:
                            # We reset the value to None because new additional properties are not allowed
                            if exception:
                                value = ValidationError(
                                    'No validation schema found for token "{}" and new schema properties not allowed by model'
                                )
                            else:
                                value = None
                                raise UserWarning(
                                    f'No validation schema found for token "{token}" and model "{domain}" does not allow new schema properties'
                                )
                        else:
                            if schema.get('type') == 'object':
                                # We warn the user but as we have additionalProperties allowed (object's default), we continue using the value with the new token
                                raise UserWarning(
                                    f'No validation schema found for token "{token}". Define model schema in "freedm.models.{domain}.py"'
                                )
                            else:
                                # Validate against the last schema we found
                                raise ValidationError(
                                    f'Token "{t}" refers to invalid sub-element to property of type "{schema.get("type")}"'
                                )

                # Prepare the data (To get rid of dictionaries with numeric keys)
                dataobject = __prepareCollectionObject(value)

                # Make sure that single members of a collection (=Token must contain a number) are properly packed for validation
                if schema.get('type') == 'array' and any(
                        d in token for d in '0123456789') and not isinstance(
                            dataobject, list):
                    # Value is a single collection element, we need to pack it in a list
                    validate([dataobject], schema)
                # Make sure that all single items in a collection are each individually checked against the schema
                elif schema.get(
                        'type') != 'array' and '[]' in token and isinstance(
                            dataobject, list):
                    # Validate each element individually
                    for v in dataobject:
                        validate(v, schema)
                # The normal case where a value is checked against its schema
                else:
                    validate(dataobject, schema)
            else:
                raise UserWarning(
                    f'No validation schema found for token "{domain}.{tokens[0]}.*". Define schema in "freedm.models.{domain}.py"'
                )

        # Validate against a root schema, for instance just "model", without any further key like "model.?" (schema module in freedm.models)
        elif cls:
            # The dictionary is the schema
            if isinstance(cls, dict):
                validate(value, cls)
            # Build a schema for each property we find in the class
            else:
                # Build one JSON schema of all schema properties
                schema = {}
                for key in [k for k in cls.__dict__.keys() if k[:1] != '_']:
                    schema.update({key: getattr(cls, key)})
                # We validate a data structure (object)
                if isinstance(value, dict):
                    # Try validating the domain data with the found schemas
                    s_keys = schema.keys()
                    v_keys = value.keys()
                    s_diff = list(set(s_keys) - set(v_keys))
                    v_diff = list(set(v_keys) - set(s_keys))
                    if len(s_diff) > 0:
                        raise UserWarning(
                            f'Domain data does not define values for: {", ".join(s_diff)}'
                        )
                    elif len(v_diff) > 0:
                        raise ValidationError(
                            f'Domain data should not contain these additional values ({", ".join(v_diff)})'
                        )
                    else:
                        for v in v_keys:
                            # Prepare the data (To get rid of dictionaries with numeric keys)
                            dataobject = __prepareCollectionObject(value[v])
                            # Validate
                            validate(dataobject, schema[v])
                # We validate just one single value
                else:
                    validate(value, schema)
        # If no class is found at all, make sure we raise an exception and return "None"
        else:
            raise UserWarning(
                f'No validation schema found for token "{domain}.*". Define schema in "freedm.models.{domain}.py"'
            )
    except UserWarning as uw:
        logger = logging.getLogger(str(os.getpid()))
        logger.debug(uw)
    except SchemaError as se:
        logger = logging.getLogger(str(os.getpid()))
        logger.warn(
            f'Validation schema for token "{token}" is malformed ({se.message})'
        )
    except ValidationError as ve:
        try:
            if not exception:
                logger = logging.getLogger(str(os.getpid()))
                logger.warn(
                    f'{"Schema" if token.isalpha() else "Sub-Schema"} "{token}" validation with value "{ellipsis(str(value), 40)}" failed ({ve.message})'
                )
        finally:
            # Make sure a "None" will be returned on Validation errors in any case
            value = None if not exception else ve
    except Exception as e:
        pass
    finally:
        # Delete the temporary data object, created for validation
        del dataobject
        # Return the value in any case (None if a ValidationError occured)
        return value
Ejemplo n.º 11
0
def const(validator, const, instance, schema):
    if not equal(instance, const):
        yield ValidationError("%r was expected" % (const,))
Ejemplo n.º 12
0
 def wrapper(self, *args, **kwargs):
     for field, error in fields.items():
         if field not in self:
             raise ValidationError(error)
     return f(self, *args, **kwargs)
Ejemplo n.º 13
0
def discriminator_validator(swagger_spec, validator, discriminator_attribute,
                            instance, schema):
    """
    Validates instance against the schema defined by the discriminator attribute.

    [Swagger 2.0 Schema Object](http://swagger.io/specification/#schemaObject) allows discriminator field to be defined.
    discriminator field defines the attribute that will be used to discriminate the object type.

    NOTE: discriminator_validator assumes that discriminator_attribute is not None or empty

    :param swagger_spec: needed for access to deref()
    :type swagger_spec: :class:`bravado_core.spec.Spec`
    :param validator: Validator class used to validate the object
    :type validator: :class: `Swagger20Validator` or
        :class: `jsonschema.validators.Draft4Validator`
    :param discriminator_attribute: name of the discriminator attribute
    :type discriminator_attribute: str
    :param instance: object instance value
    :type instance: dict
    :param schema: swagger spec for the object
    :type schema: dict
    """

    try:
        discriminator_value = instance[discriminator_attribute]
    except KeyError:
        raise ValidationError(
            "'{}' is a required property".format(discriminator_attribute))

    if discriminator_value not in swagger_spec.definitions:
        raise ValidationError(
            message='\'{}\' is not a recognized schema'.format(
                discriminator_value), )

    if discriminator_value == schema[MODEL_MARKER]:
        return

    discriminated_schema = swagger_spec.definitions[
        discriminator_value]._model_spec
    if 'allOf' not in discriminated_schema:
        raise ValidationError(
            message='discriminated schema \'{}\' must inherit from \'{}\''.
            format(
                discriminator_value,
                schema[MODEL_MARKER],
            ), )

    schemas_to_remove = [
        s for s in discriminated_schema['allOf']
        if swagger_spec.deref(s) == schema
    ]
    if not schemas_to_remove:
        # Not checking against len(schemas_to_remove) > 1 because it should be prevented by swagger spec validation
        raise ValidationError(
            message='discriminated schema \'{}\' must inherit from \'{}\''.
            format(
                discriminator_value,
                schema[MODEL_MARKER],
            ), )

    # Remove the current schema from the allOf list in order to avoid unbounded recursion
    # (the current object is already validated against schema)
    # WARNING: This is especially important if internally_dereference_refs is set to true
    #   as we're modifying new_schema and new_schema is a dict (so mutable) we need to copy
    #   it in order to have a brand new dictionary that we can modify
    new_schema = discriminated_schema.copy()
    new_schema['allOf'] = [
        all_of_schema if all_of_schema not in schemas_to_remove else {}
        for all_of_schema in new_schema['allOf']
    ]

    from bravado_core.validate import validate_object  # Local import due to circular dependency
    validate_object(swagger_spec=swagger_spec,
                    object_spec=new_schema,
                    value=instance)
Ejemplo n.º 14
0
    def post(self):
        """
        This is the POST method used to insert new book
        Request:
            URL : POST http://localhost:8080/api/v1/books
            Param Data :
                  "book":
                   {
                        "name": "My First Book",
                        "isbn": "123-3213243567",
                        "authors": [
                            "John Doe"
                        ],
                        "number_of_pages": 350,
                        "publisher": "Acme Books",
                        "country": "United States",
                        "release_date": "2019-08-01",
                   }

        Response:
            [
                "status_code": 201,
                "status": "success",
                "data": [
                    "book": {
                        "name": "My First Book",
                        "isbn": "123-3213243567",
                        "authors": [
                            "John Doe"
                        ],
                        "number_of_pages": 350,
                        "publisher": "Acme Books",
                        "country": "United States",
                        "release_date": "2019-08-01",
                    },
                ]
             ]

        """
        try:
            logger.info("Entering InternalBooksController POST method")
            if not request.content_type == 'application/json':
                raise ValidationError("Given content type : {} is not acceptable."
                                      " Accepted content type is application/json ".format(request.content_type))

            request_data = request.get_json()
            validate(request_data, post_schema, format_checker=jsonschema.FormatChecker())

            int_bk_obj = InternalBooks()

            result = int_bk_obj.insert_book(request_data)

            return result

            logger.info("Existing InternalBooksController POST method")
        except ValueError as err:
            logger.exception("Value Error :: {}".format(err))
            abort(400, str(err))

        except ValidationError as err:
            logger.exception("Validation Error :: {}".format(err))
            abort(400, err.message)

        except Exception as err:
            logger.exception("Un-handled Exception :: {}".format(err))
            abort(500, "Internal Server Error")
Ejemplo n.º 15
0
def validator_form(validator, form, instance, schema, _from_items=False):
    """
    - Silk form validators
      - Every "form" property must be either absent or present
      - If present, the form must have exactly that value
      - Or, the "form" property must be a list, and have one of the values in the list
        Or, if numeric, it must have one of the values between any two adjacent ascending list items
      - The above applies a bit differently for shape, as it is already a list:
        - Or, the "form" property must be a list of lists. The property must have the same length.
          For each item in the lists-of-lists, the property must have one of the values, or
          be between any two adjacent ascending list items.
      - Validation on "strides" works through exact match of the strides value.
        Note that "strides" is only present if "contiguous" is absent (and vice versa)
    """
    def _allowed_value(schema_value, instance_value):
        if isinstance(schema_value, (list, tuple)):
            if instance_value in schema_value:
                return True
            for n in range(len(schema_value)-1):
                left, right = schema_value[n:n+2]
                if instance_value > left and instance_value < right:
                    return True
            return False
        else:
            return schema_value == instance_value

    if isinstance(instance, FormWrapper):
        instance_storage, instance_form = instance._storage, instance._form
    else:
        #TODO:BAD
        instance_storage, instance_form = get_form(instance)
    form_str = indent(pprint.pformat(instance_form, width=72))
    if instance_form is not None and "storage" in instance_form:
        storage_form = instance_form["storage"]
        for error in _validator_storage(storage_form, instance_storage, form_str):
            yield error
        if instance_storage is None:
            instance_storage = storage_form.get("form")
    if instance_storage is None:
        return

    if _from_items:
        form_str += "\n(on items)"
    binary_form_props = ("unsigned", "shape", "bytesize", "strides", "ndim")
    for key, value in sorted(form.items(),key=lambda item:item[0]):
        if key in binary_form_props and not instance_storage.endswith("binary"):
            continue
        missing_key = None
        if key == "ndim":
            if "shape" not in instance_form:
                missing_key = "'shape' (needed by ndim)"
        else:
            if key not in instance_form:
                missing_key = "'" + key  + "'"
        if missing_key:
            msg = textwrap.dedent("""

                No form property '%s'

                On form:
                %s
                """.rstrip()
            ) % (missing_key, form_str)
            yield ValidationError(msg)
        if key != "ndim":
            instance_value = instance_form[key]
        ok = True
        if key == "ndim":
            instance_value = len(instance_form["shape"])
            if instance_value != value:
                ok = False
        elif key == "strides":
            if value != instance_value:
                ok = False
        elif key == "shape":
            assert len(value) == len(instance_value) #TODO: check before for inconsistent shape/ndim requirement
            for schema_dim, instance_dim in zip(value, instance_value):
                if schema_dim == -1:
                    continue
                if not _allowed_value(schema_dim, instance_dim):
                    ok = False
        elif isinstance(instance_value, _types["number"]):
            if isinstance(value, _types["number"]):
                if not _allowed_value(value, instance_value):
                    ok = False
        else:
            if value != instance_value:
                ok = False
        if not ok:
            msg = textwrap.dedent("""

                Form property '%s' has value %r, not %r

                On form:
                %s
                """.rstrip()
            ) % (key, instance_value, value, form_str)
            yield ValidationError(msg)

    if not _from_items and is_numpy_structure_schema(schema):
        assert instance_storage is not None, schema
        if "items" not in instance_form:
            msg = textwrap.dedent("""

                No form property 'items'

                On form:
                %s
                """.rstrip()
            ) % (form_str,)
            yield ValidationError(msg)
            return
        form_wrapper =  FormWrapper(None, instance_form["items"], instance_storage)
        items_form = schema.get("items", {}).get("form" ,  {})
        for error in validator_form(
            validator,
            items_form, form_wrapper,
            schema, _from_items=True
          ):
            yield error
Ejemplo n.º 16
0
def contains(validator, contains, instance, schema):
    if not validator.is_type(instance, "array"):
        return

    if not any(validator.is_valid(element, contains) for element in instance):
        yield ValidationError("XXX")
Ejemplo n.º 17
0
def format(validator, format, instance, schema):
    if validator.format_checker is not None:
        try:
            validator.format_checker.check(instance, format)
        except FormatError as error:
            yield ValidationError(error.message, cause=error.cause)
Ejemplo n.º 18
0
def _config_get_validators_fail_bad_params(temp_dir, key_):
    # calling str() on ValidationErrors returns more detailed into about the error
    _config_get_validators_fail('', temp_dir,
                                ValidationError("'' is not of type 'object'"))
    _config_get_validators_fail(
        ['foo', 'bar'], temp_dir,
        ValidationError("['foo', 'bar'] is not of type 'object'"))
    _config_get_validators_fail(
        {'key': 'y'}, temp_dir,
        ValidationError(
            "Additional properties are not allowed ('key' was unexpected)"))
    _config_get_validators_fail({key_: 'y'}, temp_dir,
                                ValidationError("'y' is not of type 'object'"))
    _config_get_validators_fail({key_: {
        'y': ['foo']
    }}, temp_dir, ValidationError("['foo'] is not of type 'object'"))
    _config_get_validators_fail({key_: {
        'y': {
            'key_metadata': {
                'a': 'b'
            }
        }
    }}, temp_dir, ValidationError("'validators' is a required property"))
    _config_get_validators_fail({key_: {
        'y': {
            'randomkey': {
                'a': 'b'
            }
        }
    }}, temp_dir, ValidationError("'validators' is a required property"))
    _config_get_validators_fail({key_: {
        'key': {
            'validators': {}
        }
    }}, temp_dir, ValidationError("{} is not of type 'array'"))
    _config_get_validators_fail({key_: {
        'key': {
            'validators': ['foo']
        }
    }}, temp_dir, ValidationError("'foo' is not of type 'object'"))
    _config_get_validators_fail(
        {
            key_: {
                'key': {
                    'validators': [{
                        'module': 'foo',
                        'callable_builder': 'bar'
                    }],
                    'key_metadata': []
                }
            }
        }, temp_dir, ValidationError("[] is not of type 'object'"))
    _config_get_validators_fail(
        {
            key_: {
                'key': {
                    'validators': [{
                        'module': 'foo',
                        'callable_builder': 'bar'
                    }],
                    'key_metadata': {
                        'a': {}
                    }
                }
            }
        }, temp_dir,
        ValidationError(
            "{} is not of type 'number', 'boolean', 'string', 'null'"))
    _config_get_validators_fail({key_: {
        'key': {
            'validators': [{}]
        }
    }}, temp_dir, ValidationError("'module' is a required property"))
    _config_get_validators_fail(
        {key_: {
            'key': {
                'validators': [{
                    'module': 'foo'
                }]
            }
        }}, temp_dir,
        ValidationError("'callable_builder' is a required property"))
    _config_get_validators_fail(
        {
            key_: {
                'key': {
                    'validators': [{
                        'module': 'foo',
                        'callable_builder': 'baz',
                        'callable-builder': 'bar'
                    }]
                }
            }
        }, temp_dir,
        ValidationError(
            "{'callable-builder': 'bar', 'callable_builder': 'baz', 'module': 'foo'} is valid "
            +
            "under each of {'required': ['callable-builder']}, {'required': ['callable_builder']}"
        ))
    _config_get_validators_fail(
        {
            key_: {
                'key': {
                    'validators': [{
                        'module': 'foo',
                        'callable_builder': 'bar',
                        'prefix': 1
                    }]
                }
            }
        }, temp_dir,
        ValidationError(
            "Additional properties are not allowed ('prefix' was unexpected)"))
    _config_get_validators_fail(
        {
            key_: {
                'key': {
                    'validators': [{
                        'module': ['foo'],
                        'callable_builder': 'bar'
                    }]
                }
            }
        }, temp_dir, ValidationError("['foo'] is not of type 'string'"))
    _config_get_validators_fail(
        {
            key_: {
                'key': {
                    'validators': [{
                        'module': 'foo',
                        'callable_builder': ['bar']
                    }]
                }
            }
        }, temp_dir, ValidationError("['bar'] is not of type 'string'"))
    _config_get_validators_fail(
        {
            key_: {
                'key': {
                    'validators': [{
                        'module': 'foo',
                        'callable_builder': 'bar',
                        'parameters': 'foo'
                    }]
                }
            }
        }, temp_dir, ValidationError("'foo' is not of type 'object'"))
Ejemplo n.º 19
0
def maxLength(validator, mL, instance, schema):
    if validator.is_type(instance, "string") and len(instance) > mL:
        yield ValidationError("%r is too long" % (instance, ))
Ejemplo n.º 20
0
	def isValid(self,validator,nslist,origValue,schema):
		found = False
		checkedPatterns = []
		matchType = str(schema.get(self.MatchTypeAttrName,'loose'))  if schema is not None  else 'canonical'
		if matchType not in CurieSearch.VALID_MATCHES:
			raise ValidationError("attribute '{0}' is {1} but it must be one of the next values: {2}".format(self.MatchTypeAttrName,matchType,CurieSearch.VALID_MATCHES.keys()))
		
		cache = self.GetCurieCache(cachePath=self.config.get('cacheDir'))
		
		parsed = None
		try:
			parsed = rfc3987.parse(origValue, rule="URI")
		except BaseException as be:
			if matchType != 'loose':
				raise be
		# Trying to decide the matching mode
		prefix = None
		if parsed:
			prefix = parsed.get('scheme')
			if prefix:
				if len(prefix) > 0:
					if matchType == 'loose':
						matchType = 'canonical'
					
					# We have to enforce lowercase schemes
					if prefix.lower() != prefix:
						raise ValidationError('The namespace of {} must be in lower case'.format(origValue))
		
		if nslist:
			# The restricted namespaces list could have some of them in capitals
			l_nslist = list(map(lambda x: None  if x is None  else x.lower()  if isinstance(x,str)  else str(x).lower(), nslist))
		else:
			l_nslist = nslist
		
		if matchType == 'basic':
			# Basic mode is like canonical, but without querying identifiers.org cache
			found = l_nslist and (prefix in l_nslist)
		elif matchType == 'loose':
			if l_nslist:
				valToVal = origValue
				validatedCURIEs = list(filter(lambda curie: curie is not None,map(lambda namespace: cache.get(namespace),l_nslist)))
				if not validatedCURIEs:
					raise ValidationError('No namespace from {} was found in identifiers.org cache'.format(nslist))
				
				# Looking for a match
				for curie in validatedCURIEs:
					checkedPatterns.append(curie.pattern)
					pat = re.compile(curie.pattern)
					if pat.search(valToVal):
						found = True
						break
			else:
				raise ValidationError('In "loose" mode, at least one namespace must be declared')
		elif prefix is None:
			raise ValidationError('In "canonical" mode, the value must be prefixed by the namespace')
		else:
			# Searching in canonical mode. To do that, we have to remove the prefix
			valToVal = origValue[(origValue.find(':')+1):]
			# The case where the namespace list is empty
			if l_nslist and (prefix not in l_nslist):
				raise ValidationError('The namespace {} is not in the list of the accepted ones: {}'.format(prefix,nslist))
			
			curie = cache.get(prefix)
			if not curie:
				raise ValidationError('The namespace {} was not found in identifiers.org cache'.format(prefix))
			
			checkedPatterns.append(curie.pattern)
			pat = re.compile(curie.pattern)
			found = pat.search(valToVal) or pat.search(origValue)
		
		return found, checkedPatterns
Ejemplo n.º 21
0
def disallow_draft3(validator, disallow, instance, schema):
    for disallowed in _utils.ensure_list(disallow):
        if validator.is_valid(instance, {"type": [disallowed]}):
            yield ValidationError("%r is disallowed for %r" %
                                  (disallowed, instance))
Ejemplo n.º 22
0
    def create(cls, data, id_=None, version_of=None):
        """Create a deposit with the optional id.

        :params version_of: PID of an existing record. If set, the new record
        will be marked as a new version of this referenced record. If no data
        is provided the new record will be a copy of this record. Note: this
        PID must reference the current last version of a record.
        """

        # check that the status field is not set
        if 'publication_state' in data:
            raise InvalidDepositError(
                'Field "publication_state" cannot be set.')
        data['publication_state'] = PublicationStates.draft.name
        # Set record's schema
        if '$schema' in data:
            raise InvalidDepositError('"$schema" field should not be set.')

        # Retrieve reserved record PID which should have already been created
        # by the deposit minter (The record PID value is the same
        # as the one of the deposit)
        rec_pid = RecordUUIDProvider.get(data['_deposit']['id']).pid
        version_master, prev_version = None, None
        # if this is a new version of an existing record, add the future
        # record pid in the chain of versions.
        if version_of:
            version_master, prev_version = \
                find_version_master_and_previous_record(version_of)
            # The new version must be in the same community
            if data['community'] != prev_version['community']:
                raise ValidationError(
                    'The community field cannot change between versions.')
            try:
                version_master.insert_draft_child(rec_pid)
            except Exception as exc:
                # Only one draft is allowed per version chain.
                if 'Draft child already exists for this relation' in \
                        exc.args[0]:
                    raise DraftExistsVersioningError(
                        version_master.draft_child
                    )
                raise exc
        else:
            # create parent PID
            parent_pid = RecordUUIDProvider.create().pid
            version_master = PIDVersioning(parent=parent_pid)
            version_master.insert_draft_child(child=rec_pid)

        # Mint the deposit with the parent PID
        data['_pid'] = [{
            'value': version_master.parent.pid_value,
            'type': RecordUUIDProvider.parent_pid_type,
        }]
        if 'community' not in data or not data['community']:
            raise ValidationError(
                'Record\s metadata has no community field.')
        try:
            community_id = uuid.UUID(data['community'])
        except ValueError as e:
            raise InvalidDepositError(
                'Community ID is not a valid UUID.') from e
        try:
            schema = CommunitySchema.get_community_schema(community_id)
        except CommunitySchemaDoesNotExistError as e:
            raise InvalidDepositError(
                'No schema for community {}.'.format(community_id)) from e

        if version_of:
            data['$schema'] = Deposit._build_deposit_schema(prev_version)
        else:
            from b2share.modules.schemas.serializers import \
                community_schema_draft_json_schema_link
            data['$schema'] = community_schema_draft_json_schema_link(
                schema,
                _external=True
            )

        # prepopulate required boolean fields with false
        if not version_of:
            from b2share.modules.schemas.api import BlockSchema
            import json
            community_schema = json.loads(schema.community_schema)
            if 'required' in community_schema:
                bs_id = json.loads(schema.community_schema)['required'][0]
                bs = BlockSchema.get_block_schema(bs_id)
                bs_version = bs.versions[len(bs.versions) - 1]
                schema_dict = json.loads(bs_version.json_schema)
                required = []
                if 'required' in schema_dict:
                    required = schema_dict['required']
                properties = {}
                if 'properties' in schema_dict:
                    properties = schema_dict['properties']
                try:
                    community_metadata = data['community_specific'][bs_id]
                except KeyError:
                    community_metadata = {}
                for key in required:
                    if properties.get(key).get('type') == 'boolean' and not key in community_metadata:
                        community_metadata[key] = False
                data['community_specific'] = {bs_id: community_metadata}

        # create file bucket
        if prev_version and prev_version.files:
            # Clone the bucket from the previous version. This doesn't
            # duplicate files.
            bucket = prev_version.files.bucket.snapshot(lock=False)
            bucket.locked = False
        else:
            bucket = Bucket.create(storage_class=current_app.config[
                'DEPOSIT_DEFAULT_STORAGE_CLASS'
            ])

        if 'external_pids' in data:
            create_b2safe_file(data['external_pids'], bucket)
            del data['external_pids']

        deposit = super(Deposit, cls).create(data, id_=id_)
        db.session.add(bucket)
        db.session.add(RecordsBuckets(
            record_id=deposit.id, bucket_id=bucket.id
        ))

        return deposit
Ejemplo n.º 23
0
def required_draft4(validator, required, instance, schema):
    if not validator.is_type(instance, "object"):
        return
    for property in required:
        if property not in instance:
            yield ValidationError("%r is a required property" % property)
Ejemplo n.º 24
0
def const(validator, const, instance, schema):
    if instance != const:
        yield ValidationError("%r was expected" % (const, ))
Ejemplo n.º 25
0
def maxProperties_draft4(validator, mP, instance, schema):
    if not validator.is_type(instance, "object"):
        return
    if validator.is_type(instance, "object") and len(instance) > mP:
        yield ValidationError("%r has too many properties" % (instance, ))
Ejemplo n.º 26
0
def minItems(validator, mI, instance, schema):
    if validator.is_type(instance, "array") and len(instance) < mI:
        yield ValidationError("%r is too short" % (instance, ))
Ejemplo n.º 27
0
def oneOf_draft4(validator, oneOf, instance, schema):
    """
    oneOf_draft4 validator from
    https://github.com/Julian/jsonschema/blob/d16713a4296663f3d62c50b9f9a2893cb380b7af/jsonschema/_validators.py#L337

    Modified to:
    - sort the instance JSON, so we get a reproducible output that we
      can can test more easily
    - Yield all the individual errors for linked or embedded releases within a
      record.
    - Return more information on the ValidationError object, to allow us to
      replace the translation with a message in cove-ocds
    """
    subschemas = enumerate(oneOf)
    all_errors = []
    for index, subschema in subschemas:
        errs = list(validator.descend(instance, subschema, schema_path=index))
        if not errs:
            first_valid = subschema
            break
        # We check the title, because we don't have access to the field name,
        # as it lives in the parent.
        # It will not match the releases array in a release package, because
        # there is no oneOf.
        if (schema.get("title") == "Releases" or schema.get("description")
                == "An array of linking identifiers or releases"):
            # If instance is not a list, or is a list of zero length, then
            # validating against either subschema will work.
            # Assume instance is an array of Linked releases, if there are no
            # "id"s in any of the releases.
            if type(instance) is not list or all("id" not in release
                                                 for release in instance):
                if "properties" in subschema.get(
                        "items",
                    {}) and "id" not in subschema["items"]["properties"]:
                    for err in errs:
                        err.assumption = "linked_releases"
                        yield err
                    return
            # Assume instance is an array of Embedded releases, if there is an
            # "id" in each of the releases
            elif all("id" in release for release in instance):
                if "id" in subschema.get("items", {}).get(
                        "properties", {}) or subschema.get("items", {}).get(
                            "$ref", "").endswith("release-schema.json"):
                    for err in errs:
                        err.assumption = "embedded_releases"
                        yield err
                    return
            else:
                err = ValidationError(
                    "This array should contain either entirely embedded releases or "
                    "linked releases. Embedded releases contain an 'id' whereas linked "
                    "releases do not. Your releases contain a mixture.")
                err.error_id = "releases_both_embedded_and_linked"
                yield err
                return

        all_errors.extend(errs)
    else:
        err = ValidationError(
            f"{json.dumps(instance, sort_keys=True, default=decimal_default)} "
            "is not valid under any of the given schemas",
            context=all_errors,
        )
        err.error_id = "oneOf_any"
        yield err

    more_valid = [s for i, s in subschemas if validator.is_valid(instance, s)]
    if more_valid:
        more_valid.append(first_valid)
        reprs = ", ".join(repr(schema) for schema in more_valid)
        err = ValidationError(f"{instance!r} is valid under each of {reprs}")
        err.error_id = "oneOf_each"
        err.reprs = reprs
        yield err
Ejemplo n.º 28
0
def maxItems(validator, mI, instance, schema):
    if validator.is_type(instance, "array") and len(instance) > mI:
        yield ValidationError("%r is too long" % (instance, ))
Ejemplo n.º 29
0
def nullable(validator, is_nullable, instance, schema):
    if instance is None and not is_nullable:
        yield ValidationError("None for not nullable")
Ejemplo n.º 30
0
def uniqueItems(validator, uI, instance, schema):
    if (uI and validator.is_type(instance, "array")
            and not _utils.uniq(instance)):
        yield ValidationError("%r has non-unique elements" % instance)
Ejemplo n.º 31
0
def readOnly(validator, ro, instance, schema):
    if not validator.write or not ro:
        return

    yield ValidationError("Tried to write read-only property with %s" %
                          (instance))
Ejemplo n.º 32
0
def pattern(validator, patrn, instance, schema):
    if (validator.is_type(instance, "string")
            and not re.search(patrn, instance)):
        yield ValidationError("%r does not match %r" % (instance, patrn))