示例#1
0
    def validate_items(self):
        from python_jsonschema_objects import classbuilder

        if self.__itemtype__ is None:
            return

        type_checks = self.__itemtype__
        if not isinstance(type_checks, (tuple, list)):
            # we were given items = {'type': 'blah'} ; thus ensure the type for all data.
            type_checks = [type_checks] * len(self.data)
        elif len(type_checks) > len(self.data):
            raise ValidationError(
                "{1} does not have sufficient elements to validate against {0}"
                .format(self.__itemtype__, self.data))

        typed_elems = []
        for elem, typ in zip(self.data, type_checks):
            if isinstance(typ, dict):
                for param, paramval in six.iteritems(typ):
                    validator = registry(param)
                    if validator is not None:
                        validator(paramval, elem, typ)

            elif util.safe_issubclass(typ, classbuilder.LiteralValue):
                val = typ(elem)
                val.validate()
                typed_elems.append(val)
            elif util.safe_issubclass(typ, classbuilder.ProtocolBase):
                if not isinstance(elem, typ):
                    try:
                        if isinstance(elem, (six.string_types, six.integer_types, float)):
                            val = typ(elem)
                        else:
                            val = typ(**util.coerce_for_expansion(elem))
                    except TypeError as e:
                        raise ValidationError("'{0}' is not a valid value for '{1}': {2}"
                                              .format(elem, typ, e))
                else:
                    val = elem
                val.validate()
                typed_elems.append(val)
            elif util.safe_issubclass(typ, ArrayValidator):
                val = typ(elem)
                val.validate()
                typed_elems.append(val)
            elif isinstance(typ, classbuilder.TypeProxy):
                try:
                    if isinstance(elem, (six.string_types, six.integer_types, float)):
                        val = typ(elem)
                    else:
                        val = typ(**util.coerce_for_expansion(elem))
                except TypeError as e:
                    raise ValidationError("'{0}' is not a valid value for '{1}': {2}"
                                          .format(elem, typ, e))
                val.validate()
                typed_elems.append(val)

        return typed_elems
    def create(name, item_constraint=None, **addl_constraints):
        """ Create an array validator based on the passed in constraints.

        If item_constraint is a tuple, it is assumed that tuple validation
        is being performed. If it is a class or dictionary, list validation
        will be performed. Classes are assumed to be subclasses of ProtocolBase,
        while dictionaries are expected to be basic types ('string', 'number', ...).

        addl_constraints is expected to be key-value pairs of any of the other
        constraints permitted by JSON Schema v4.
        """
        from python_jsonschema_objects import classbuilder
        props = {}

        if item_constraint is not None:
            if isinstance(item_constraint, (tuple, list)):
                for i, elem in enumerate(item_constraint):
                    isdict = isinstance(elem, (dict, ))
                    isklass = isinstance(elem, type) and util.safe_issubclass(
                        elem,
                        (classbuilder.ProtocolBase, classbuilder.LiteralValue))

                    if not any([isdict, isklass]):
                        raise TypeError(
                            "Item constraint (position {0}) was not a schema".
                            format(i))
            else:
                isdict = isinstance(item_constraint, (dict, ))
                isklass = isinstance(
                    item_constraint, type) and util.safe_issubclass(
                        item_constraint,
                        (classbuilder.ProtocolBase, classbuilder.LiteralValue))

                if not any([isdict, isklass]):
                    raise TypeError("Item constraint was not a schema")

                if isdict and item_constraint['type'] == 'array':
                    item_constraint = ArrayValidator.create(
                        name + "#sub",
                        item_constraint=item_constraint['items'],
                        addl_constraints=item_constraint)

        props['__itemtype__'] = item_constraint

        props.update(addl_constraints)

        validator = type(str(name), (ArrayValidator, ), props)

        return validator
示例#3
0
    def _make_type(self, typ, val):
        import python_jsonschema_objects.classbuilder as cb

        if getattr(typ, 'isLiteralClass', None) is True:
            return typ(val)

        if util.safe_issubclass(typ, cb.ProtocolBase):
            return typ(**util.coerce_for_expansion(val))

        if util.safe_issubclass(typ, validators.ArrayValidator):
            return typ(val)

        raise validators.ValidationError(
            "additionalProperty type {0} was neither a literal "
            "nor a schema wrapper: {1}".format(typ, val))
    def __setattr__(self, name, val):
        if name.startswith("_"):
            object.__setattr__(self, name, val)
        elif name in self.__propinfo__:
            # If its in __propinfo__, then it actually has a property defined.
            # The property does special validation, so we actually need to
            # run its setter. We get it from the class definition and call
            # it directly. XXX Heinous.
            prop = self.__class__.__dict__[self.__prop_names__[name]]
            prop.fset(self, val)
        else:
            # This is an additional property of some kind
            typ = getattr(self, '__extensible__', None)
            if typ is False:
                raise validators.ValidationError(
                    "Attempted to set unknown property '{0}', "
                    "but 'additionalProperties' is false.".format(name))
            if typ is True:
                # There is no type defined, so just make it a basic literal
                # Pick the type based on the type of the values
                valtype = [k for k, t in six.iteritems(self.__SCHEMA_TYPES__)
                           if t is not None and isinstance(val, t)]
                valtype = valtype[0]
                val = MakeLiteral(name, valtype, val)
            elif isinstance(typ, type) and getattr(typ, 'isLiteralClass', None) is True:
                val = typ(val)
            elif isinstance(typ, type) and util.safe_issubclass(typ, ProtocolBase):
                val = typ(**util.coerce_for_expansion(val))

            self._extended_properties[name] = val
示例#5
0
    def apply(self, klass, resolve_map={}):
        """ Attach this property to the provided class

        Args:
            klass: (ProtocolBase) The class wrapper to which this
                property should be attached.
            resolve_map: (dict) A map of URIs to resolved ProtocolBase
                objects.
        """
        assert util.safe_issubclass(klass, ProtocolBase)

        if self.is_array:
            typ = resolve_map[self.refuri]
            propdata = {
                'type':
                'array',
                'validator':
                python_jsonschema_objects.wrapper_types.ArrayWrapper.create(
                    self.refuri, item_constraint=typ)
            }
        else:
            propdata = {'type': resolve_map[self.refuri]}

        resolved_property = make_property(self.property_name, propdata,
                                          resolve_map[self.refuri].__doc__)

        setattr(klass, self.property_name, resolved_property)
        klass.__propinfo__[self.property_name] = {
            "$ref": self.refuri,
            "type": resolve_map[self.refuri]
        }
