def build_classes(self,strict=False):
        """

        Args:
            strict: use this to validate required fields while creating the class

        Returns:

        """
        builder = classbuilder.ClassBuilder(self.resolver)
        for nm, defn in iteritems(self.schema.get('definitions', {})):
            uri = util.resolve_ref_uri(
                self.resolver.resolution_scope,
                "#/definitions/" + nm)
            builder.construct(uri, defn)

        nm = self.schema['title'] if 'title' in self.schema else self.schema['id']
        nm = inflection.parameterize(six.text_type(nm), '_')

        kw = {"strict" : strict}
        builder.construct(nm, self.schema,**kw)
        self._resolved = builder.resolved

        return (
            util.Namespace.from_mapping(dict(
                (inflection.camelize(uri.split('/')[-1]),
                 klass) for uri,
                klass in six.iteritems(builder.resolved)))
        )
Beispiel #2
0
    def build_classes(self, strict=False):
        """

        Args:
            strict: use this to validate required fields while creating the class

        Returns:

        """
        builder = classbuilder.ClassBuilder(self.resolver)
        for nm, defn in iteritems(self.schema.get('definitions', {})):
            uri = util.resolve_ref_uri(self.resolver.resolution_scope,
                                       "#/definitions/" + nm)
            builder.construct(uri, defn)

        nm = self.schema['title'] if 'title' in self.schema else self.schema[
            'id']
        nm = inflection.parameterize(six.text_type(nm), '_')

        kw = {"strict": strict}
        builder.construct(nm, self.schema, **kw)
        self._resolved = builder.resolved

        return (util.Namespace.from_mapping(
            dict((inflection.camelize(uri.split('/')[-1]), klass)
                 for uri, klass in six.iteritems(builder.resolved))))
Beispiel #3
0
    def build_classes(self):
        builder = classbuilder.ClassBuilder(self.resolver)
        for nm, defn in iteritems(self.schema.get('definitions', {})):
            uri = util.resolve_ref_uri(self.resolver.resolution_scope,
                                       "#/definitions/" + nm)
            builder.construct(uri, defn)

        nm = self.schema['title'] if 'title' in self.schema else self.schema[
            'id']
        nm = inflection.parameterize(six.text_type(nm), '_')

        builder.construct(nm, self.schema)

        return (util.Namespace.from_mapping(
            dict((inflection.camelize(uri.split('/')[-1]), klass)
                 for uri, klass in six.iteritems(builder.resolved))))
Beispiel #4
0
    def resolve_classes(self, iterable):
        pp = []
        for elem in iterable:
            if '$ref' in elem:
                ref = elem['$ref']
                uri = util.resolve_ref_uri(self.resolver.resolution_scope, ref)
                if uri in self.resolved:
                    pp.append(self.resolved[uri])
                else:
                    with self.resolver.resolving(ref) as resolved:
                        self.resolved[uri] = self.construct(
                            uri, resolved, (ProtocolBase, ))
                        pp.append(self.resolved[uri])
            else:
                pp.append(elem)

        return pp
    def build_classes(self):
        builder = classbuilder.ClassBuilder(self.resolver)
        for nm, defn in iteritems(self.schema.get('definitions', {})):
            uri = util.resolve_ref_uri(
                self.resolver.resolution_scope,
                "#/definitions/" + nm)
            builder.construct(uri, defn)

        nm = self.schema['title'] if 'title' in self.schema else self.schema['id']
        nm = inflection.parameterize(six.text_type(nm), '_')

        builder.construct(nm, self.schema)

        return (
            util.Namespace.from_mapping(dict(
                (inflection.camelize(uri.split('/')[-1]),
                 klass) for uri,
                klass in six.iteritems(builder.resolved)))
        )
    def resolve_classes(self, iterable):
        pp = []
        for elem in iterable:
            if '$ref' in elem:
                ref = elem['$ref']
                uri = util.resolve_ref_uri(self.resolver.resolution_scope, ref)
                if uri in self.resolved:
                    pp.append(self.resolved[uri])
                else:
                    with self.resolver.resolving(ref) as resolved:
                        self.resolved[uri] = self.construct(
                            uri,
                            resolved,
                            (ProtocolBase,))
                        pp.append(self.resolved[uri])
            else:
                pp.append(elem)

        return pp
Beispiel #7
0
    def resolve_type(self, ref, source):
        """ Return a resolved type for a URI, potentially constructing one if necessary"""
        uri = util.resolve_ref_uri(self.resolver.resolution_scope, ref)
        if uri in self.resolved:
            return self.resolved[uri]

        elif uri in self.under_construction:
            logger.debug(
                util.lazy_format(
                    "Using a TypeRef to avoid a cyclic reference for {0} -> {1} ",
                    uri,
                    source,
                ))
            return TypeRef(uri, self.resolved)
        else:
            logger.debug(
                util.lazy_format(
                    "Resolving direct reference object {0} -> {1}", source,
                    uri))
            with self.resolver.resolving(ref) as resolved:
                self.resolved[uri] = self.construct(uri, resolved,
                                                    (ProtocolBase, ))
                return self.resolved[uri]
    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']
                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 in self.resolved:
                    typ = self.resolved[uri]
                else:
                    typ = self.construct(uri, detail, (ProtocolBase,))

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

            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'])
                        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)}

                    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'])

                            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)

        """ 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

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

        return cls
    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))
Beispiel #10
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
Beispiel #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.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
Beispiel #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:
            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)
                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))
Beispiel #13
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
Beispiel #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.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"]
                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 in self.resolved:
                    typ = self.resolved[uri]
                else:
                    typ = self.construct(uri, detail, (ProtocolBase,))

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

            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"])
                        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
                            ),
                        }

                    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"])

                            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)

        """ 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

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

        return cls
Beispiel #15
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:
            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)
            )
    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 _build_object(self, nm, clsdata, parents):
        logger.debug("Building object {0}".format(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'])
                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:
                            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
Beispiel #18
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