Exemple #1
0
    def validate(self):
        """Applies all defined validation to the current
        state of the object, and raises an error if
        they are not all met.

        Raises:
            ValidationError: if validations do not pass
        """

        missing = self.missing_property_names()

        if len(missing) > 0:
            raise validators.ValidationError(
                "'{0}' are required attributes for {1}".format(
                    missing, self.__class__.__name__))

        for prop, val in six.iteritems(self._properties):
            if val is None:
                continue

            if isinstance(val, ProtocolBase):
                val.validate()
            elif getattr(val, "isLiteralClass", None) is True:
                val.validate()
            elif isinstance(val, list):
                for subval in val:
                    subval.validate()
            else:
                # This object is of the wrong type, but just try setting it
                # The property setter will enforce its correctness
                # and handily coerce its type at the same time
                setattr(self, prop, val)

        return True
Exemple #2
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
Exemple #3
0
    def validate(self):
        propname = lambda x: self.__prop_names__[x]
        missing = [
            x for x in self.__required__ if propname(x) not in self._properties
            or self._properties[propname(x)] is None
        ]

        if len(missing) > 0:
            raise validators.ValidationError(
                "'{0}' are required attributes for {1}".format(
                    missing, self.__class__))

        for prop, val in self._properties.iteritems():
            if val is None:
                continue

            if isinstance(val, ProtocolBase):
                val.validate()
            elif getattr(val, 'isLiteralClass', None) is True:
                val.validate()
            elif isinstance(val, list):
                for subval in val:
                    subval.validate()
            else:
                # This object is of the wrong type, but just try setting it
                # The property setter will enforce its correctness
                # and handily coerce its type at the same time
                setattr(self, prop, val)

        return True
    def instantiate(self, name, val):
        import python_jsonschema_objects.classbuilder as cb

        for p in self._pattern_types:
            if p.pattern.search(name):
                logger.debug(
                    "Found patternProperties match: %s %s" % (p.pattern.pattern, name)
                )
                return self._make_type(p.schema_type, val)

        if self._additional_type is True:

            valtype = [
                k
                for k, t in validators.SCHEMA_TYPE_MAPPING
                if t is not None and isinstance(val, t)
            ]
            valtype = valtype[0]
            return MakeLiteral(name, valtype, val)

        elif isinstance(self._additional_type, type):
            return self._make_type(self._additional_type, val)

        raise validators.ValidationError(
            "additionalProperties not permitted " "and no patternProperties specified"
        )
Exemple #5
0
    def __setattr__(self, name, val):
        if name.startswith("__donttouch_"):
            object.__setattr__(self, name, val)
            return

        inverter = dict((v, k) for k, v in six.iteritems(self.__prop_names__))

        # If name is a sanitized version (e.g. base_var) of the actual property (e.g. "base var"), invert it back so that the following lookups work properly.
        # The bigger problem appears to be the fact that the __prop_names__ mapping is somewhat backwards...
        if name in inverter:
            name = inverter[name]

        if name in self.__object_attr_list__:
            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 = getattr(self.__class__, self.__prop_names__[name])
            prop.fset(self, val)
        else:
            # This is an additional property of some kind
            try:
                val = self.__extensible__.instantiate(name, val)
            except Exception as e:
                raise validators.ValidationError(
                    "Attempted to set unknown property '{0}': {1} ".format(
                        name, e))

            self._extended_properties[name] = val
Exemple #6
0
    def setprop(this, val):
        if isinstance(info['type'], (list, tuple)):
            ok = False
            errors = []
            for typ in info['type']:
                if isinstance(val, typ):
                    ok = True
                    break
                elif getattr(typ, 'isLiteralClass'):
                    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
                elif issubclass(typ, ProtocolBase):
                    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']):
                val = info['type'](val)

        elif issubclass(info['type'], ProtocolBase):
            if not isinstance(val, info['type']):
                val = info['type'](**val)

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

        this._properties[prop] = val
Exemple #7
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 in self.__object_attr_list__:
            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 = getattr(self.__class__, self.__prop_names__[name])
            prop.fset(self, val)
        else:
            # This is an additional property of some kind
            try:
                val = self.__extensible__.instantiate(name, val)
            except Exception as e:
                raise validators.ValidationError(
                    "Attempted to set unknown property '{0}': {1} ".format(
                        name, e))

            self._extended_properties[name] = val