示例#6
0
    def __setattr__(self, name, val):
        if name.startswith("_"):
            object.__setattr__(self, name, val)
        elif name in self.__propinfo__:
            # If its in __propinfo__, then it actually has a property defined.
            # The property does special validation, so we actually need to
            # run its setter. We get it from the class definition and call
            # it directly. XXX Heinous.
            prop = self.__class__.__dict__[self.__prop_names__[name]]
            prop.fset(self, val)
        else:
            # This is an additional property of some kind
            typ = getattr(self, '__extensible__', None)
            if typ is False:
                raise validators.ValidationError(
                    "Attempted to set unknown property '{0}', "
                    "but 'additionalProperties' is false.".format(name))
            if typ is True:
                # There is no type defined, so just make it a basic literal
                # Pick the type based on the type of the values
                valtype = [
                    k for k, t in six.iteritems(self.__SCHEMA_TYPES__)
                    if t is not None and isinstance(val, t)
                ]
                valtype = valtype[0]
                val = MakeLiteral(name, valtype, val)
            elif isinstance(
                    typ,
                    type) and getattr(typ, 'isLiteralClass', None) is True:
                val = typ(val)
            elif isinstance(typ, type) and util.safe_issubclass(
                    typ, ProtocolBase):
                val = typ(**util.coerce_for_expansion(val))

            self._extended_properties[name] = val
    def _make_type(self, typ, val):
        import python_jsonschema_objects.classbuilder as cb

        if getattr(
               typ, 'isLiteralClass', None) is True:
            return typ(val)

        if util.safe_issubclass(typ, cb.ProtocolBase):
            return typ(**util.coerce_for_expansion(val))

        if util.safe_issubclass(typ, validators.ArrayValidator):
            return typ(val)

        raise validators.ValidationError(
            "additionalProperty type {0} was neither a literal "
            "nor a schema wrapper: {1}".format(typ, val))
    def create(name, item_constraint=None, **addl_constraints):
        """ Create an array validator based on the passed in constraints.

        If item_constraint is a tuple, it is assumed that tuple validation
        is being performed. If it is a class or dictionary, list validation
        will be performed. Classes are assumed to be subclasses of ProtocolBase,
        while dictionaries are expected to be basic types ('string', 'number', ...).

        addl_constraints is expected to be key-value pairs of any of the other
        constraints permitted by JSON Schema v4.
        """
        from python_jsonschema_objects import classbuilder
        props = {}

        if item_constraint is not None:
            if isinstance(item_constraint, (tuple, list)):
                for i, elem in enumerate(item_constraint):
                    isdict = isinstance(elem, (dict,))
                    isklass = isinstance( elem, type) and util.safe_issubclass(
                        elem, (classbuilder.ProtocolBase, classbuilder.LiteralValue))

                    if not any([isdict, isklass]):
                        raise TypeError(
                            "Item constraint (position {0}) was not a schema".format(i))
            else:
                isdict = isinstance(item_constraint, (dict,))
                isklass = isinstance( item_constraint, type) and util.safe_issubclass(
                    item_constraint, (classbuilder.ProtocolBase, classbuilder.LiteralValue))

                if not any([isdict, isklass]):
                    raise TypeError("Item constraint was not a schema")

                if isdict and item_constraint['type'] == 'array':
                    item_constraint = ArrayValidator.create(name + "#sub",
                                                            item_constraint=item_constraint[
                                                                'items'],
                                                            addl_constraints=item_constraint)

        props['__itemtype__'] = item_constraint

        props.update(addl_constraints)

        validator = type(str(name), (ArrayValidator,), props)

        return validator
    def apply(self, klass, resolve_map={}):
        """ Attach this property to the provided class

        Args:
            klass: (ProtocolBase) The class wrapper to which this
                property should be attached.
            resolve_map: (dict) A map of URIs to resolved ProtocolBase
                objects.
        """
        assert util.safe_issubclass(klass, ProtocolBase)

        resolved_property = make_property(self.property_name,
                                          {'type': resolve_map[self.refuri]},
                                          resolve_map[self.refuri].__doc__)

        setattr(klass, self.property_name, resolved_property)
        klass.__propinfo__[self.property_name] = {
            "$ref": self.refuri,
            "type": resolve_map[self.refuri]
        }
    def _construct(self, uri, clsdata, parent=(ProtocolBase,)):
        if 'oneOf' in clsdata:
            potential_parents = self.resolve_classes(clsdata['oneOf'])

            for p in potential_parents:
                if util.safe_issubclass(p, ProtocolBase):
                    self.resolved[uri] = self._build_object(
                        uri,
                        clsdata,
                        (p,))
                else:
                    raise Exception("Don't know how to deal with this")

            return self.resolved[uri]

        elif 'anyOf' in clsdata:
            raise NotImplementedError(
                "anyOf is not supported as bare property")

        elif 'allOf' in clsdata:
            potential_parents = self.resolve_classes(clsdata['allOf'])
            parents = []
            for p in potential_parents:
                if isinstance(p, dict):
                    # This is additional constraints
                    clsdata.update(p)
                elif util.safe_issubclass(p, ProtocolBase):
                    parents.append(p)

            self.resolved[uri] = self._build_object(
                uri,
                clsdata,
                parents)
            return self.resolved[uri]

        elif '$ref' in clsdata:

            if 'type' in clsdata and util.safe_issubclass(
                    clsdata['type'], (ProtocolBase, LiteralValue)):
                # It's possible that this reference was already resolved, in which
                # case it will have its type parameter set
                logging.debug("Using previously resolved type "
                              "(with different URI) for %s", uri)
                self.resolved[uri] = clsdata['type']
            elif uri in self.resolved:
                logging.debug("Using previously resolved object for %s", uri)
            else:
                logging.debug("Resolving object for %s", uri)

                with self.resolver.resolving(uri) as resolved:
                    self.resolved[uri] = None # Set incase there is a circular reference in schema definition
                    self.resolved[uri] = self._build_object(
                        uri,
                        resolved,
                        parent)

            return self.resolved[uri]

        elif clsdata.get('type') == 'array' and 'items' in clsdata:
            self.resolved[uri] = self._build_object(
                uri,
                clsdata,
                parent)

        elif (clsdata.get('type', None) == 'object' or
              clsdata.get('properties', None) is not None or
              clsdata.get('additionalProperties', False)):
            self.resolved[uri] = self._build_object(
                uri,
                clsdata,
                parent)
            return self.resolved[uri]
        elif clsdata.get('type') in ('integer', 'number', 'string', 'boolean', 'null'):
            self.resolved[uri] = self._build_literal(
                uri,
                clsdata)
            return self.resolved[uri]
        elif 'enum' in clsdata:
            obj = self._build_literal(uri, clsdata)
            self.resolved[uri] = obj
            return obj

        elif 'type' in clsdata and util.safe_issubclass(clsdata['type'], ProtocolBase):
            self.resolved[uri] = clsdata.get('type')
            return self.resolved[uri]
        else:
            raise NotImplementedError(
                "Unable to parse schema object '{0}' with "
                "no type and no reference".format(clsdata))
    def _construct(self, uri, clsdata, parent=(ProtocolBase,),**kw):

        if 'anyOf' in clsdata:
            raise NotImplementedError(
                "anyOf is not supported as bare property")

        elif 'oneOf' in clsdata:
            self.resolved[uri] = self._build_object(
                uri,
                clsdata,
                parent, **kw)
            return self.resolved[uri]

        elif 'allOf' in clsdata:
            potential_parents = self.resolve_classes(clsdata['allOf'])
            parents = []
            for p in potential_parents:
                if isinstance(p, dict):
                    # This is additional constraints
                    clsdata.update(p)
                elif util.safe_issubclass(p, ProtocolBase):
                    parents.append(p)

            self.resolved[uri] = self._build_object(
                uri,
                clsdata,
                parents,**kw)
            return self.resolved[uri]

        elif '$ref' in clsdata:

            if 'type' in clsdata and util.safe_issubclass(
                    clsdata['type'], (ProtocolBase, LiteralValue)):
                # It's possible that this reference was already resolved, in which
                # case it will have its type parameter set
                logger.debug(util.lazy_format("Using previously resolved type "
                              "(with different URI) for {0}", uri))
                self.resolved[uri] = clsdata['type']
            elif uri in self.resolved:
                logger.debug(util.lazy_format("Using previously resolved object for {0}", uri))
            else:
                ref = clsdata['$ref']
                refuri = util.resolve_ref_uri(
                    self.resolver.resolution_scope, ref)
                if refuri in self.under_construction:
                    logger.debug(
                            util.lazy_format(
                                    "Resolving cyclic reference from {0} to {1}.",
                                    uri,
                                    refuri))
                    return TypeRef(refuri, self.resolved)
                else:
                    logger.debug(
                            util.lazy_format(
                                    "Resolving direct reference object for {0}: {1}",
                                    uri,
                                    refuri))

                    with self.resolver.resolving(refuri) as resolved:
                        self.resolved[uri] = self.construct(
                                refuri,
                                resolved,
                                parent)

            return self.resolved[uri]

        elif clsdata.get('type') == 'array' and 'items' in clsdata:
            clsdata_copy = {}
            clsdata_copy.update(clsdata)
            self.resolved[uri] = python_jsonschema_objects.wrapper_types.ArrayWrapper.create(
                uri,
                item_constraint=clsdata_copy.pop('items'),
                classbuilder=self,
                **clsdata_copy)
            return self.resolved[uri]

        elif isinstance(clsdata.get('type'), list):
            types = []
            for i, item_detail in enumerate(clsdata['type']):
                subdata = {k: v for k, v in six.iteritems(clsdata) if k != 'type'}
                subdata['type'] = item_detail
                types.append(self._build_literal(
                    uri + "_%s" % i,
                    subdata))

            self.resolved[uri] = TypeProxy(types)
            return self.resolved[uri]

        elif (clsdata.get('type', None) == 'object' or
              clsdata.get('properties', None) is not None or
              clsdata.get('additionalProperties', False)):
            self.resolved[uri] = self._build_object(
                uri,
                clsdata,
                parent,**kw)
            return self.resolved[uri]
        elif clsdata.get('type') in ('integer', 'number', 'string', 'boolean', 'null'):
            self.resolved[uri] = self._build_literal(
                uri,
                clsdata)
            return self.resolved[uri]
        elif 'enum' in clsdata:
            obj = self._build_literal(uri, clsdata)
            self.resolved[uri] = obj
            return obj

        elif 'type' in clsdata and util.safe_issubclass(clsdata['type'], ProtocolBase):
            self.resolved[uri] = clsdata.get('type')
            return self.resolved[uri]
        else:
            raise NotImplementedError(
                "Unable to parse schema object '{0}' with "
                "no type and no reference".format(clsdata))
