Example #1
0
def create_model_type(swagger_spec, model_name, model_spec, bases=(Model, )):
    """Create a dynamic class from the model data defined in the swagger
    spec.

    The docstring for this class is dynamically generated because generating
    the docstring is relatively expensive, and would only be used in rare
    cases for interactive debugging in a REPL.

    :type swagger_spec: :class:`bravado_core.spec.Spec`
    :param model_name: model name
    :param model_spec: json-like dict that describes a model.
    :param tuple bases: Base classes for type. At least one should be
        :class:`.Model` or a subclass of it.
    :returns: dynamic type inheriting from ``bases``.
    :rtype: type
    """

    inherits_from = []
    if 'allOf' in model_spec:
        for schema in model_spec['allOf']:
            inherited_name = swagger_spec.deref(schema).get(MODEL_MARKER, None)
            if inherited_name:
                inherits_from.append(inherited_name)

    return type(
        str(model_name), bases,
        dict(
            __doc__=ModelDocstring(),
            _swagger_spec=swagger_spec,
            _model_spec=model_spec,
            _properties=collapsed_properties(model_spec, swagger_spec),
            _inherits_from=inherits_from,
        ))
Example #2
0
def create_model_type(swagger_spec, model_name, model_spec, bases=(Model,)):
    """Create a dynamic class from the model data defined in the swagger
    spec.

    The docstring for this class is dynamically generated because generating
    the docstring is relatively expensive, and would only be used in rare
    cases for interactive debugging in a REPL.

    :type swagger_spec: :class:`bravado_core.spec.Spec`
    :param model_name: model name
    :param model_spec: json-like dict that describes a model.
    :param tuple bases: Base classes for type. At least one should be
        :class:`.Model` or a subclass of it.
    :returns: dynamic type inheriting from ``bases``.
    :rtype: type
    """

    inherits_from = []
    if 'allOf' in model_spec:
        for schema in model_spec['allOf']:
            inherited_name = swagger_spec.deref(schema).get(MODEL_MARKER, None)
            if inherited_name:
                inherits_from.append(inherited_name)

    return type(str(model_name), bases, dict(
        __doc__=ModelDocstring(),
        _swagger_spec=swagger_spec,
        _model_spec=model_spec,
        _properties=collapsed_properties(model_spec, swagger_spec),
        _inherits_from=inherits_from,
    ))
Example #3
0
def test_model_properties_iteration_allOf(cat_swagger_spec, cat_type,
                                          cat_kwargs):
    cat = cat_type(**cat_kwargs)
    assert set(cat) == set(
        collapsed_properties(
            cat_swagger_spec.spec_dict['definitions']['Cat'],
            cat_swagger_spec,
        ).keys(), )
Example #4
0
def test_recursive_ref(node_spec, recursive_swagger_spec):
    props = collapsed_properties(node_spec, recursive_swagger_spec)

    expected_props = {
        'name': {'type': 'string'},
        'child': {'$ref': '#/definitions/Node'}
    }
    assert props == expected_props
Example #5
0
def test_allOf(cat_swagger_spec, cat_type, cat_kwargs):
    cat = cat_type(**cat_kwargs)
    assert cat.id == 12
    assert cat.category == {'id': 42, 'name': 'Feline'}
    assert cat.name == 'Oskar'
    assert cat.photoUrls == ['example.com/img1', 'example.com/img2']
    assert cat.tags == [{'id': 1, 'name': 'cute'}]
    assert cat.neutered is True
    assert set(cat) == set(collapsed_properties(
        cat_swagger_spec.spec_dict['definitions']['Cat'], cat_swagger_spec
    ).keys())