Exemple #9
0
    def __call__(self, *a, **kw):
        validation_errors = []
        valid_types = self._types
        for klass in valid_types:
            logger.debug(
                util.lazy_format("Attempting to instantiate {0} as {1}",
                                 self.__class__, klass))
            try:
                obj = klass(*a, **kw)
            except TypeError as e:
                validation_errors.append((klass, e))
            except validators.ValidationError as e:
                validation_errors.append((klass, e))
            else:
                return obj

        else:  # We got nothing
            raise validators.ValidationError(
                "Unable to instantiate any valid types: \n"
                "".join("{0}: {1}\n".format(k, e)
                        for k, e in validation_errors))
Exemple #10
0
    def __new__(cls, **props):
        """ Overridden to support oneOf, where we need to
        instantiate a different class depending on what
        value we've seen """
        if getattr(cls, "__validation__", None) is None:
            new = super(ProtocolBase, cls).__new__
            if new is object.__new__:
                return new(cls)
            return new(cls, **props)

        valid_types = cls.__validation__.get("type", None)

        if valid_types is None or not isinstance(valid_types, list):
            new = super(ProtocolBase, cls).__new__
            if new is object.__new__:
                return new(cls)
            return new(cls, **props)

        obj = None
        validation_errors = []
        for klass in valid_types:
            logger.debug(
                util.lazy_format("Attempting to instantiate {0} as {1}", cls, klass)
            )
            try:
                obj = klass(**props)
                obj.validate()
            except validators.ValidationError as e:
                validation_errors.append((klass, e))
            else:
                break

        else:  # We got nothing
            raise validators.ValidationError(
                "Unable to instantiate any valid types: \n"
                "".join("{0}: {1}\n".format(k, e) for k, e in validation_errors)
            )

        return obj