示例#12
0
    def _construct(self, uri, clsdata, parent=(ProtocolBase,), **kw):

        if "anyOf" in clsdata:
            raise NotImplementedError("anyOf is not supported as bare property")

        elif "oneOf" in clsdata:
            """ If this object itself has a 'oneOf' designation, 
            then construct a TypeProxy.
            """
            klasses = self.construct_objects(clsdata["oneOf"], uri)

            logger.debug(
                util.lazy_format("Designating {0} as TypeProxy for {1}", uri, klasses)
            )
            self.resolved[uri] = TypeProxy(klasses, title=clsdata.get("title"))
            return self.resolved[uri]

        elif "allOf" in clsdata:
            potential_parents = self.expand_references(uri, clsdata["allOf"])
            parents = []
            for p in potential_parents:
                if isinstance(p, dict):
                    # This is additional constraints
                    clsdata.update(p)
                elif util.safe_issubclass(p, ProtocolBase):
                    parents.append(p)

            self.resolved[uri] = self._build_object(uri, clsdata, parents, **kw)
            return self.resolved[uri]

        elif "$ref" in clsdata:

            if "type" in clsdata and util.safe_issubclass(
                clsdata["type"], (ProtocolBase, LiteralValue)
            ):
                # It's possible that this reference was already resolved, in which
                # case it will have its type parameter set
                logger.debug(
                    util.lazy_format(
                        "Using previously resolved type "
                        "(with different URI) for {0}",
                        uri,
                    )
                )
                self.resolved[uri] = clsdata["type"]
            elif uri in self.resolved:
                logger.debug(
                    util.lazy_format("Using previously resolved object for {0}", uri)
                )
            else:
                ref = clsdata["$ref"]
                typ = self.resolve_type(ref, uri)
                self.resolved[uri] = typ

            return self.resolved[uri]

        elif clsdata.get("type") == "array" and "items" in clsdata:
            clsdata_copy = {}
            clsdata_copy.update(clsdata)
            self.resolved[
                uri
            ] = python_jsonschema_objects.wrapper_types.ArrayWrapper.create(
                uri,
                item_constraint=clsdata_copy.pop("items"),
                classbuilder=self,
                **clsdata_copy
            )
            return self.resolved[uri]

        elif isinstance(clsdata.get("type"), list):
            types = []
            for i, item_detail in enumerate(clsdata["type"]):
                subdata = {k: v for k, v in six.iteritems(clsdata) if k != "type"}
                subdata["type"] = item_detail
                types.append(self._build_literal(uri + "_%s" % i, subdata))

            self.resolved[uri] = TypeProxy(types)
            return self.resolved[uri]

        elif (
            clsdata.get("type", None) == "object"
            or clsdata.get("properties", None) is not None
            or clsdata.get("additionalProperties", False)
        ):
            self.resolved[uri] = self._build_object(uri, clsdata, parent, **kw)
            return self.resolved[uri]
        elif clsdata.get("type") in ("integer", "number", "string", "boolean", "null"):
            self.resolved[uri] = self._build_literal(uri, clsdata)
            return self.resolved[uri]
        elif "enum" in clsdata:
            obj = self._build_literal(uri, clsdata)
            self.resolved[uri] = obj
            return obj

        elif "type" in clsdata and util.safe_issubclass(clsdata["type"], ProtocolBase):
            self.resolved[uri] = clsdata.get("type")
            return self.resolved[uri]
        else:
            raise NotImplementedError(
                "Unable to parse schema object '{0}' with "
                "no type and no reference".format(clsdata)
            )