Example #6
0
def model_dir(model, model_spec, swagger_spec):
    """Responsible for returning the names of the valid attributes on this
    model object.  This includes any properties defined in this model's spec,
    any properties that happen to be defined in parent polymorphic models,
    plus additional attibutes that exist as `additionalProperties`.

    :param model: instance of a model
    :param model_spec: spec the passed in model in dict form
    :type swagger_spec: :class:`bravado_core.spec.Spec`
    :returns: list of str
    """
    return (list(collapsed_properties(model_spec, swagger_spec).keys()) +
            model._additional_props)
Example #7
0
def unmarshal_object(swagger_spec, object_spec, object_value):
    """Unmarshal a jsonschema type of 'object' into a python dict.

    :type swagger_spec: :class:`bravado_core.spec.Spec`
    :type object_spec: dict
    :type object_value: dict
    :rtype: dict
    :raises: SwaggerMappingError
    """
    deref = swagger_spec.deref

    if object_value is None:
        return handle_null_value(swagger_spec, object_spec)

    if not is_dict_like(object_value):
        raise SwaggerMappingError('Expected dict like type for {0}:{1}'.format(
            type(object_value), object_value))

    object_spec = deref(object_spec)
    required_fields = object_spec.get('required', [])

    result = {}
    for k, v in iteritems(object_value):
        prop_spec = get_spec_for_prop(swagger_spec, object_spec, object_value,
                                      k)
        if v is None and k not in required_fields and prop_spec:
            if schema.has_default(swagger_spec, prop_spec):
                result[k] = schema.get_default(swagger_spec, prop_spec)
            else:
                result[k] = None
        elif prop_spec:
            # Zohar: Ugly hack to fix handling of unicode type, which were recognized as objects
            if type(v) == type(u''):
                result[k] = unmarshal_primitive(swagger_spec, prop_spec, v)
            # elif type(v) == type(list()):
            #     result[k] = unmarshal_array(swagger_spec, prop_spec, v)
            else:
                result[k] = unmarshal_schema_object(swagger_spec, prop_spec, v)
        else:
            # Don't marshal when a spec is not available - just pass through
            result[k] = v

    properties = collapsed_properties(deref(object_spec), swagger_spec)
    for prop_name, prop_spec in iteritems(properties):
        if prop_name not in result and swagger_spec.config[
                'include_missing_properties']:
            result[prop_name] = None
            if schema.has_default(swagger_spec, prop_spec):
                result[prop_name] = schema.get_default(swagger_spec, prop_spec)

    return result
Example #8
0
def create_model_repr(model, model_spec, swagger_spec):
    """Generates the repr string for the model.

    :param model: Instance of a model
    :param model_spec: model specification
    :type model_spec: dict
    :param swagger_spec: :class:`bravado_core.spec.Spec`
    :returns: repr string for the model
    """
    properties = collapsed_properties(model_spec, swagger_spec)
    s = [
        "{0}={1!r}".format(attr_name, getattr(model, attr_name))
        for attr_name in sorted(properties.keys())
    ]
    return "{0}({1})".format(model.__class__.__name__, ', '.join(s))
Example #9
0
def unmarshal_object(swagger_spec, object_spec, object_value):
    """Unmarshal a jsonschema type of 'object' into a python dict.

    :type swagger_spec: :class:`bravado_core.spec.Spec`
    :type object_spec: dict
    :type object_value: dict
    :rtype: dict
    :raises: SwaggerMappingError
    """
    deref = swagger_spec.deref

    if object_value is None:
        return handle_null_value(swagger_spec, object_spec)

    if not is_dict_like(object_value):
        raise SwaggerMappingError('Expected dict like type for {0}:{1}'.format(
            type(object_value), object_value))

    object_spec = deref(object_spec)
    required_fields = object_spec.get('required', [])
    properties = collapsed_properties(object_spec, swagger_spec)

    result = {}
    for k, v in iteritems(object_value):
        prop_spec = get_spec_for_prop(
            swagger_spec, object_spec, object_value, k, properties)
        if v is None and k not in required_fields and prop_spec:
            if schema.has_default(swagger_spec, prop_spec):
                result[k] = schema.get_default(swagger_spec, prop_spec)
            else:
                result[k] = None
        elif prop_spec:
            result[k] = unmarshal_schema_object(swagger_spec, prop_spec, v)
        else:
            # Don't marshal when a spec is not available - just pass through
            result[k] = v

    for prop_name, prop_spec in iteritems(properties):
        if prop_name not in result and swagger_spec.config['include_missing_properties']:
            result[prop_name] = None
            if schema.has_default(swagger_spec, prop_spec):
                result[prop_name] = schema.get_default(swagger_spec, prop_spec)

    return result