Exemple #11
0
    def _build_object(self, nm, clsdata, parents, **kw):
        logger.debug(util.lazy_format("Building object {0}", nm))

        # To support circular references, we tag objects that we're
        # currently building as "under construction"
        self.under_construction.add(nm)

        props = {}
        defaults = set()

        properties = {}
        for p in parents:
            properties = util.propmerge(properties, p.__propinfo__)

        if "properties" in clsdata:
            properties = util.propmerge(properties, clsdata["properties"])

        name_translation = {}

        for prop, detail in properties.items():
            logger.debug(util.lazy_format("Handling property {0}.{1}", nm, prop))
            properties[prop]["raw_name"] = prop
            name_translation[prop] = prop.replace("@", "")
            prop = name_translation[prop]

            if detail.get("default", None) is not None:
                defaults.add(prop)

            if detail.get("type", None) == "object":
                uri = "{0}/{1}_{2}".format(nm, prop, "<anonymous>")
                self.resolved[uri] = self.construct(uri, detail, (ProtocolBase,))

                props[prop] = make_property(
                    prop, {"type": self.resolved[uri]}, self.resolved[uri].__doc__
                )
                properties[prop]["type"] = self.resolved[uri]

            elif "type" not in detail and "$ref" in detail:
                ref = detail["$ref"]
                typ = self.resolve_type(ref, ".".join([nm, prop]))

                props[prop] = make_property(prop, {"type": typ}, typ.__doc__)
                properties[prop]["$ref"] = ref
                properties[prop]["type"] = typ

            elif "oneOf" in detail:
                potential = self.expand_references(nm, detail["oneOf"])
                logger.debug(
                    util.lazy_format("Designating {0} as oneOf {1}", prop, potential)
                )
                desc = detail["description"] if "description" in detail else ""
                props[prop] = make_property(prop, {"type": potential}, desc)

            elif "type" in detail and detail["type"] == "array":
                if "items" in detail and isinstance(detail["items"], dict):
                    if "$ref" in detail["items"]:
                        typ = self.resolve_type(detail["items"]["$ref"], nm)
                        constraints = copy.copy(detail)
                        constraints["strict"] = kw.get("strict")
                        propdata = {
                            "type": "array",
                            "validator": python_jsonschema_objects.wrapper_types.ArrayWrapper.create(
                                nm, item_constraint=typ, **constraints
                            ),
                        }

                    else:
                        uri = "{0}/{1}_{2}".format(nm, prop, "<anonymous_field>")
                        try:
                            if "oneOf" in detail["items"]:
                                typ = TypeProxy(
                                    self.construct_objects(
                                        detail["items"]["oneOf"], uri
                                    )
                                )
                            else:
                                typ = self.construct(uri, detail["items"])

                            constraints = copy.copy(detail)
                            constraints["strict"] = kw.get("strict")
                            propdata = {
                                "type": "array",
                                "validator": python_jsonschema_objects.wrapper_types.ArrayWrapper.create(
                                    uri, item_constraint=typ, **constraints
                                ),
                            }

                        except NotImplementedError:
                            typ = detail["items"]
                            constraints = copy.copy(detail)
                            constraints["strict"] = kw.get("strict")
                            propdata = {
                                "type": "array",
                                "validator": python_jsonschema_objects.wrapper_types.ArrayWrapper.create(
                                    uri, item_constraint=typ, **constraints
                                ),
                            }

                    props[prop] = make_property(prop, propdata, typ.__doc__)
                elif "items" in detail:
                    typs = []
                    for i, elem in enumerate(detail["items"]):
                        uri = "{0}/{1}/<anonymous_{2}>".format(nm, prop, i)
                        typ = self.construct(uri, elem)
                        typs.append(typ)

                    props[prop] = make_property(prop, {"type": typs})

            else:
                desc = detail["description"] if "description" in detail else ""
                uri = "{0}/{1}".format(nm, prop)
                typ = self.construct(uri, detail)

                props[prop] = make_property(prop, {"type": typ}, desc)

        props["__extensible__"] = pattern_properties.ExtensibleValidator(
            nm, clsdata, self
        )

        props["__prop_names__"] = name_translation

        props["__propinfo__"] = properties
        required = set.union(*[p.__required__ for p in parents])

        if "required" in clsdata:
            for prop in clsdata["required"]:
                required.add(prop)

        invalid_requires = [req for req in required if req not in props["__propinfo__"]]
        if len(invalid_requires) > 0:
            raise validators.ValidationError(
                "Schema Definition Error: {0} schema requires "
                "'{1}', but properties are not defined".format(nm, invalid_requires)
            )

        props["__required__"] = required
        props["__has_default__"] = defaults
        if required and kw.get("strict"):
            props["__strict__"] = True

        props["__title__"] = clsdata.get("title")
        cls = type(str(nm.split("/")[-1]), tuple(parents), props)
        self.under_construction.remove(nm)

        return cls