示例#13
0
    def setprop(self, val):
        if isinstance(info['type'], (list, tuple)):
            ok = False
            errors = []
            type_checks = []

            for typ in info['type']:
                if not isinstance(typ, dict):
                    type_checks.append(typ)
                    continue
                typ = ProtocolBase.__SCHEMA_TYPES__[typ['type']]
                if typ is None:
                    typ = type(None)
                if isinstance(typ, (list, tuple)):
                    type_checks.extend(typ)
                else:
                    type_checks.append(typ)

            for typ in type_checks:
                if isinstance(val, typ):
                    ok = True
                    break
                elif hasattr(typ, 'isLiteralClass'):
                    try:
                        validator = typ(val)
                    except Exception as e:
                        errors.append("Failed to coerce to '{0}': {1}".format(
                            typ, e))
                        pass
                    else:
                        validator.validate()
                        ok = True
                        break
                elif util.safe_issubclass(typ, ProtocolBase):
                    # force conversion- thus the val rather than validator assignment
                    try:
                        val = typ(**util.coerce_for_expansion(val))
                    except Exception as e:
                        errors.append("Failed to coerce to '{0}': {1}".format(
                            typ, e))
                        pass
                    else:
                        val.validate()
                        ok = True
                        break
                elif util.safe_issubclass(typ, validators.ArrayValidator):
                    try:
                        val = typ(val)
                    except Exception as e:
                        errors.append("Failed to coerce to '{0}': {1}".format(
                            typ, e))
                        pass
                    else:
                        val.validate()
                        ok = True
                        break

            if not ok:
                errstr = "\n".join(errors)
                raise validators.ValidationError(
                    "Object must be one of {0}: \n{1}".format(
                        info['type'], errstr))

        elif info['type'] == 'array':
            instance = info['validator'](val)
            val = instance.validate()

        elif getattr(info['type'], 'isLiteralClass', False) is True:
            if not isinstance(val, info['type']):
                validator = info['type'](val)
            validator.validate()

        elif util.safe_issubclass(info['type'], ProtocolBase):
            if not isinstance(val, info['type']):
                val = info['type'](**util.coerce_for_expansion(val))

            val.validate()

        elif isinstance(info['type'], TypeProxy):
            val = info['type'](val)

        elif info['type'] is None:
            # This is the null value
            if val is not None:
                raise validators.ValidationError(
                    "None is only valid value for null")

        else:
            raise TypeError("Unknown object type: '{0}'".format(info['type']))

        self._properties[prop] = val
示例#14
0
    def _construct(self, uri, clsdata, parent=(ProtocolBase, )):

        if 'anyOf' in clsdata:
            raise NotImplementedError(
                "anyOf is not supported as bare property")

        elif 'allOf' in clsdata:
            potential_parents = self.resolve_classes(clsdata['allOf'])
            parents = []
            for p in potential_parents:
                if isinstance(p, dict):
                    # This is additional constraints
                    clsdata.update(p)
                elif util.safe_issubclass(p, ProtocolBase):
                    parents.append(p)

            self.resolved[uri] = self._build_object(uri, clsdata, parents)
            return self.resolved[uri]

        elif '$ref' in clsdata:

            if 'type' in clsdata and util.safe_issubclass(
                    clsdata['type'], (ProtocolBase, LiteralValue)):
                # It's possible that this reference was already resolved, in which
                # case it will have its type parameter set
                logger.debug(
                    util.lazy_format(
                        "Using previously resolved type "
                        "(with different URI) for {0}", uri))
                self.resolved[uri] = clsdata['type']
            elif uri in self.resolved:
                logger.debug(
                    util.lazy_format(
                        "Using previously resolved object for {0}", uri))
            else:
                logger.debug(util.lazy_format("Resolving object for {0}", uri))

                with self.resolver.resolving(uri) as resolved:
                    self.resolved[
                        uri] = None  # Set incase there is a circular reference in schema definition
                    self.resolved[uri] = self.construct(uri, resolved, parent)

            return self.resolved[uri]

        elif clsdata.get('type') == 'array' and 'items' in clsdata:
            clsdata_copy = {}
            clsdata_copy.update(clsdata)
            self.resolved[uri] = validators.ArrayValidator.create(
                uri,
                item_constraint=clsdata_copy.pop('items'),
                classbuilder=self,
                **clsdata_copy)
            return self.resolved[uri]

        elif isinstance(clsdata.get('type'), list):
            types = []
            for i, item_detail in enumerate(clsdata['type']):
                subdata = {
                    k: v
                    for k, v in six.iteritems(clsdata) if k != 'type'
                }
                subdata['type'] = item_detail
                types.append(self._build_literal(uri + "_%s" % i, subdata))

            self.resolved[uri] = TypeProxy(types)
            return self.resolved[uri]

        elif (clsdata.get('type', None) == 'object'
              or clsdata.get('properties', None) is not None
              or clsdata.get('additionalProperties', False)):
            self.resolved[uri] = self._build_object(uri, clsdata, parent)
            return self.resolved[uri]
        elif clsdata.get('type') in ('integer', 'number', 'string', 'boolean',
                                     'null'):
            self.resolved[uri] = self._build_literal(uri, clsdata)
            return self.resolved[uri]
        elif 'enum' in clsdata:
            obj = self._build_literal(uri, clsdata)
            self.resolved[uri] = obj
            return obj

        elif 'type' in clsdata and util.safe_issubclass(
                clsdata['type'], ProtocolBase):
            self.resolved[uri] = clsdata.get('type')
            return self.resolved[uri]
        else:
            raise NotImplementedError(
                "Unable to parse schema object '{0}' with "
                "no type and no reference".format(clsdata))
    def validate_items(self):
        """ Validates the items in the backing array, including
        performing type validation.

        Sets the _typed property and clears the dirty flag as a side effect

        Returns:
            The typed array
        """
        logger.debug(fmt("Validating {}", self))
        from python_jsonschema_objects import classbuilder

        if self.__itemtype__ is None:
            return

        type_checks = self.__itemtype__
        if not isinstance(type_checks, (tuple, list)):
            # we were given items = {'type': 'blah'} ; thus ensure the type for all data.
            type_checks = [type_checks] * len(self.data)
        elif len(type_checks) > len(self.data):
            raise ValidationError(
                "{1} does not have sufficient elements to validate against {0}"
                .format(self.__itemtype__, self.data))

        typed_elems = []
        for elem, typ in zip(self.data, type_checks):
            if isinstance(typ, dict):
                for param, paramval in six.iteritems(typ):
                    validator = registry(param)
                    if validator is not None:
                        validator(paramval, elem, typ)
                typed_elems.append(elem)

            elif util.safe_issubclass(typ, classbuilder.LiteralValue):
                val = typ(elem)
                val.validate()
                typed_elems.append(val)
            elif util.safe_issubclass(typ, classbuilder.ProtocolBase):
                if not isinstance(elem, typ):
                    try:
                        if isinstance(elem, (six.string_types, six.integer_types, float)):
                            val = typ(elem)
                        else:
                            val = typ(**util.coerce_for_expansion(elem))
                    except TypeError as e:
                        raise ValidationError("'{0}' is not a valid value for '{1}': {2}"
                                              .format(elem, typ, e))
                else:
                    val = elem
                val.validate()
                typed_elems.append(val)

            elif util.safe_issubclass(typ, ArrayWrapper):
                val = typ(elem)
                val.validate()
                typed_elems.append(val)

            elif isinstance(typ, (classbuilder.TypeProxy, classbuilder.TypeRef)):
                try:
                    if isinstance(elem, (six.string_types, six.integer_types, float)):
                        val = typ(elem)
                    else:
                        val = typ(**util.coerce_for_expansion(elem))
                except TypeError as e:
                    raise ValidationError("'{0}' is not a valid value for '{1}': {2}"
                                          .format(elem, typ, e))
                else:
                    val.validate()
                    typed_elems.append(val)

        self._dirty = False
        self._typed = typed_elems
        return typed_elems
    def setprop(self, val):
        if isinstance(info['type'], (list, tuple)):
            ok = False
            errors = []
            type_checks = []

            for typ in info['type']:
              if not isinstance(typ, dict):
                type_checks.append(typ)
                continue
              typ = ProtocolBase.__SCHEMA_TYPES__[typ['type']]
              if typ == None:
                typ = type(None)
              if isinstance(typ, (list, tuple)):
                type_checks.extend(typ)
              else:
                type_checks.append(typ)

            for typ in type_checks:
                if isinstance(val, typ):
                    ok = True
                    break
                elif hasattr(typ, 'isLiteralClass'):
                    try:
                        validator = typ(val)
                    except Exception as e:
                        errors.append(
                            "Failed to coerce to '{0}': {1}".format(typ, e))
                        pass
                    else:
                        validator.validate()
                        ok = True
                        break
                elif util.safe_issubclass(typ, ProtocolBase):
                    # force conversion- thus the val rather than validator assignment
                    try:
                        val = typ(**util.coerce_for_expansion(val))
                    except Exception as e:
                        errors.append(
                            "Failed to coerce to '{0}': {1}".format(typ, e))
                        pass
                    else:
                        val.validate()
                        ok = True
                        break

            if not ok:
                errstr = "\n".join(errors)
                raise validators.ValidationError(
                    "Object must be one of {0}: \n{1}".format(info['type'], errstr))

        elif info['type'] == 'array':
            instance = info['validator'](val)
            val = instance.validate()

        elif getattr(info['type'], 'isLiteralClass', False) is True:
            if not isinstance(val, info['type']):
                validator = info['type'](val)
            validator.validate()

        elif util.safe_issubclass(info['type'], ProtocolBase):
            if not isinstance(val, info['type']):
                val = info['type'](**util.coerce_for_expansion(val))

            val.validate()
        else:
            raise TypeError("Unknown object type: '{0}'".format(info['type']))

        self._properties[prop] = val