Example #10
0
def create_model_docstring(swagger_spec, model_spec):
    """
    :type swagger_spec: :class:`bravado_core.spec.Spec`
    :param model_spec: specification for a model in dict form
    :rtype: string or unicode
    """
    deref = swagger_spec.deref
    model_spec = deref(model_spec)

    s = 'Attributes:\n\n\t'
    properties = collapsed_properties(model_spec, swagger_spec)
    attr_iter = iter(sorted(iteritems(properties)))
    # TODO: Add more stuff available in the spec - 'required', 'example', etc
    for attr_name, attr_spec in attr_iter:
        attr_spec = deref(attr_spec)
        schema_type = deref(attr_spec['type'])

        attr_type = None
        if schema_type in SWAGGER_PRIMITIVES:
            # TODO: update to python types and take 'format' into account
            attr_type = schema_type

        elif schema_type == 'array':
            array_spec = deref(attr_spec['items'])
            if is_model(swagger_spec, array_spec):
                array_type = deref(array_spec[MODEL_MARKER])
            else:
                array_type = deref(array_spec['type'])
            attr_type = u'list of {0}'.format(array_type)

        elif is_model(swagger_spec, attr_spec):
            attr_type = deref(attr_spec[MODEL_MARKER])

        elif schema_type == 'object':
            attr_type = 'dict'

        s += u'{0}: {1}'.format(attr_name, attr_type)

        if deref(attr_spec.get('description')):
            s += u' - {0}'.format(deref(attr_spec['description']))

        s += '\n\t'
    return s
Example #11
0
def create_model_docstring(swagger_spec, model_spec):
    """
    :type swagger_spec: :class:`bravado_core.spec.Spec`
    :param model_spec: specification for a model in dict form
    :rtype: string or unicode
    """
    deref = swagger_spec.deref
    model_spec = deref(model_spec)

    s = 'Attributes:\n\n\t'
    properties = collapsed_properties(model_spec, swagger_spec)
    attr_iter = iter(sorted(iteritems(properties)))
    # TODO: Add more stuff available in the spec - 'required', 'example', etc
    for attr_name, attr_spec in attr_iter:
        attr_spec = deref(attr_spec)
        schema_type = deref(attr_spec['type'])

        if schema_type in SWAGGER_PRIMITIVES:
            # TODO: update to python types and take 'format' into account
            attr_type = schema_type

        elif schema_type == 'array':
            array_spec = deref(attr_spec['items'])
            if is_model(swagger_spec, array_spec):
                array_type = deref(array_spec[MODEL_MARKER])
            else:
                array_type = deref(array_spec['type'])
            attr_type = u'list of {0}'.format(array_type)

        elif is_model(swagger_spec, attr_spec):
            attr_type = deref(attr_spec[MODEL_MARKER])

        elif schema_type == 'object':
            attr_type = 'dict'

        s += u'{0}: {1}'.format(attr_name, attr_type)

        if deref(attr_spec.get('description')):
            s += u' - {0}'.format(deref(attr_spec['description']))

        s += '\n\t'
    return s
