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))) )
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))))
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
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
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))
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
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 _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))
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
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) )
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
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