Exemple #12
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
Exemple #13
0
    def _build_object(self, nm, clsdata, parents):
        logger.debug(util.lazy_format("Building object {0}", nm))

        props = {}

        properties = {}
        for p in parents:
            properties = util.propmerge(properties, p.__propinfo__)

        if 'properties' in clsdata:
            properties = util.propmerge(properties, clsdata['properties'])

        name_translation = {}

        for prop, detail in properties.items():
            properties[prop]['raw_name'] = prop
            name_translation[prop] = prop.replace('@', '')
            prop = name_translation[prop]

            if detail.get('type', None) == 'object':
                uri = "{0}/{1}_{2}".format(nm, prop, "<anonymous>")
                self.resolved[uri] = self.construct(uri, detail,
                                                    (ProtocolBase, ))

                props[prop] = make_property(prop, {'type': self.resolved[uri]},
                                            self.resolved[uri].__doc__)
                properties[prop]['type'] = self.resolved[uri]

            elif 'type' not in detail and '$ref' in detail:
                ref = detail['$ref']
                uri = util.resolve_ref_uri(self.resolver.resolution_scope, ref)
                if uri not in self.resolved:
                    with self.resolver.resolving(ref) as resolved:
                        self.resolved[uri] = self.construct(
                            uri, resolved, (ProtocolBase, ))

                props[prop] = make_property(prop, {'type': self.resolved[uri]},
                                            self.resolved[uri].__doc__)
                properties[prop]['$ref'] = uri
                properties[prop]['type'] = self.resolved[uri]

            elif 'oneOf' in detail:
                potential = self.resolve_classes(detail['oneOf'])
                logger.debug(
                    util.lazy_format("Designating {0} as oneOf {1}", prop,
                                     potential))
                desc = detail['description'] if 'description' in detail else ""
                props[prop] = make_property(prop, {'type': potential}, desc)

            elif 'type' in detail and detail['type'] == 'array':
                if 'items' in detail and isinstance(detail['items'], dict):
                    if '$ref' in detail['items']:
                        uri = util.resolve_ref_uri(
                            self.resolver.resolution_scope,
                            detail['items']['$ref'])
                        typ = self.construct(uri, detail['items'])
                        propdata = {
                            'type':
                            'array',
                            'validator':
                            validators.ArrayValidator.create(
                                uri, item_constraint=typ)
                        }
                    else:
                        uri = "{0}/{1}_{2}".format(nm, prop,
                                                   "<anonymous_field>")
                        try:
                            if 'oneOf' in detail['items']:
                                typ = TypeProxy([
                                    self.construct(uri + "_%s" % i,
                                                   item_detail) if '$ref'
                                    not in item_detail else self.construct(
                                        util.resolve_ref_uri(
                                            self.resolver.resolution_scope,
                                            item_detail['$ref']), item_detail)
                                    for i, item_detail in enumerate(
                                        detail['items']['oneOf'])
                                ])
                            else:
                                typ = self.construct(uri, detail['items'])
                            propdata = {
                                'type':
                                'array',
                                'validator':
                                validators.ArrayValidator.create(
                                    uri,
                                    item_constraint=typ,
                                    addl_constraints=detail)
                            }
                        except NotImplementedError:
                            typ = detail['items']
                            propdata = {
                                'type':
                                'array',
                                'validator':
                                validators.ArrayValidator.create(
                                    uri,
                                    item_constraint=typ,
                                    addl_constraints=detail)
                            }

                    props[prop] = make_property(prop, propdata, typ.__doc__)
                elif 'items' in detail:
                    typs = []
                    for i, elem in enumerate(detail['items']):
                        uri = "{0}/{1}/<anonymous_{2}>".format(nm, prop, i)
                        typ = self.construct(uri, detail['items'])
                        typs.append(typ)

                    props[prop] = make_property(prop, {
                        'type': 'tuple',
                        'items': typ
                    }, typ.__doc__)

            else:
                desc = detail['description'] if 'description' in detail else ""
                uri = "{0}/{1}".format(nm, prop)
                typ = self.construct(uri, detail)

                props[prop] = make_property(prop, {'type': typ}, desc)
        """ If this object itself has a 'oneOf' designation, then
        make the validation 'type' the list of potential objects.
        """
        if 'oneOf' in clsdata:
            klasses = self.resolve_classes(clsdata['oneOf'])
            # Need a validation to check that it meets one of them
            props['__validation__'] = {'type': klasses}

        props['__extensible__'] = True
        if 'additionalProperties' in clsdata:
            addlProp = clsdata['additionalProperties']

            if addlProp is False:
                props['__extensible__'] = False
            elif addlProp is True:
                props['__extensible__'] = True
            else:
                if '$ref' in addlProp:
                    refs = self.resolve_classes([addlProp])
                else:
                    uri = "{0}/{1}_{2}".format(nm, "<additionalProperties>",
                                               "<anonymous>")
                    self.resolved[uri] = self.construct(
                        uri, addlProp, (ProtocolBase, ))
                    refs = [self.resolved[uri]]

                props['__extensible__'] = refs[0]

        props['__prop_names__'] = name_translation

        props['__propinfo__'] = properties
        required = set.union(*[p.__required__ for p in parents])

        if 'required' in clsdata:
            for prop in clsdata['required']:
                required.add(prop)

        invalid_requires = [
            req for req in required if req not in props['__propinfo__']
        ]
        if len(invalid_requires) > 0:
            raise validators.ValidationError(
                "Schema Definition Error: {0} schema requires "
                "'{1}', but properties are not defined".format(
                    nm, invalid_requires))

        props['__required__'] = required

        cls = type(str(nm.split('/')[-1]), tuple(parents), props)

        return cls