Example #12
0
def marshal_object(swagger_spec, object_spec, object_value):
    """Marshal a python dict to json dict.

    :type swagger_spec: :class:`bravado_core.spec.Spec`
    :type object_spec: dict
    :type object_value: dict

    :rtype: dict
    :raises: SwaggerMappingError
    """
    deref = swagger_spec.deref

    if object_value is None:
        return handle_null_value(swagger_spec, object_spec)

    if not is_dict_like(object_value):
        raise SwaggerMappingError('Expected dict like type for {0}:{1}'.format(
            type(object_value), object_value))

    object_spec = deref(object_spec)
    required_fields = object_spec.get('required', [])
    properties = collapsed_properties(object_spec, swagger_spec)

    result = {}
    for k, v in iteritems(object_value):

        prop_spec = get_spec_for_prop(
            swagger_spec, object_spec, object_value, k, properties)

        if not prop_spec:
            # Don't marshal when a spec is not available - just pass through
            result[k] = v
            continue

        if v is None and k not in required_fields:
            if not is_prop_nullable(swagger_spec, prop_spec):
                continue

        result[k] = marshal_schema_object(swagger_spec, prop_spec, v)

    return result
Example #13
0
def marshal_object(swagger_spec, object_spec, object_value):
    """Marshal a python dict to json dict.

    :type swagger_spec: :class:`bravado_core.spec.Spec`
    :type object_spec: dict
    :type object_value: dict

    :rtype: dict
    :raises: SwaggerMappingError
    """
    deref = swagger_spec.deref

    if object_value is None:
        return handle_null_value(swagger_spec, object_spec)

    if not is_dict_like(object_value):
        raise SwaggerMappingError('Expected dict like type for {0}:{1}'.format(
            type(object_value), object_value))

    object_spec = deref(object_spec)
    required_fields = object_spec.get('required', [])
    properties = collapsed_properties(object_spec, swagger_spec)

    result = {}
    for k, v in iteritems(object_value):

        prop_spec = get_spec_for_prop(
            swagger_spec, object_spec, object_value, k, properties)

        if not prop_spec:
            # Don't marshal when a spec is not available - just pass through
            result[k] = v
            continue

        if v is None and k not in required_fields:
            if not is_prop_nullable(swagger_spec, prop_spec):
                continue

        result[k] = marshal_schema_object(swagger_spec, prop_spec, v)

    return result
Example #14
0
def unmarshal_object(swagger_spec, object_spec, object_value):
    """Unmarshal a jsonschema type of 'object' into a python dict.

    :type swagger_spec: :class:`bravado_core.spec.Spec`
    :type object_spec: dict
    :type object_value: dict
    :rtype: dict
    :raises: SwaggerMappingError
    """
    deref = swagger_spec.deref

    if object_value is None:
        return handle_null_value(swagger_spec, object_spec)

    if not is_dict_like(object_value):
        raise SwaggerMappingError('Expected dict like type for {0}:{1}'.format(
            type(object_value), object_value))

    object_spec = deref(object_spec)
    required_fields = object_spec.get('required', [])

    result = {}
    for k, v in iteritems(object_value):
        prop_spec = get_spec_for_prop(
            swagger_spec, object_spec, object_value, k)
        if v is None and k not in required_fields:
            result[k] = None
        elif prop_spec:
            result[k] = unmarshal_schema_object(swagger_spec, prop_spec, v)
        else:
            # Don't marshal when a spec is not available - just pass through
            result[k] = v

    # re-introduce and None'ify any properties that weren't passed
    properties = collapsed_properties(deref(object_spec), swagger_spec)
    for prop_name, prop_spec in iteritems(properties):
        if prop_name not in result:
            result[prop_name] = None
    return result
Example #15
0
def test_allOf(users_spec, users_swagger_spec):
    """Test allOf functionality, including:
     - multiple levels of allOf
     - multiple references within one allOf
     - referencing the same model multiple times across the
       allOf-hierarchy
    """
    superuser_spec = users_spec['SuperUser']
    props = collapsed_properties(superuser_spec, users_swagger_spec)

    expected_props = {
        # User properties
        'id': {'type': 'integer', 'format': 'int64'},
        'username': {'type': 'string'},
        'email': {'type': 'string'},
        'password': {'type': 'string'},
        # VIP additional properties
        'vip_pass_no': {'type': 'string'},
        # Admin additional properties
        'permissions': {'items': {'type': 'string'}, 'type': 'array'}
    }
    assert props == expected_props