示例#17
0
    def create(name, item_constraint=None, **addl_constraints):
        """ Create an array validator based on the passed in constraints.

        If item_constraint is a tuple, it is assumed that tuple validation
        is being performed. If it is a class or dictionary, list validation
        will be performed. Classes are assumed to be subclasses of ProtocolBase,
        while dictionaries are expected to be basic types ('string', 'number', ...).

        addl_constraints is expected to be key-value pairs of any of the other
        constraints permitted by JSON Schema v4.
        """
        from python_jsonschema_objects import classbuilder
        klassbuilder = addl_constraints.pop("classbuilder", None)
        props = {}

        if item_constraint is not None:
            if isinstance(item_constraint, (tuple, list)):
                for i, elem in enumerate(item_constraint):
                    isdict = isinstance(elem, (dict,))
                    isklass = isinstance( elem, type) and util.safe_issubclass(
                        elem, (classbuilder.ProtocolBase, classbuilder.LiteralValue))

                    if not any([isdict, isklass]):
                        raise TypeError(
                            "Item constraint (position {0}) is not a schema".format(i))
            elif isinstance(item_constraint, classbuilder.TypeProxy):
                pass
            else:
                isdict = isinstance(item_constraint, (dict,))
                isklass = isinstance( item_constraint, type) and util.safe_issubclass(
                    item_constraint, (classbuilder.ProtocolBase, classbuilder.LiteralValue))

                if not any([isdict, isklass]):
                    raise TypeError("Item constraint is not a schema")

                if isdict and '$ref' in item_constraint:
                    if klassbuilder is None:
                        raise TypeError("Cannot resolve {0} without classbuilder"
                                        .format(item_constraint['$ref']))

                    uri = item_constraint['$ref']
                    if uri in klassbuilder.resolved:
                        logger.debug(util.lazy_format(
                            "Using previously resolved object for {0}", uri))
                    else:
                        logger.debug(util.lazy_format("Resolving object for {0}", uri))

                        with klassbuilder.resolver.resolving(uri) as resolved:
                            # Set incase there is a circular reference in schema definition
                            klassbuilder.resolved[uri] = None
                            klassbuilder.resolved[uri] = klassbuilder.construct(
                                uri,
                                resolved,
                                (classbuilder.ProtocolBase,))

                    item_constraint = klassbuilder.resolved[uri]

                elif isdict and item_constraint['type'] == 'array':
                    item_constraint = ArrayValidator.create(name + "#sub",
                                                            item_constraint=item_constraint[
                                                                'items'],
                                                            addl_constraints=item_constraint)

        props['__itemtype__'] = item_constraint

        props.update(addl_constraints)

        validator = type(str(name), (ArrayValidator,), props)

        return validator
    def setprop(self, val):
        if isinstance(info['type'], (list, tuple)):
            ok = False
            errors = []
            type_checks = []

            for typ in info['type']:
                if not isinstance(typ, dict):
                    type_checks.append(typ)
                    continue
                typ = next(t for n, t in validators.SCHEMA_TYPE_MAPPING
                           if typ['type'] == n)
                if typ is None:
                    typ = type(None)
                if isinstance(typ, (list, tuple)):
                    type_checks.extend(typ)
                else:
                    type_checks.append(typ)

            for typ in type_checks:
                if isinstance(val, typ):
                    ok = True
                    break
                elif hasattr(typ, 'isLiteralClass'):
                    try:
                        validator = typ(val)
                    except Exception as e:
                        errors.append("Failed to coerce to '{0}': {1}".format(
                            typ, e))
                        pass
                    else:
                        validator.validate()
                        ok = True
                        break
                elif util.safe_issubclass(typ, ProtocolBase):
                    # force conversion- thus the val rather than validator assignment
                    try:
                        val = typ(**util.coerce_for_expansion(val))
                    except Exception as e:
                        errors.append("Failed to coerce to '{0}': {1}".format(
                            typ, e))
                        pass
                    else:
                        val.validate()
                        ok = True
                        break
                elif util.safe_issubclass(
                        typ,
                        python_jsonschema_objects.wrapper_types.ArrayWrapper):
                    try:
                        val = typ(val)
                    except Exception as e:
                        errors.append("Failed to coerce to '{0}': {1}".format(
                            typ, e))
                        pass
                    else:
                        val.validate()
                        ok = True
                        break

            if not ok:
                errstr = "\n".join(errors)
                raise validators.ValidationError(
                    "Object must be one of {0}: \n{1}".format(
                        info['type'], errstr))

        elif info['type'] == 'array':
            val = info['validator'](val)
            val.validate()

        elif util.safe_issubclass(
                info['type'],
                python_jsonschema_objects.wrapper_types.ArrayWrapper):
            # An array type may have already been converted into an ArrayValidator
            val = info['type'](val)
            val.validate()

        elif getattr(info['type'], 'isLiteralClass', False) is True:
            if not isinstance(val, info['type']):
                validator = info['type'](val)
                validator.validate()
                if validator._value is not None:
                    # This allows setting of default Literal values
                    val = validator

        elif util.safe_issubclass(info['type'], ProtocolBase):
            if not isinstance(val, info['type']):
                val = info['type'](**util.coerce_for_expansion(val))

            val.validate()

        elif isinstance(info['type'], TypeProxy):
            val = info['type'](val)

        elif isinstance(info['type'], TypeRef):
            if not isinstance(val, info['type'].ref_class):
                val = info['type'](**val)

            val.validate()

        elif info['type'] is None:
            # This is the null value
            if val is not None:
                raise validators.ValidationError(
                    "None is only valid value for null")

        else:
            raise TypeError("Unknown object type: '{0}'".format(info['type']))

        self._properties[prop] = val