Exemple #14
0
    def _build_object(self, nm, clsdata, parents, **kw):
        logger.debug(util.lazy_format("Building object {0}", nm))

        # To support circular references, we tag objects that we're
        # currently building as "under construction"
        self.under_construction.append(nm)

        props = {}
        defaults = set()

        properties = {}
        for p in parents:
            properties = util.propmerge(properties, p.__propinfo__)

        if 'properties' in clsdata:
            properties = util.propmerge(properties, clsdata['properties'])

        name_translation = {}

        for prop, detail in properties.items():
            logger.debug(
                util.lazy_format("Handling property {0}.{1}", nm, prop))
            properties[prop]['raw_name'] = prop
            name_translation[prop] = prop.replace('@', '')
            prop = name_translation[prop]

            if detail.get('default', None) is not None:
                defaults.add(prop)

            if detail.get('type', None) == 'object':
                uri = "{0}/{1}_{2}".format(nm, prop, "<anonymous>")
                self.resolved[uri] = self.construct(uri, detail,
                                                    (ProtocolBase, ))

                props[prop] = make_property(prop, {'type': self.resolved[uri]},
                                            self.resolved[uri].__doc__)
                properties[prop]['type'] = self.resolved[uri]

            elif 'type' not in detail and '$ref' in detail:
                ref = detail['$ref']
                uri = util.resolve_ref_uri(self.resolver.resolution_scope, ref)
                logger.debug(
                    util.lazy_format("Resolving reference {0} for {1}.{2}",
                                     ref, nm, prop))
                if uri not in self.resolved:
                    """
                    if $ref is under construction, then we're staring at a
                    circular reference.  We save the information required to
                    construct the property for later.
                    """
                    if uri in self.under_construction:
                        self.pending.add(
                            UnresolvedProperty(uri=nm,
                                               property_name=prop,
                                               refuri=uri,
                                               is_array=False))
                        continue

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

                props[prop] = make_property(prop, {'type': self.resolved[uri]},
                                            self.resolved[uri].__doc__)
                properties[prop]['$ref'] = uri
                properties[prop]['type'] = self.resolved[uri]

            elif 'oneOf' in detail:
                potential = self.resolve_classes(detail['oneOf'])
                logger.debug(
                    util.lazy_format("Designating {0} as oneOf {1}", prop,
                                     potential))
                desc = detail['description'] if 'description' in detail else ""
                props[prop] = make_property(prop, {'type': potential}, desc)

            elif 'type' in detail and detail['type'] == 'array':
                if 'items' in detail and isinstance(detail['items'], dict):
                    if '$ref' in detail['items']:
                        ref = detail['items']['$ref']
                        uri = util.resolve_ref_uri(
                            self.resolver.resolution_scope, ref)

                        if uri not in self.resolved and uri in self.under_construction:
                            """
                            if $ref is under construction, then we're staring at a
                            circular reference.  We save the information required to
                            construct the property for later.
                            """
                            self.pending.add(
                                UnresolvedProperty(uri=nm,
                                                   property_name=prop,
                                                   refuri=uri,
                                                   is_array=True))
                            continue
                        else:
                            typ = self.construct(uri, detail['items'])
                            propdata = {
                                'type':
                                'array',
                                'validator':
                                python_jsonschema_objects.wrapper_types.
                                ArrayWrapper.create(uri, item_constraint=typ)
                            }
                    else:
                        uri = "{0}/{1}_{2}".format(nm, prop,
                                                   "<anonymous_field>")
                        try:
                            if 'oneOf' in detail['items']:
                                typ = TypeProxy([
                                    self.construct(uri + "_%s" % i,
                                                   item_detail) if '$ref'
                                    not in item_detail else self.construct(
                                        util.resolve_ref_uri(
                                            self.resolver.resolution_scope,
                                            item_detail['$ref']), item_detail)
                                    for i, item_detail in enumerate(
                                        detail['items']['oneOf'])
                                ])
                            else:
                                typ = self.construct(uri, detail['items'])
                            propdata = {
                                'type':
                                'array',
                                'validator':
                                python_jsonschema_objects.wrapper_types.
                                ArrayWrapper.create(uri,
                                                    item_constraint=typ,
                                                    addl_constraints=detail)
                            }
                        except NotImplementedError:
                            typ = detail['items']
                            propdata = {
                                'type':
                                'array',
                                'validator':
                                python_jsonschema_objects.wrapper_types.
                                ArrayWrapper.create(uri,
                                                    item_constraint=typ,
                                                    addl_constraints=detail)
                            }

                    props[prop] = make_property(prop, propdata, typ.__doc__)
                elif 'items' in detail:
                    typs = []
                    for i, elem in enumerate(detail['items']):
                        uri = "{0}/{1}/<anonymous_{2}>".format(nm, prop, i)
                        typ = self.construct(uri, detail['items'])
                        typs.append(typ)

                    props[prop] = make_property(prop, {
                        'type': 'tuple',
                        'items': typ
                    }, typ.__doc__)

            else:
                desc = detail['description'] if 'description' in detail else ""
                uri = "{0}/{1}".format(nm, prop)
                typ = self.construct(uri, detail)

                props[prop] = make_property(prop, {'type': typ}, desc)
        """ If this object itself has a 'oneOf' designation, then
        make the validation 'type' the list of potential objects.
        """
        if 'oneOf' in clsdata:
            klasses = self.resolve_classes(clsdata['oneOf'])
            # Need a validation to check that it meets one of them
            props['__validation__'] = {'type': klasses}

        props['__extensible__'] = pattern_properties.ExtensibleValidator(
            nm, clsdata, self)

        props['__prop_names__'] = name_translation

        props['__propinfo__'] = properties
        required = set.union(*[p.__required__ for p in parents])

        if 'required' in clsdata:
            for prop in clsdata['required']:
                required.add(prop)

        invalid_requires = [
            req for req in required if req not in props['__propinfo__']
        ]
        if len(invalid_requires) > 0:
            raise validators.ValidationError(
                "Schema Definition Error: {0} schema requires "
                "'{1}', but properties are not defined".format(
                    nm, invalid_requires))

        props['__required__'] = required
        props['__has_default__'] = defaults
        if required and kw.get("strict"):
            props['__strict__'] = True
        cls = type(str(nm.split('/')[-1]), tuple(parents), props)
        self.under_construction.remove(nm)

        return cls
    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