Example #16
0
def model_constructor(model, model_spec, swagger_spec, constructor_kwargs):
    """Constructor for the given model instance. Just assigns kwargs as attrs
    on the model based on the 'properties' in the model specification.

    :param model: Instance of a model type
    :type model: type
    :param model_spec: model specification
    :type model_spec: dict
    :type swagger_spec: :class:`bravado_core.spec.Spec`
    :param constructor_kwargs: kwargs sent in to the constructor invocation
    :type constructor_kwargs: dict
    :raises: AttributeError on constructor_kwargs that don't exist in the
        model specification's list of properties
    """
    arg_names = list(constructor_kwargs.keys())

    properties = collapsed_properties(model_spec, swagger_spec)

    for attr_name, attr_spec in iteritems(properties):
        if attr_name in arg_names:
            attr_value = constructor_kwargs[attr_name]
            arg_names.remove(attr_name)
        else:
            attr_value = None
        setattr(model, attr_name, attr_value)

    if arg_names and not model_spec.get('additionalProperties', True):
        raise AttributeError(
            "Model {0} does not have attributes for: {1}".format(
                type(model), arg_names))

    # we've got additionalProperties to set on the model
    for arg_name in arg_names:
        setattr(model, arg_name, constructor_kwargs[arg_name])

    # stash so that dir(model) works
    model._additional_props = arg_names
Example #17
0
def _marshaling_method_object(swagger_spec, object_schema):
    # type: (Spec, JSONDict) -> MarshalingMethod
    """
    Determine the marshaling method needed for a schema of a type object.

    The method will be responsible for the identification of:
     * required and nullable value for the all properties
     * marshaling methods of all the properties
     * marshaling method of the eventual additional properties
     * polymorphic nature of the object (`discriminator` attribute) and list of the associated models

    :param swagger_spec: Spec object
    :param object_schema: Schema of the object type
    """

    model_type = None  # type: typing.Optional[typing.Type[Model]]
    object_schema = swagger_spec.deref(object_schema)
    if MODEL_MARKER in object_schema:
        model_name = object_schema[MODEL_MARKER]
        model_type = swagger_spec.definitions.get(model_name)
        if model_type is None:
            return partial(
                _raise_unknown_model,
                model_name,
            )

    properties = collapsed_properties(object_schema, swagger_spec)
    required_properties = set(object_schema.get('required', []))
    properties_to_marshaling_function = {
        prop_name: _get_marshaling_method(
            swagger_spec=swagger_spec,
            object_schema=prop_schema,
            required=prop_name in required_properties,
        )
        for prop_name, prop_schema in iteritems(properties)
    }

    additional_properties_marshaling_function = _no_op_marshaling
    if object_schema.get('additionalProperties') is not False:
        additional_properties_schema = object_schema.get(
            'additionalProperties', {})
        if additional_properties_schema not in ({}, True):
            additional_properties_marshaling_function = _get_marshaling_method(
                swagger_spec=swagger_spec,
                object_schema=additional_properties_schema,
            )

    discriminator_property = object_schema.get('discriminator')
    possible_discriminated_type_name_to_model = {}
    if model_type and object_schema.get('discriminator'):
        possible_discriminated_type_name_to_model.update({
            k: v
            for k, v in iteritems(swagger_spec.definitions)
            if model_type and model_type.__name__ in v._inherits_from
        })

    nullable_properties = {
        prop_name
        for prop_name, prop_schema in iteritems(properties)
        if schema.is_prop_nullable(swagger_spec, prop_schema)
    }

    return partial(
        _marshal_object,
        swagger_spec,
        properties_to_marshaling_function,
        additional_properties_marshaling_function,
        discriminator_property,
        possible_discriminated_type_name_to_model,
        required_properties,
        nullable_properties,
    )