示例#19
0
    def create(name, item_constraint=None, **addl_constraints):
        """ Create an array validator based on the passed in constraints.

        If item_constraint is a tuple, it is assumed that tuple validation
        is being performed. If it is a class or dictionary, list validation
        will be performed. Classes are assumed to be subclasses of ProtocolBase,
        while dictionaries are expected to be basic types ('string', 'number', ...).

        addl_constraints is expected to be key-value pairs of any of the other
        constraints permitted by JSON Schema v4.
        """
        logger.debug(
            fmt("Constructing ArrayValidator with {} and {}", item_constraint,
                addl_constraints))
        from python_jsonschema_objects import classbuilder
        klassbuilder = addl_constraints.pop("classbuilder", None)
        props = {}

        if item_constraint is not None:
            if isinstance(item_constraint, (tuple, list)):
                for i, elem in enumerate(item_constraint):
                    isdict = isinstance(elem, (dict, ))
                    isklass = isinstance(elem, type) and util.safe_issubclass(
                        elem,
                        (classbuilder.ProtocolBase, classbuilder.LiteralValue))

                    if not any([isdict, isklass]):
                        raise TypeError(
                            "Item constraint (position {0}) is not a schema".
                            format(i))
            elif isinstance(item_constraint,
                            (classbuilder.TypeProxy, classbuilder.TypeRef)):
                pass
            elif util.safe_issubclass(item_constraint, ArrayWrapper):
                pass
            else:
                isdict = isinstance(item_constraint, (dict, ))
                isklass = isinstance(
                    item_constraint, type) and util.safe_issubclass(
                        item_constraint,
                        (classbuilder.ProtocolBase, classbuilder.LiteralValue))

                if not any([isdict, isklass]):
                    raise TypeError("Item constraint is not a schema")

                if isdict and '$ref' in item_constraint:
                    if klassbuilder is None:
                        raise TypeError(
                            "Cannot resolve {0} without classbuilder".format(
                                item_constraint['$ref']))

                    uri = item_constraint['$ref']
                    if uri in klassbuilder.resolved:
                        logger.debug(
                            util.lazy_format(
                                "Using previously resolved object for {0}",
                                uri))
                    else:
                        logger.debug(
                            util.lazy_format("Resolving object for {0}", uri))

                        with klassbuilder.resolver.resolving(uri) as resolved:
                            # Set incase there is a circular reference in schema definition
                            klassbuilder.resolved[uri] = None
                            klassbuilder.resolved[
                                uri] = klassbuilder.construct(
                                    uri, resolved,
                                    (classbuilder.ProtocolBase, ))

                    item_constraint = klassbuilder.resolved[uri]

                elif isdict and item_constraint.get('type') == 'array':
                    # We need to create a sub-array validator.
                    item_constraint = ArrayWrapper.create(
                        name + "#sub",
                        item_constraint=item_constraint['items'],
                        addl_constraints=item_constraint)
                elif isdict and 'oneOf' in item_constraint:
                    # We need to create a TypeProxy validator
                    uri = "{0}_{1}".format(name, "<anonymous_list_type>")
                    type_array = []
                    for i, item_detail in enumerate(item_constraint['oneOf']):
                        if '$ref' in item_detail:
                            subtype = klassbuilder.construct(
                                util.resolve_ref_uri(
                                    klassbuilder.resolver.resolution_scope,
                                    item_detail['$ref']), item_detail)
                        else:
                            subtype = klassbuilder.construct(
                                uri + "_%s" % i, item_detail)

                        type_array.append(subtype)

                    item_constraint = classbuilder.TypeProxy(type_array)

                elif isdict and item_constraint.get('type') == 'object':
                    """ We need to create a ProtocolBase object for this anonymous definition"""
                    uri = "{0}_{1}".format(name, "<anonymous_list_type>")
                    item_constraint = klassbuilder.construct(
                        uri, item_constraint)

        props['__itemtype__'] = item_constraint

        strict = addl_constraints.pop('strict', False)
        props['_strict_'] = strict
        props.update(addl_constraints)

        validator = type(str(name), (ArrayWrapper, ), props)

        return validator
