def validate(self): """Applies all defined validation to the current state of the object, and raises an error if they are not all met. Raises: ValidationError: if validations do not pass """ missing = self.missing_property_names() if len(missing) > 0: raise validators.ValidationError( "'{0}' are required attributes for {1}".format( missing, self.__class__.__name__)) for prop, val in six.iteritems(self._properties): if val is None: continue if isinstance(val, ProtocolBase): val.validate() elif getattr(val, "isLiteralClass", None) is True: val.validate() elif isinstance(val, list): for subval in val: subval.validate() else: # This object is of the wrong type, but just try setting it # The property setter will enforce its correctness # and handily coerce its type at the same time setattr(self, prop, val) return True
def __setattr__(self, name, val): if name.startswith("_"): object.__setattr__(self, name, val) elif name in self.__propinfo__: # If its in __propinfo__, then it actually has a property defined. # The property does special validation, so we actually need to # run its setter. We get it from the class definition and call # it directly. XXX Heinous. prop = self.__class__.__dict__[self.__prop_names__[name]] prop.fset(self, val) else: # This is an additional property of some kind typ = getattr(self, '__extensible__', None) if typ is False: raise validators.ValidationError( "Attempted to set unknown property '{0}', " "but 'additionalProperties' is false.".format(name)) if typ is True: # There is no type defined, so just make it a basic literal # Pick the type based on the type of the values valtype = [ k for k, t in six.iteritems(self.__SCHEMA_TYPES__) if t is not None and isinstance(val, t) ] valtype = valtype[0] val = MakeLiteral(name, valtype, val) elif isinstance( typ, type) and getattr(typ, 'isLiteralClass', None) is True: val = typ(val) elif isinstance(typ, type) and util.safe_issubclass( typ, ProtocolBase): val = typ(**util.coerce_for_expansion(val)) self._extended_properties[name] = val
def validate(self): propname = lambda x: self.__prop_names__[x] missing = [ x for x in self.__required__ if propname(x) not in self._properties or self._properties[propname(x)] is None ] if len(missing) > 0: raise validators.ValidationError( "'{0}' are required attributes for {1}".format( missing, self.__class__)) for prop, val in self._properties.iteritems(): if val is None: continue if isinstance(val, ProtocolBase): val.validate() elif getattr(val, 'isLiteralClass', None) is True: val.validate() elif isinstance(val, list): for subval in val: subval.validate() else: # This object is of the wrong type, but just try setting it # The property setter will enforce its correctness # and handily coerce its type at the same time setattr(self, prop, val) return True
def instantiate(self, name, val): import python_jsonschema_objects.classbuilder as cb for p in self._pattern_types: if p.pattern.search(name): logger.debug( "Found patternProperties match: %s %s" % (p.pattern.pattern, name) ) return self._make_type(p.schema_type, val) if self._additional_type is True: valtype = [ k for k, t in validators.SCHEMA_TYPE_MAPPING if t is not None and isinstance(val, t) ] valtype = valtype[0] return MakeLiteral(name, valtype, val) elif isinstance(self._additional_type, type): return self._make_type(self._additional_type, val) raise validators.ValidationError( "additionalProperties not permitted " "and no patternProperties specified" )
def __setattr__(self, name, val): if name.startswith("__donttouch_"): object.__setattr__(self, name, val) return inverter = dict((v, k) for k, v in six.iteritems(self.__prop_names__)) # If name is a sanitized version (e.g. base_var) of the actual property (e.g. "base var"), invert it back so that the following lookups work properly. # The bigger problem appears to be the fact that the __prop_names__ mapping is somewhat backwards... if name in inverter: name = inverter[name] if name in self.__object_attr_list__: object.__setattr__(self, name, val) elif name in self.__propinfo__: # If its in __propinfo__, then it actually has a property defined. # The property does special validation, so we actually need to # run its setter. We get it from the class definition and call # it directly. XXX Heinous. prop = getattr(self.__class__, self.__prop_names__[name]) prop.fset(self, val) else: # This is an additional property of some kind try: val = self.__extensible__.instantiate(name, val) except Exception as e: raise validators.ValidationError( "Attempted to set unknown property '{0}': {1} ".format( name, e)) self._extended_properties[name] = val
def setprop(this, val): if isinstance(info['type'], (list, tuple)): ok = False errors = [] for typ in info['type']: if isinstance(val, typ): ok = True break elif getattr(typ, 'isLiteralClass'): try: val = typ(val) except Exception as e: errors.append("Failed to coerce to '{0}': {1}".format( typ, e)) pass else: val.validate() ok = True break elif issubclass(typ, ProtocolBase): try: val = typ(**val) except Exception as e: errors.append("Failed to coerce to '{0}': {1}".format( typ, e)) pass else: val.validate() ok = True break if not ok: errstr = "\n".join(errors) raise validators.ValidationError( "Object must be one of {0}: \n{1}".format( info['type'], errstr)) elif info['type'] == 'array': instance = info['validator'](val) val = instance.validate() elif getattr(info['type'], 'isLiteralClass', False) is True: if not isinstance(val, info['type']): val = info['type'](val) elif issubclass(info['type'], ProtocolBase): if not isinstance(val, info['type']): val = info['type'](**val) val.validate() else: raise TypeError("Unknown object type: '{0}'".format(info['type'])) this._properties[prop] = val
def _make_type(self, typ, val): import python_jsonschema_objects.classbuilder as cb if getattr(typ, 'isLiteralClass', None) is True: return typ(val) if util.safe_issubclass(typ, cb.ProtocolBase): return typ(**util.coerce_for_expansion(val)) if util.safe_issubclass(typ, validators.ArrayValidator): return typ(val) raise validators.ValidationError( "additionalProperty type {0} was neither a literal " "nor a schema wrapper: {1}".format(typ, val))
def __setattr__(self, name, val): if name in self.__object_attr_list__: object.__setattr__(self, name, val) elif name in self.__propinfo__: # If its in __propinfo__, then it actually has a property defined. # The property does special validation, so we actually need to # run its setter. We get it from the class definition and call # it directly. XXX Heinous. prop = getattr(self.__class__, self.__prop_names__[name]) prop.fset(self, val) else: # This is an additional property of some kind try: val = self.__extensible__.instantiate(name, val) except Exception as e: raise validators.ValidationError( "Attempted to set unknown property '{0}': {1} ".format( name, e)) self._extended_properties[name] = val
def __call__(self, *a, **kw): validation_errors = [] valid_types = self._types for klass in valid_types: logger.debug( util.lazy_format("Attempting to instantiate {0} as {1}", self.__class__, klass)) try: obj = klass(*a, **kw) except TypeError as e: validation_errors.append((klass, e)) except validators.ValidationError as e: validation_errors.append((klass, e)) else: return obj else: # We got nothing raise validators.ValidationError( "Unable to instantiate any valid types: \n" "".join("{0}: {1}\n".format(k, e) for k, e in validation_errors))
def __new__(cls, **props): """ Overridden to support oneOf, where we need to instantiate a different class depending on what value we've seen """ if getattr(cls, "__validation__", None) is None: new = super(ProtocolBase, cls).__new__ if new is object.__new__: return new(cls) return new(cls, **props) valid_types = cls.__validation__.get("type", None) if valid_types is None or not isinstance(valid_types, list): new = super(ProtocolBase, cls).__new__ if new is object.__new__: return new(cls) return new(cls, **props) obj = None validation_errors = [] for klass in valid_types: logger.debug( util.lazy_format("Attempting to instantiate {0} as {1}", cls, klass) ) try: obj = klass(**props) obj.validate() except validators.ValidationError as e: validation_errors.append((klass, e)) else: break else: # We got nothing raise validators.ValidationError( "Unable to instantiate any valid types: \n" "".join("{0}: {1}\n".format(k, e) for k, e in validation_errors) ) return obj
def _build_object(self, nm, clsdata, parents, **kw): logger.debug(util.lazy_format("Building object {0}", nm)) # To support circular references, we tag objects that we're # currently building as "under construction" self.under_construction.add(nm) props = {} defaults = set() properties = {} for p in parents: properties = util.propmerge(properties, p.__propinfo__) if "properties" in clsdata: properties = util.propmerge(properties, clsdata["properties"]) name_translation = {} for prop, detail in properties.items(): logger.debug(util.lazy_format("Handling property {0}.{1}", nm, prop)) properties[prop]["raw_name"] = prop name_translation[prop] = prop.replace("@", "") prop = name_translation[prop] if detail.get("default", None) is not None: defaults.add(prop) if detail.get("type", None) == "object": uri = "{0}/{1}_{2}".format(nm, prop, "<anonymous>") self.resolved[uri] = self.construct(uri, detail, (ProtocolBase,)) props[prop] = make_property( prop, {"type": self.resolved[uri]}, self.resolved[uri].__doc__ ) properties[prop]["type"] = self.resolved[uri] elif "type" not in detail and "$ref" in detail: ref = detail["$ref"] typ = self.resolve_type(ref, ".".join([nm, prop])) props[prop] = make_property(prop, {"type": typ}, typ.__doc__) properties[prop]["$ref"] = ref properties[prop]["type"] = typ elif "oneOf" in detail: potential = self.expand_references(nm, detail["oneOf"]) logger.debug( util.lazy_format("Designating {0} as oneOf {1}", prop, potential) ) desc = detail["description"] if "description" in detail else "" props[prop] = make_property(prop, {"type": potential}, desc) elif "type" in detail and detail["type"] == "array": if "items" in detail and isinstance(detail["items"], dict): if "$ref" in detail["items"]: typ = self.resolve_type(detail["items"]["$ref"], nm) constraints = copy.copy(detail) constraints["strict"] = kw.get("strict") propdata = { "type": "array", "validator": python_jsonschema_objects.wrapper_types.ArrayWrapper.create( nm, item_constraint=typ, **constraints ), } else: uri = "{0}/{1}_{2}".format(nm, prop, "<anonymous_field>") try: if "oneOf" in detail["items"]: typ = TypeProxy( self.construct_objects( detail["items"]["oneOf"], uri ) ) else: typ = self.construct(uri, detail["items"]) constraints = copy.copy(detail) constraints["strict"] = kw.get("strict") propdata = { "type": "array", "validator": python_jsonschema_objects.wrapper_types.ArrayWrapper.create( uri, item_constraint=typ, **constraints ), } except NotImplementedError: typ = detail["items"] constraints = copy.copy(detail) constraints["strict"] = kw.get("strict") propdata = { "type": "array", "validator": python_jsonschema_objects.wrapper_types.ArrayWrapper.create( uri, item_constraint=typ, **constraints ), } props[prop] = make_property(prop, propdata, typ.__doc__) elif "items" in detail: typs = [] for i, elem in enumerate(detail["items"]): uri = "{0}/{1}/<anonymous_{2}>".format(nm, prop, i) typ = self.construct(uri, elem) typs.append(typ) props[prop] = make_property(prop, {"type": typs}) else: desc = detail["description"] if "description" in detail else "" uri = "{0}/{1}".format(nm, prop) typ = self.construct(uri, detail) props[prop] = make_property(prop, {"type": typ}, desc) props["__extensible__"] = pattern_properties.ExtensibleValidator( nm, clsdata, self ) props["__prop_names__"] = name_translation props["__propinfo__"] = properties required = set.union(*[p.__required__ for p in parents]) if "required" in clsdata: for prop in clsdata["required"]: required.add(prop) invalid_requires = [req for req in required if req not in props["__propinfo__"]] if len(invalid_requires) > 0: raise validators.ValidationError( "Schema Definition Error: {0} schema requires " "'{1}', but properties are not defined".format(nm, invalid_requires) ) props["__required__"] = required props["__has_default__"] = defaults if required and kw.get("strict"): props["__strict__"] = True props["__title__"] = clsdata.get("title") cls = type(str(nm.split("/")[-1]), tuple(parents), props) self.under_construction.remove(nm) return cls
def setprop(self, val): if isinstance(info['type'], (list, tuple)): ok = False errors = [] type_checks = [] for typ in info['type']: if not isinstance(typ, dict): type_checks.append(typ) continue typ = ProtocolBase.__SCHEMA_TYPES__[typ['type']] if typ is None: typ = type(None) if isinstance(typ, (list, tuple)): type_checks.extend(typ) else: type_checks.append(typ) for typ in type_checks: if isinstance(val, typ): ok = True break elif hasattr(typ, 'isLiteralClass'): try: validator = typ(val) except Exception as e: errors.append("Failed to coerce to '{0}': {1}".format( typ, e)) pass else: validator.validate() ok = True break elif util.safe_issubclass(typ, ProtocolBase): # force conversion- thus the val rather than validator assignment try: val = typ(**util.coerce_for_expansion(val)) except Exception as e: errors.append("Failed to coerce to '{0}': {1}".format( typ, e)) pass else: val.validate() ok = True break elif util.safe_issubclass(typ, validators.ArrayValidator): try: val = typ(val) except Exception as e: errors.append("Failed to coerce to '{0}': {1}".format( typ, e)) pass else: val.validate() ok = True break if not ok: errstr = "\n".join(errors) raise validators.ValidationError( "Object must be one of {0}: \n{1}".format( info['type'], errstr)) elif info['type'] == 'array': instance = info['validator'](val) val = instance.validate() elif getattr(info['type'], 'isLiteralClass', False) is True: if not isinstance(val, info['type']): validator = info['type'](val) validator.validate() elif util.safe_issubclass(info['type'], ProtocolBase): if not isinstance(val, info['type']): val = info['type'](**util.coerce_for_expansion(val)) val.validate() elif isinstance(info['type'], TypeProxy): val = info['type'](val) elif info['type'] is None: # This is the null value if val is not None: raise validators.ValidationError( "None is only valid value for null") else: raise TypeError("Unknown object type: '{0}'".format(info['type'])) self._properties[prop] = val
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 setprop(self, val): if isinstance(info['type'], (list, tuple)): ok = False errors = [] type_checks = [] for typ in info['type']: if not isinstance(typ, dict): type_checks.append(typ) continue typ = next(t for n, t in validators.SCHEMA_TYPE_MAPPING if typ['type'] == n) if typ is None: typ = type(None) if isinstance(typ, (list, tuple)): type_checks.extend(typ) else: type_checks.append(typ) for typ in type_checks: if isinstance(val, typ): ok = True break elif hasattr(typ, 'isLiteralClass'): try: validator = typ(val) except Exception as e: errors.append("Failed to coerce to '{0}': {1}".format( typ, e)) pass else: validator.validate() ok = True break elif util.safe_issubclass(typ, ProtocolBase): # force conversion- thus the val rather than validator assignment try: val = typ(**util.coerce_for_expansion(val)) except Exception as e: errors.append("Failed to coerce to '{0}': {1}".format( typ, e)) pass else: val.validate() ok = True break elif util.safe_issubclass( typ, python_jsonschema_objects.wrapper_types.ArrayWrapper): try: val = typ(val) except Exception as e: errors.append("Failed to coerce to '{0}': {1}".format( typ, e)) pass else: val.validate() ok = True break if not ok: errstr = "\n".join(errors) raise validators.ValidationError( "Object must be one of {0}: \n{1}".format( info['type'], errstr)) elif info['type'] == 'array': val = info['validator'](val) val.validate() elif util.safe_issubclass( info['type'], python_jsonschema_objects.wrapper_types.ArrayWrapper): # An array type may have already been converted into an ArrayValidator val = info['type'](val) val.validate() elif getattr(info['type'], 'isLiteralClass', False) is True: if not isinstance(val, info['type']): validator = info['type'](val) validator.validate() if validator._value is not None: # This allows setting of default Literal values val = validator elif util.safe_issubclass(info['type'], ProtocolBase): if not isinstance(val, info['type']): val = info['type'](**util.coerce_for_expansion(val)) val.validate() elif isinstance(info['type'], TypeProxy): val = info['type'](val) elif isinstance(info['type'], TypeRef): if not isinstance(val, info['type'].ref_class): val = info['type'](**val) val.validate() elif info['type'] is None: # This is the null value if val is not None: raise validators.ValidationError( "None is only valid value for null") else: raise TypeError("Unknown object type: '{0}'".format(info['type'])) self._properties[prop] = val
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