Example #18
0
 def _properties(self):
     return collapsed_properties(self._model_spec, self._swagger_spec)
Example #19
0
def test_model_properties_iteration_allOf(cat_swagger_spec, cat_type, cat_kwargs):
    cat = cat_type(**cat_kwargs)
    assert set(cat) == set(collapsed_properties(
        cat_swagger_spec.spec_dict['definitions']['Cat'], cat_swagger_spec
    ).keys())
Example #20
0
def _unmarshaling_method_object(swagger_spec, object_schema, use_models=True):
    # type: (Spec, JSONDict, bool) -> UnmarshalingMethod
    """
    Determine the unmarshaling method needed for a schema of a type object.

    The method will be responsible for the identification of:
     * required, nullable and default value for the all properties
     * unmarshaling methods of all the properties
     * unmarshaling method of the eventual additional properties
     * polymorphic nature of the object (`discriminator` attribute) and list of the associated models

    :param swagger_spec: Spec object
    :param object_schema: Schema of the object type
    # TODO: use_models parameter should be removed once unmarshal_model function is removed
    :param use_models: Flag that enables or disables the usage of Models
    """

    model_type = None  # type: typing.Optional[typing.Type[Model]]
    object_schema = swagger_spec.deref(object_schema)
    if MODEL_MARKER in object_schema:
        model_name = object_schema[MODEL_MARKER]
        model_type = swagger_spec.definitions.get(model_name)
        if use_models and model_type is None:
            return partial(
                _raise_unknown_model,
                model_name,
            )
        if not use_models:
            model_type = None

    properties = collapsed_properties(object_schema, swagger_spec)
    required_properties = object_schema.get('required', [])
    properties_to_unmarshaling_function = {
        prop_name: _get_unmarshaling_method(
            swagger_spec=swagger_spec,
            object_schema=prop_schema,
            is_nullable=prop_schema.get('x-nullable', False)
            or prop_name not in required_properties,
        )
        for prop_name, prop_schema in iteritems(properties)
    }

    additional_properties_unmarshaling_function = _no_op_unmarshaling
    if object_schema.get('additionalProperties') is not False:
        additional_properties_schema = object_schema.get(
            'additionalProperties', {})
        if additional_properties_schema not in ({}, True):
            additional_properties_unmarshaling_function = _get_unmarshaling_method(
                swagger_spec=swagger_spec,
                object_schema=additional_properties_schema,
                is_nullable=False,
            )

    properties_to_default_value = {
        prop_name: unmarshal_schema_object(
            swagger_spec=swagger_spec,
            schema_object_spec=prop_schema,
            value=schema.get_default(swagger_spec, prop_schema),
        )
        for prop_name, prop_schema in iteritems(properties)
        if schema.has_default(swagger_spec, prop_schema)
    }

    discriminator_property = object_schema.get('discriminator')
    possible_discriminated_type_name_to_model = {}
    if model_type and object_schema.get('discriminator'):
        possible_discriminated_type_name_to_model.update({
            k: v
            for k, v in iteritems(swagger_spec.definitions)
            if model_type and model_type.__name__ in v._inherits_from
        })

    return partial(
        _unmarshal_object,
        swagger_spec,
        model_type
        if model_type and swagger_spec.config['use_models'] else dict,
        properties_to_unmarshaling_function,
        additional_properties_unmarshaling_function,
        properties_to_default_value,
        discriminator_property,
        possible_discriminated_type_name_to_model,
    )
Example #21
0
 def _get_swagger_model_spec(self, obj):
     """Retieve raw json swagger spec for ``obj``"""
     all_definitions = self.swagger_spec.spec_dict['definitions']
     definition_name = obj.__class__.__name__
     defintion_raw = all_definitions[definition_name]
     return collapsed_properties(defintion_raw, self.swagger_spec)