示例#20
0
    def validate_items(self):
        """ Validates the items in the backing array, including
        performing type validation.

        Sets the _typed property and clears the dirty flag as a side effect

        Returns:
            The typed array
        """
        logger.debug(fmt("Validating {}", self))
        from python_jsonschema_objects import classbuilder

        if self.__itemtype__ is None:
            return

        type_checks = self.__itemtype__
        if not isinstance(type_checks, (tuple, list)):
            # we were given items = {'type': 'blah'} ; thus ensure the type for all data.
            type_checks = [type_checks] * len(self.data)
        elif len(type_checks) > len(self.data):
            raise ValidationError(
                "{1} does not have sufficient elements to validate against {0}"
                .format(self.__itemtype__, self.data))

        typed_elems = []
        for elem, typ in zip(self.data, type_checks):
            if isinstance(typ, dict):
                for param, paramval in six.iteritems(typ):
                    validator = registry(param)
                    if validator is not None:
                        validator(paramval, elem, typ)
                typed_elems.append(elem)

            elif util.safe_issubclass(typ, classbuilder.LiteralValue):
                val = typ(elem)
                val.validate()
                typed_elems.append(val)
            elif util.safe_issubclass(typ, classbuilder.ProtocolBase):
                if not isinstance(elem, typ):
                    try:
                        if isinstance(
                                elem,
                            (six.string_types, six.integer_types, float)):
                            val = typ(elem)
                        else:
                            val = typ(**util.coerce_for_expansion(elem))
                    except TypeError as e:
                        raise ValidationError(
                            "'{0}' is not a valid value for '{1}': {2}".format(
                                elem, typ, e))
                else:
                    val = elem
                val.validate()
                typed_elems.append(val)

            elif util.safe_issubclass(typ, ArrayWrapper):
                val = typ(elem)
                val.validate()
                typed_elems.append(val)

            elif isinstance(typ,
                            (classbuilder.TypeProxy, classbuilder.TypeRef)):
                try:
                    if isinstance(
                            elem,
                        (six.string_types, six.integer_types, float)):
                        val = typ(elem)
                    else:
                        val = typ(**util.coerce_for_expansion(elem))
                except TypeError as e:
                    raise ValidationError(
                        "'{0}' is not a valid value for '{1}': {2}".format(
                            elem, typ, e))
                else:
                    val.validate()
                    typed_elems.append(val)

        self._dirty = False
        self._typed = typed_elems
        return typed_elems
    def create(name, item_constraint=None, **addl_constraints):
        """ Create an array validator based on the passed in constraints.

        If item_constraint is a tuple, it is assumed that tuple validation
        is being performed. If it is a class or dictionary, list validation
        will be performed. Classes are assumed to be subclasses of ProtocolBase,
        while dictionaries are expected to be basic types ('string', 'number', ...).

        addl_constraints is expected to be key-value pairs of any of the other
        constraints permitted by JSON Schema v4.
        """
        logger.debug(
            fmt(
                "Constructing ArrayValidator with {} and {}",
                item_constraint,
                addl_constraints,
            )
        )
        from python_jsonschema_objects import classbuilder

        klassbuilder = addl_constraints.pop(
            "classbuilder", None
        )  # type: python_jsonschema_objects.classbuilder.ClassBuilder
        props = {}

        if item_constraint is not None:
            if isinstance(item_constraint, (tuple, list)):
                for i, elem in enumerate(item_constraint):
                    isdict = isinstance(elem, (dict,))
                    isklass = isinstance(elem, type) and util.safe_issubclass(
                        elem, (classbuilder.ProtocolBase, classbuilder.LiteralValue)
                    )

                    if not any([isdict, isklass]):
                        raise TypeError(
                            "Item constraint (position {0}) is not a schema".format(i)
                        )
            elif isinstance(
                item_constraint, (classbuilder.TypeProxy, classbuilder.TypeRef)
            ):
                pass
            elif util.safe_issubclass(item_constraint, ArrayWrapper):
                pass
            else:
                isdict = isinstance(item_constraint, (dict,))
                isklass = isinstance(item_constraint, type) and util.safe_issubclass(
                    item_constraint,
                    (classbuilder.ProtocolBase, classbuilder.LiteralValue),
                )

                if not any([isdict, isklass]):
                    raise TypeError("Item constraint is not a schema")

                if isdict and "$ref" in item_constraint:
                    if klassbuilder is None:
                        raise TypeError(
                            "Cannot resolve {0} without classbuilder".format(
                                item_constraint["$ref"]
                            )
                        )

                    item_constraint = klassbuilder.resolve_type(
                        item_constraint["$ref"], name
                    )

                elif isdict and item_constraint.get("type") == "array":
                    # We need to create a sub-array validator.
                    item_constraint = ArrayWrapper.create(
                        name + "#sub",
                        item_constraint=item_constraint["items"],
                        addl_constraints=item_constraint,
                    )
                elif isdict and "oneOf" in item_constraint:
                    # We need to create a TypeProxy validator
                    uri = "{0}_{1}".format(name, "<anonymous_list_type>")
                    type_array = klassbuilder.construct_objects(
                        item_constraint["oneOf"], uri
                    )

                    item_constraint = classbuilder.TypeProxy(type_array)

                elif isdict and item_constraint.get("type") == "object":
                    """ We need to create a ProtocolBase object for this anonymous definition"""
                    uri = "{0}_{1}".format(name, "<anonymous_list_type>")
                    item_constraint = klassbuilder.construct(uri, item_constraint)

        props["__itemtype__"] = item_constraint

        strict = addl_constraints.pop("strict", False)
        props["_strict_"] = strict
        props.update(addl_constraints)

        validator = type(str(name), (ArrayWrapper,), props)

        return validator
    def create(name, item_constraint=None, **addl_constraints):
        """ Create an array validator based on the passed in constraints.

        If item_constraint is a tuple, it is assumed that tuple validation
        is being performed. If it is a class or dictionary, list validation
        will be performed. Classes are assumed to be subclasses of ProtocolBase,
        while dictionaries are expected to be basic types ('string', 'number', ...).

        addl_constraints is expected to be key-value pairs of any of the other
        constraints permitted by JSON Schema v4.
        """
        from python_jsonschema_objects import classbuilder
        klassbuilder = addl_constraints.pop("classbuilder", None)
        props = {}

        if item_constraint is not None:
            if isinstance(item_constraint, (tuple, list)):
                for i, elem in enumerate(item_constraint):
                    isdict = isinstance(elem, (dict,))
                    isklass = isinstance( elem, type) and util.safe_issubclass(
                        elem, (classbuilder.ProtocolBase, classbuilder.LiteralValue))

                    if not any([isdict, isklass]):
                        raise TypeError(
                            "Item constraint (position {0}) is not a schema".format(i))
            elif isinstance(item_constraint, classbuilder.TypeProxy):
                pass
            elif util.safe_issubclass(item_constraint, ArrayValidator):
                pass
            else:
                isdict = isinstance(item_constraint, (dict,))
                isklass = isinstance( item_constraint, type) and util.safe_issubclass(
                    item_constraint, (classbuilder.ProtocolBase, classbuilder.LiteralValue))

                if not any([isdict, isklass]):
                    raise TypeError("Item constraint is not a schema")

                if isdict and '$ref' in item_constraint:
                    if klassbuilder is None:
                        raise TypeError("Cannot resolve {0} without classbuilder"
                                        .format(item_constraint['$ref']))

                    uri = item_constraint['$ref']
                    if uri in klassbuilder.resolved:
                        logger.debug(util.lazy_format(
                            "Using previously resolved object for {0}", uri))
                    else:
                        logger.debug(util.lazy_format("Resolving object for {0}", uri))

                        with klassbuilder.resolver.resolving(uri) as resolved:
                            # Set incase there is a circular reference in schema definition
                            klassbuilder.resolved[uri] = None
                            klassbuilder.resolved[uri] = klassbuilder.construct(
                                uri,
                                resolved,
                                (classbuilder.ProtocolBase,))

                    item_constraint = klassbuilder.resolved[uri]

                elif isdict and item_constraint.get('type') == 'array':
                    # We need to create a sub-array validator.
                    item_constraint = ArrayValidator.create(name + "#sub",
                                                            item_constraint=item_constraint[
                                                                'items'],
                                                            addl_constraints=item_constraint)
                elif isdict and 'oneOf' in item_constraint:
                    # We need to create a TypeProxy validator
                    uri = "{0}_{1}".format(name, "<anonymous_list_type>")
                    type_array = []
                    for i, item_detail in enumerate(item_constraint['oneOf']):
                        if '$ref' in item_detail:
                            subtype = klassbuilder.construct(
                                util.resolve_ref_uri(
                                    klassbuilder.resolver.resolution_scope,
                                    item_detail['$ref']),
                                item_detail)
                        else:
                            subtype = klassbuilder.construct(
                                uri + "_%s" % i, item_detail)

                        type_array.append(subtype)

                    item_constraint = classbuilder.TypeProxy(type_array)

        props['__itemtype__'] = item_constraint

        props.update(addl_constraints)

        validator = type(str(name), (ArrayValidator,), props)

        return validator
    def setprop(self, val):
        if isinstance(info['type'], (list, tuple)):
            ok = False
            errors = []
            type_checks = []

            for typ in info['type']:
              if not isinstance(typ, dict):
                type_checks.append(typ)
                continue
              typ = next(t
                         for n, t in validators.SCHEMA_TYPE_MAPPING
                         if typ['type'] == t)
              if typ is None:
                  typ = type(None)
              if isinstance(typ, (list, tuple)):
                  type_checks.extend(typ)
              else:
                  type_checks.append(typ)

            for typ in type_checks:
                if isinstance(val, typ):
                    ok = True
                    break
                elif hasattr(typ, 'isLiteralClass'):
                    try:
                        validator = typ(val)
                    except Exception as e:
                        errors.append(
                            "Failed to coerce to '{0}': {1}".format(typ, e))
                        pass
                    else:
                        validator.validate()
                        ok = True
                        break
                elif util.safe_issubclass(typ, ProtocolBase):
                    # force conversion- thus the val rather than validator assignment
                    try:
                        val = typ(**util.coerce_for_expansion(val))
                    except Exception as e:
                        errors.append(
                            "Failed to coerce to '{0}': {1}".format(typ, e))
                        pass
                    else:
                        val.validate()
                        ok = True
                        break
                elif util.safe_issubclass(typ, validators.ArrayValidator):
                    try:
                        val = typ(val)
                    except Exception as e:
                        errors.append(
                            "Failed to coerce to '{0}': {1}".format(typ, e))
                        pass
                    else:
                        val.validate()
                        ok = True
                        break

            if not ok:
                errstr = "\n".join(errors)
                raise validators.ValidationError(
                    "Object must be one of {0}: \n{1}".format(info['type'], errstr))

        elif info['type'] == 'array':
            instance = info['validator'](val)
            val = instance.validate()

        elif util.safe_issubclass(info['type'], validators.ArrayValidator):
            # An array type may have already been converted into an ArrayValidator
            instance = info['type'](val)
            val = instance.validate()

        elif getattr(info['type'], 'isLiteralClass', False) is True:
            if not isinstance(val, info['type']):
                validator = info['type'](val)
            validator.validate()

        elif util.safe_issubclass(info['type'], ProtocolBase):
            if not isinstance(val, info['type']):
                val = info['type'](**util.coerce_for_expansion(val))

            val.validate()

        elif isinstance(info['type'], TypeProxy):
            val = info['type'](val)

        elif info['type'] is None:
            # This is the null value
            if val is not None:
                raise validators.ValidationError(
                    "None is only valid value for null")

        else:
            raise TypeError("Unknown object type: '{0}'".format(info['type']))

        self._properties[prop] = val