Exemple #16
0
    def _build_object(self, nm, clsdata, parents, **kw):
        logger.debug(util.lazy_format("Building object {0}", nm))
        clsdata_hash = hash_dict(clsdata)

        props = {}

        properties = {}
        for p in parents:
            properties = util.propmerge(properties, p.__propinfo__)

        if 'properties' in clsdata:
            properties = util.propmerge(properties, clsdata['properties'])

        name_translation = {}

        for prop, detail in properties.items():
            logger.debug(
                util.lazy_format("Handling property {0}.{1}", nm, prop))
            properties[prop]['raw_name'] = prop
            name_translation[prop] = prop.replace('@', '').replace(' ', '_')
            raw_prop = prop
            prop = name_translation[prop]

            if detail.get('type', None) == 'object':
                #~ uri = "{0}/{1}_{2}".format(nm,
                #~ prop, "<anonymous>")
                # Re-use existing submodules if possible
                uri = detail['title']
                # Scrub raw_name since that's a function of this property but not of the substructure.
                detail_clean = dict(detail)
                del detail_clean['raw_name']
                self.resolved[uri] = self.construct(uri, detail_clean,
                                                    (ProtocolBase, ))

                props[prop] = make_property(prop, {'type': self.resolved[uri]},
                                            self.resolved[uri].__doc__)
                properties[raw_prop]['type'] = self.resolved[uri]

            elif 'type' not in detail and '$ref' in detail:
                ref = detail['$ref']
                uri = util.resolve_ref_uri(self.resolver.resolution_scope, ref)
                logger.debug(
                    util.lazy_format("Resolving reference {0} for {1}.{2}",
                                     ref, nm, prop))
                if uri not in self.resolved:
                    with self.resolver.resolving(ref) as resolved:
                        self.resolved[uri] = self.construct(
                            uri, resolved, (ProtocolBase, ))

                props[prop] = make_property(prop, {'type': self.resolved[uri]},
                                            self.resolved[uri].__doc__)
                properties[prop]['$ref'] = uri
                properties[prop]['type'] = self.resolved[uri]

            elif 'oneOf' in detail:
                potential = self.resolve_classes(detail['oneOf'])
                logger.debug(
                    util.lazy_format("Designating {0} as oneOf {1}", prop,
                                     potential))
                desc = detail['description'] if 'description' in detail else ""
                props[prop] = make_property(prop, {'type': potential}, desc)

            elif 'type' in detail and detail['type'] == 'array':
                if 'items' in detail and isinstance(detail['items'], dict):
                    if '$ref' in detail['items']:
                        uri = util.resolve_ref_uri(
                            self.resolver.resolution_scope,
                            detail['items']['$ref'])
                        typ = self.construct(uri, detail['items'])
                        propdata = {
                            'type':
                            'array',
                            'validator':
                            python_jsonschema_objects.wrapper_types.
                            ArrayWrapper.create(uri, item_constraint=typ)
                        }
                    else:
                        uri = "{0}/{1}_{2}".format(nm, prop,
                                                   "<anonymous_field>")
                        try:
                            if 'oneOf' in detail['items']:
                                typ = TypeProxy([
                                    self.construct(uri + "_%s" % i,
                                                   item_detail) if '$ref'
                                    not in item_detail else self.construct(
                                        util.resolve_ref_uri(
                                            self.resolver.resolution_scope,
                                            item_detail['$ref']), item_detail)
                                    for i, item_detail in enumerate(
                                        detail['items']['oneOf'])
                                ])
                            else:
                                # Re-use existing submodules if possible
                                uri = detail['items']['title']
                                typ = self.construct(uri, detail['items'])
                            propdata = {
                                'type':
                                'array',
                                'validator':
                                python_jsonschema_objects.wrapper_types.
                                ArrayWrapper.create(uri,
                                                    item_constraint=typ,
                                                    addl_constraints=detail)
                            }
                        except NotImplementedError:
                            typ = detail['items']
                            propdata = {
                                'type':
                                'array',
                                'validator':
                                python_jsonschema_objects.wrapper_types.
                                ArrayWrapper.create(uri,
                                                    item_constraint=typ,
                                                    addl_constraints=detail)
                            }

                    props[prop] = make_property(prop, propdata, typ.__doc__)
                elif 'items' in detail:
                    typs = []
                    for i, elem in enumerate(detail['items']):
                        uri = "{0}/{1}/<anonymous_{2}>".format(nm, prop, i)
                        typ = self.construct(uri, detail['items'])
                        typs.append(typ)

                    props[prop] = make_property(prop, {
                        'type': 'tuple',
                        'items': typ
                    }, typ.__doc__)

            else:
                desc = detail['description'] if 'description' in detail else ""
                uri = "{0}/{1}".format(nm, prop)
                typ = self.construct(uri, detail)

                props[prop] = make_property(prop, {'type': typ}, desc)
        """ If this object itself has a 'oneOf' designation, then
        make the validation 'type' the list of potential objects.
        """
        if 'oneOf' in clsdata:
            klasses = self.resolve_classes(clsdata['oneOf'])
            # Need a validation to check that it meets one of them
            props['__validation__'] = {'type': klasses}

        props['__extensible__'] = pattern_properties.ExtensibleValidator(
            nm, clsdata, self)

        props['__prop_names__'] = name_translation

        props['__propinfo__'] = properties
        required = set.union(*[p.__required__ for p in parents])

        if 'required' in clsdata:
            for prop in clsdata['required']:
                required.add(prop)

        invalid_requires = [
            req for req in required if req not in props['__propinfo__']
        ]
        if len(invalid_requires) > 0:
            raise validators.ValidationError(
                "Schema Definition Error: {0} schema requires "
                "'{1}', but properties are not defined".format(
                    nm, invalid_requires))

        props['__required__'] = required
        props['__clsdata_hash__'] = clsdata_hash
        if required and kw.get("strict"):
            props['__strict__'] = True
        cls = type(str(nm.split('/')[-1]), tuple(parents), props)

        return cls