def descend(fragment, path, visited_refs): if is_ref(fragment): ref_dict = fragment ref = fragment['$ref'] attach_scope(ref_dict, resolver) # Don't recurse down already visited refs. A ref is not unique # by its name alone. Its scope (attached above) is part of the # equivalence comparison. if ref_dict in visited_refs: log.debug('Already visited %s' % ref) return visited_refs.append(ref_dict) with resolver.resolving(ref) as target: descend(target, path, visited_refs) return # fragment is guaranteed not to be a ref from this point onwards if is_dict_like(fragment): for key, value in iteritems(fragment): fire_callbacks(fragment, key, path + [key]) descend(fragment[key], path + [key], visited_refs) elif is_list_like(fragment): for index in range(len(fragment)): fire_callbacks(fragment, index, path + [str(index)]) descend(fragment[index], path + [str(index)], visited_refs)
def descend(fragment, path, visited_refs): if is_ref(fragment): ref_dict = fragment ref = fragment['$ref'] attach_scope(ref_dict, resolver) # Don't recurse down already visited refs. A ref is not unique # by its name alone. Its scope (attached above) is part of the # equivalence comparison. if ref_dict in visited_refs: log.debug('Already visited %s' % ref) return visited_refs.append(ref_dict) with resolver.resolving(ref) as target: descend(target, path, visited_refs) return # fragment is guaranteed not to be a ref from this point onwards if is_dict_like(fragment): if 'type' not in fragment: if 'properties' in fragment: fragment['type'] = 'object' elif 'items' in fragment: fragment['type'] = 'array' for key, value in iteritems(fragment): fire_callbacks(fragment, key, path + [key]) descend(fragment[key], path + [key], visited_refs) elif is_list_like(fragment): for index in range(len(fragment)): fire_callbacks(fragment, index, path + [str(index)]) descend(fragment[index], path + [str(index)], visited_refs)
def test_create_model_type_properly_extracts_model_name(deref_value, expected_inherits): swagger_spec = mock.Mock( name='swagger-spec', deref=lambda schema: deref_value if is_ref(schema) else schema, ) model_type = create_model_type( swagger_spec=swagger_spec, model_name='Dog', model_spec={ 'type': 'object', 'title': 'Dog', 'allOf': [ { '$ref': '#/definitions/GenericPet' }, { 'properties': { 'birth_date': { 'type': 'string', 'format': 'date', }, }, 'required': ['birth_date'], }, ], } ) assert model_type._inherits_from == expected_inherits
def discriminator_validator(swagger_spec, validator, discriminator_attribute, instance, schema): """ Validates instance against the schema defined by the discriminator attribute. [Swagger 2.0 Schema Object](http://swagger.io/specification/#schemaObject) allows discriminator field to be defined. discriminator field defines the attribute that will be used to discriminate the object type. NOTE: discriminator_validator assumes that discriminator_attribute is not None or empty :param swagger_spec: needed for access to deref() :type swagger_spec: :class:`bravado_core.spec.Spec` :param validator: Validator class used to validate the object :type validator: :class: `Swagger20Validator` or :class: `jsonschema.validators.Draft4Validator` :param discriminator_attribute: name of the discriminator attribute :type discriminator_attribute: str :param instance: object instance value :type instance: dict :param schema: swagger spec for the object :type schema: dict """ discriminator_value = instance[discriminator_attribute] if discriminator_value not in swagger_spec.spec_dict['definitions']: raise ValidationError(message='\'{}\' is not a recognized schema'. format(discriminator_value)) if discriminator_value == schema['x-model']: return new_schema = deepcopy( swagger_spec.deref( swagger_spec.spec_dict['definitions'][discriminator_value])) if 'allOf' not in new_schema: raise ValidationError( message='discriminated schema \'{}\' must inherit from \'{}\''. format(discriminator_value, schema['x-model'])) schemas_to_remove = [ s for s in new_schema['allOf'] if is_ref(s) and swagger_spec.deref(s) == schema ] if not schemas_to_remove: # Not checking against len(schemas_to_remove) > 1 because it should be prevented by swagger spec validation raise ValidationError( message='discriminated schema \'{}\' must inherit from \'{}\''. format(discriminator_value, schema['x-model'])) # Remove the current schema from the allOf list in order to avoid unbounded recursion # (the current object is already validated against schema) new_schema['allOf'].remove(schemas_to_remove[0]) from bravado_core.validate import validate_object # Local import due to circular dependency validate_object(swagger_spec=swagger_spec, object_spec=new_schema, value=instance)
def test_ensure_model_spec_contains_reference_if_fully_dereference_is_not_enabled(polymorphic_dict): spec = Spec.from_dict( spec_dict=polymorphic_dict, config={'internally_dereference_refs': False}, origin_url='', ) # Ensure that Dog model has reference to GenericPet assert any( is_ref(all_of_item) and all_of_item['$ref'] == '#/definitions/GenericPet' for all_of_item in spec.definitions['Dog']._model_spec['allOf'] )
def test_ensure_model_spec_does_not_contain_references_if_fully_dereference_is_enabled( polymorphic_dict): spec = Spec.from_dict( spec_dict=polymorphic_dict, config={'internally_dereference_refs': True}, origin_url='', ) # Ensure that no reference are present assert all(not is_ref(all_of_item) for all_of_item in spec.definitions['Dog']._model_spec['allOf']) # Ensure that GenericPet is part of the allOf items of Dog assert any(all_of_item == spec.definitions['GenericPet']._model_spec for all_of_item in spec.definitions['Dog']._model_spec['allOf'])
def _force_deref(self, ref_dict): """Dereference ref_dict (if it is indeed a ref) and return what the ref points to. :param ref_dict: {'$ref': '#/blah/blah'} :return: dereferenced value of ref_dict :rtype: scalar, list, dict """ if ref_dict is None or not is_ref(ref_dict): return ref_dict # Restore attached resolution scope before resolving since the # resolver doesn't have a traversal history (accumulated scope_stack) # when asked to resolve. with in_scope(self.resolver, ref_dict): _, target = self.resolver.resolve(ref_dict['$ref']) return target
def descend(self, value): if is_ref(value): # Update spec_resolver scope to be able to dereference relative specs from a not root file with in_scope(self.spec_resolver, value): uri, deref_value = self.resolve(value['$ref']) object_type = determine_object_type( object_dict=deref_value, default_type_to_object=self.default_type_to_object, ) known_mapping_key = object_type.get_root_holder() if known_mapping_key is None: return self.descend(value=deref_value) else: uri = urlparse(uri) if uri not in self.known_mappings.get( known_mapping_key, {}): # The placeholder is present to interrupt the recursion # during the recursive traverse of the data model (``descend``) self.known_mappings[known_mapping_key][uri] = None self.known_mappings[known_mapping_key][ uri] = self.descend(value=deref_value) return { '$ref': '#/{}/{}'.format(known_mapping_key, self.marshal_uri(uri)) } elif is_dict_like(value): return { key: self.descend(value=subval) for key, subval in iteritems(value) } elif is_list_like(value): return [ self.descend(value=subval) for index, subval in enumerate(value) ] else: return value
def _rename_references_descend(value): if is_ref(value): return { '$ref': reference_renaming_mapping.get(value['$ref'], value['$ref']) } elif is_dict_like(value): return { key: _rename_references_descend(value=subval) for key, subval in iteritems(value) } elif is_list_like(value): return [ _rename_references_descend(value=subval) for index, subval in enumerate(value) ] else: return value
def wrapper(fragment, *args, **kwargs): is_reference = is_ref(fragment) if is_reference: ref = fragment['$ref'] attach_scope(fragment, resolver) with resolver.resolving(ref) as target: if id(target) in cache: log.debug('Already visited %s', ref) return func(target, *args, **kwargs) return # fragment is guaranteed not to be a ref from this point onwards fragment_id = id(fragment) if fragment_id in cache: log.debug('Already visited id %d', fragment_id) return cache.add(id(fragment)) func(fragment, *args, **kwargs)
def descend(value): if is_ref(value): uri, deref_value = resolve(value['$ref']) # Update spec_resolver scope to be able to dereference relative specs from a not root file with in_scope(spec_resolver, {'x-scope': [uri]}): object_type = _determine_object_type(object_dict=deref_value) if object_type is _TYPE_PATH_ITEM: return descend(value=deref_value) else: mapping_key = _TYPE_PROPERTY_HOLDER_MAPPING.get( object_type, 'definitions') uri = urlparse(uri) if uri not in known_mappings.get(mapping_key, {}): # The placeholder is present to interrupt the recursion # during the recursive traverse of the data model (``descend``) known_mappings[mapping_key][uri] = None known_mappings[mapping_key][uri] = descend( value=deref_value) return { '$ref': '#/{}/{}'.format(mapping_key, marshal_uri(uri)) } elif is_dict_like(value): return { key: descend(value=subval) for key, subval in iteritems(value) } elif is_list_like(value): return [ descend(value=subval) for index, subval in enumerate(value) ] else: return value
def wrapper(fragment, json_reference=None): if json_reference is None: json_reference = '{}#'.format(spec_resolver.resolution_scope) is_reference = is_ref(fragment) if is_reference: ref = fragment['$ref'] attach_scope(fragment, spec_resolver) with spec_resolver.resolving(ref) as target: if id(target) in cache: log.debug('Already visited %s', ref) return json_reference = spec_resolver.resolution_scope if '#' not in json_reference: # If $ref points to a file make sure that the fragment sign is present json_reference = '{}#'.format(json_reference) func( fragment=target, json_reference=json_reference, ) return # fragment is guaranteed not to be a ref from this point onwards fragment_id = id(fragment) if fragment_id in cache: log.debug('Already visited id %d', fragment_id) return cache.add(id(fragment)) func( fragment=fragment, json_reference=json_reference, )
def descend(value): if is_ref(value): uri, deref_value = resolve(value['$ref']) # Update spec_resolver scope to be able to dereference relative specs from a not root file with in_scope(spec_resolver, {'x-scope': [uri]}): object_type = _determine_object_type(object_dict=deref_value) if object_type is _TYPE_PATH_ITEM: return descend(value=deref_value) else: mapping_key = _TYPE_PROPERTY_HOLDER_MAPPING.get(object_type, 'definitions') uri = urlparse(uri) if uri not in known_mappings.get(mapping_key, {}): # The placeholder is present to interrupt the recursion # during the recursive traverse of the data model (``descend``) known_mappings[mapping_key][uri] = None known_mappings[mapping_key][uri] = descend(value=deref_value) return {'$ref': '#/{}/{}'.format(mapping_key, marshal_uri(uri))} elif is_dict_like(value): return { key: descend(value=subval) for key, subval in iteritems(value) } elif is_list_like(value): return [ descend(value=subval) for index, subval in enumerate(value) ] else: return value
def descend(fragment, path=None, visited_refs=None): """ :param fragment: node in spec_dict :param path: list of strings that form the current path to fragment :param visited_refs: list of visted ref_dict """ path = path or [] visited_refs = visited_refs or [] if is_ref(fragment): ref_dict = fragment ref = fragment['$ref'] attach_scope(ref_dict, resolver) # Don't recurse down already visited refs. A ref is not unique # by its name alone. Its scope (attached above) is part of the # equivalence comparison. if ref_dict in visited_refs: log.debug('Already visited %s' % ref) return visited_refs.append(ref_dict) with resolver.resolving(ref) as target: descend(target, path, visited_refs) return # fragment is guaranteed not to be a ref from this point onwards if is_dict_like(fragment): for key, value in iteritems(fragment): fire_callbacks(fragment, key, path + [key]) descend(fragment[key], path + [key], visited_refs) elif is_list_like(fragment): for index in range(len(fragment)): fire_callbacks(fragment, index, path + [str(index)]) descend(fragment[index], path + [str(index)], visited_refs)