示例#24
0
    def _construct(self, uri, clsdata, parent=(ProtocolBase, )):
        if 'oneOf' in clsdata:
            potential_parents = self.resolve_classes(clsdata['oneOf'])

            for p in potential_parents:
                if util.safe_issubclass(p, ProtocolBase):
                    self.resolved[uri] = self._build_object(
                        uri, clsdata, (p, ))
                else:
                    raise Exception("Don't know how to deal with this")

            return self.resolved[uri]

        elif 'anyOf' in clsdata:
            raise NotImplementedError(
                "anyOf is not supported as bare property")

        elif 'allOf' in clsdata:
            potential_parents = self.resolve_classes(clsdata['allOf'])
            parents = []
            for p in potential_parents:
                if isinstance(p, dict):
                    # This is additional constraints
                    clsdata.update(p)
                elif util.safe_issubclass(p, ProtocolBase):
                    parents.append(p)

            self.resolved[uri] = self._build_object(uri, clsdata, parents)
            return self.resolved[uri]

        elif '$ref' in clsdata:

            if 'type' in clsdata and util.safe_issubclass(
                    clsdata['type'], (ProtocolBase, LiteralValue)):
                # It's possible that this reference was already resolved, in which
                # case it will have its type parameter set
                logging.debug(
                    "Using previously resolved type "
                    "(with different URI) for %s", uri)
                self.resolved[uri] = clsdata['type']
            elif uri in self.resolved:
                logging.debug("Using previously resolved object for %s", uri)
            else:
                logging.debug("Resolving object for %s", uri)

                with self.resolver.resolving(uri) as resolved:
                    self.resolved[
                        uri] = None  # Set incase there is a circular reference in schema definition
                    self.resolved[uri] = self._build_object(
                        uri, resolved, parent)

            return self.resolved[uri]

        elif clsdata.get('type') == 'array' and 'items' in clsdata:
            self.resolved[uri] = self._build_object(uri, clsdata, parent)

        elif (clsdata.get('type', None) == 'object'
              or clsdata.get('properties', None) is not None
              or clsdata.get('additionalProperties', False)):
            self.resolved[uri] = self._build_object(uri, clsdata, parent)
            return self.resolved[uri]
        elif clsdata.get('type') in ('integer', 'number', 'string', 'boolean',
                                     'null'):
            self.resolved[uri] = self._build_literal(uri, clsdata)
            return self.resolved[uri]
        elif 'enum' in clsdata:
            obj = self._build_literal(uri, clsdata)
            self.resolved[uri] = obj
            return obj

        elif 'type' in clsdata and util.safe_issubclass(
                clsdata['type'], ProtocolBase):
            self.resolved[uri] = clsdata.get('type')
            return self.resolved[uri]
        else:
            raise NotImplementedError(
                "Unable to parse schema object '{0}' with "
                "no type and no reference".format(clsdata))