pinecone.core.client.model_utils

Pinecone API

No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) # noqa: E501

The version of the OpenAPI document: version not set Contact: support@pinecone.io Generated by: https://openapi-generator.tech

   1"""
   2    Pinecone API
   3
   4    No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)  # noqa: E501
   5
   6    The version of the OpenAPI document: version not set
   7    Contact: support@pinecone.io
   8    Generated by: https://openapi-generator.tech
   9"""
  10
  11
  12from datetime import date, datetime  # noqa: F401
  13import inspect
  14import io
  15import os
  16import pprint
  17import re
  18import tempfile
  19
  20from dateutil.parser import parse
  21
  22from pinecone.core.client.exceptions import (
  23    ApiKeyError,
  24    ApiAttributeError,
  25    ApiTypeError,
  26    ApiValueError,
  27)
  28
  29none_type = type(None)
  30file_type = io.IOBase
  31
  32
  33def convert_js_args_to_python_args(fn):
  34    from functools import wraps
  35
  36    @wraps(fn)
  37    def wrapped_init(_self, *args, **kwargs):
  38        """
  39        An attribute named `self` received from the api will conflicts with the reserved `self`
  40        parameter of a class method. During generation, `self` attributes are mapped
  41        to `_self` in models. Here, we name `_self` instead of `self` to avoid conflicts.
  42        """
  43        spec_property_naming = kwargs.get("_spec_property_naming", False)
  44        if spec_property_naming:
  45            kwargs = change_keys_js_to_python(kwargs, _self if isinstance(_self, type) else _self.__class__)
  46        return fn(_self, *args, **kwargs)
  47
  48    return wrapped_init
  49
  50
  51class cached_property(object):
  52    # this caches the result of the function call for fn with no inputs
  53    # use this as a decorator on function methods that you want converted
  54    # into cached properties
  55    result_key = "_results"
  56
  57    def __init__(self, fn):
  58        self._fn = fn
  59
  60    def __get__(self, instance, cls=None):
  61        if self.result_key in vars(self):
  62            return vars(self)[self.result_key]
  63        else:
  64            result = self._fn()
  65            setattr(self, self.result_key, result)
  66            return result
  67
  68
  69PRIMITIVE_TYPES = (list, float, int, bool, datetime, date, str, file_type)
  70
  71
  72def allows_single_value_input(cls):
  73    """
  74    This function returns True if the input composed schema model or any
  75    descendant model allows a value only input
  76    This is true for cases where oneOf contains items like:
  77    oneOf:
  78      - float
  79      - NumberWithValidation
  80      - StringEnum
  81      - ArrayModel
  82      - null
  83    TODO: lru_cache this
  84    """
  85    if issubclass(cls, ModelSimple) or cls in PRIMITIVE_TYPES:
  86        return True
  87    elif issubclass(cls, ModelComposed):
  88        if not cls._composed_schemas["oneOf"]:
  89            return False
  90        return any(allows_single_value_input(c) for c in cls._composed_schemas["oneOf"])
  91    return False
  92
  93
  94def composed_model_input_classes(cls):
  95    """
  96    This function returns a list of the possible models that can be accepted as
  97    inputs.
  98    TODO: lru_cache this
  99    """
 100    if issubclass(cls, ModelSimple) or cls in PRIMITIVE_TYPES:
 101        return [cls]
 102    elif issubclass(cls, ModelNormal):
 103        if cls.discriminator is None:
 104            return [cls]
 105        else:
 106            return get_discriminated_classes(cls)
 107    elif issubclass(cls, ModelComposed):
 108        if not cls._composed_schemas["oneOf"]:
 109            return []
 110        if cls.discriminator is None:
 111            input_classes = []
 112            for c in cls._composed_schemas["oneOf"]:
 113                input_classes.extend(composed_model_input_classes(c))
 114            return input_classes
 115        else:
 116            return get_discriminated_classes(cls)
 117    return []
 118
 119
 120class OpenApiModel(object):
 121    """The base class for all OpenAPIModels"""
 122
 123    def set_attribute(self, name, value):
 124        # this is only used to set properties on self
 125
 126        path_to_item = []
 127        if self._path_to_item:
 128            path_to_item.extend(self._path_to_item)
 129        path_to_item.append(name)
 130
 131        if name in self.openapi_types:
 132            required_types_mixed = self.openapi_types[name]
 133        elif self.additional_properties_type is None:
 134            raise ApiAttributeError("{0} has no attribute '{1}'".format(type(self).__name__, name), path_to_item)
 135        elif self.additional_properties_type is not None:
 136            required_types_mixed = self.additional_properties_type
 137
 138        if get_simple_class(name) != str:
 139            error_msg = type_error_message(var_name=name, var_value=name, valid_classes=(str,), key_type=True)
 140            raise ApiTypeError(error_msg, path_to_item=path_to_item, valid_classes=(str,), key_type=True)
 141
 142        if self._check_type:
 143            value = validate_and_convert_types(
 144                value,
 145                required_types_mixed,
 146                path_to_item,
 147                self._spec_property_naming,
 148                self._check_type,
 149                configuration=self._configuration,
 150            )
 151        if (name,) in self.allowed_values:
 152            check_allowed_values(self.allowed_values, (name,), value)
 153        if (name,) in self.validations:
 154            check_validations(self.validations, (name,), value, self._configuration)
 155        self.__dict__["_data_store"][name] = value
 156
 157    def __repr__(self):
 158        """For `print` and `pprint`"""
 159        return self.to_str()
 160
 161    def __ne__(self, other):
 162        """Returns true if both objects are not equal"""
 163        return not self == other
 164
 165    def __setattr__(self, attr, value):
 166        """set the value of an attribute using dot notation: `instance.attr = val`"""
 167        self[attr] = value
 168
 169    def __getattr__(self, attr):
 170        """get the value of an attribute using dot notation: `instance.attr`"""
 171        return self.get(attr)
 172
 173    def __new__(cls, *args, **kwargs):
 174        # this function uses the discriminator to
 175        # pick a new schema/class to instantiate because a discriminator
 176        # propertyName value was passed in
 177
 178        if len(args) == 1:
 179            arg = args[0]
 180            if arg is None and is_type_nullable(cls):
 181                # The input data is the 'null' value and the type is nullable.
 182                return None
 183
 184            if issubclass(cls, ModelComposed) and allows_single_value_input(cls):
 185                model_kwargs = {}
 186                oneof_instance = get_oneof_instance(cls, model_kwargs, kwargs, model_arg=arg)
 187                return oneof_instance
 188
 189        visited_composed_classes = kwargs.get("_visited_composed_classes", ())
 190        if cls.discriminator is None or cls in visited_composed_classes:
 191            # Use case 1: this openapi schema (cls) does not have a discriminator
 192            # Use case 2: we have already visited this class before and are sure that we
 193            # want to instantiate it this time. We have visited this class deserializing
 194            # a payload with a discriminator. During that process we traveled through
 195            # this class but did not make an instance of it. Now we are making an
 196            # instance of a composed class which contains cls in it, so this time make an instance of cls.
 197            #
 198            # Here's an example of use case 2: If Animal has a discriminator
 199            # petType and we pass in "Dog", and the class Dog
 200            # allOf includes Animal, we move through Animal
 201            # once using the discriminator, and pick Dog.
 202            # Then in the composed schema dog Dog, we will make an instance of the
 203            # Animal class (because Dal has allOf: Animal) but this time we won't travel
 204            # through Animal's discriminator because we passed in
 205            # _visited_composed_classes = (Animal,)
 206
 207            return super(OpenApiModel, cls).__new__(cls)
 208
 209        # Get the name and value of the discriminator property.
 210        # The discriminator name is obtained from the discriminator meta-data
 211        # and the discriminator value is obtained from the input data.
 212        discr_propertyname_py = list(cls.discriminator.keys())[0]
 213        discr_propertyname_js = cls.attribute_map[discr_propertyname_py]
 214        if discr_propertyname_js in kwargs:
 215            discr_value = kwargs[discr_propertyname_js]
 216        elif discr_propertyname_py in kwargs:
 217            discr_value = kwargs[discr_propertyname_py]
 218        else:
 219            # The input data does not contain the discriminator property.
 220            path_to_item = kwargs.get("_path_to_item", ())
 221            raise ApiValueError(
 222                "Cannot deserialize input data due to missing discriminator. "
 223                "The discriminator property '%s' is missing at path: %s" % (discr_propertyname_js, path_to_item)
 224            )
 225
 226        # Implementation note: the last argument to get_discriminator_class
 227        # is a list of visited classes. get_discriminator_class may recursively
 228        # call itself and update the list of visited classes, and the initial
 229        # value must be an empty list. Hence not using 'visited_composed_classes'
 230        new_cls = get_discriminator_class(cls, discr_propertyname_py, discr_value, [])
 231        if new_cls is None:
 232            path_to_item = kwargs.get("_path_to_item", ())
 233            disc_prop_value = kwargs.get(discr_propertyname_js, kwargs.get(discr_propertyname_py))
 234            raise ApiValueError(
 235                "Cannot deserialize input data due to invalid discriminator "
 236                "value. The OpenAPI document has no mapping for discriminator "
 237                "property '%s'='%s' at path: %s" % (discr_propertyname_js, disc_prop_value, path_to_item)
 238            )
 239
 240        if new_cls in visited_composed_classes:
 241            # if we are making an instance of a composed schema Descendent
 242            # which allOf includes Ancestor, then Ancestor contains
 243            # a discriminator that includes Descendent.
 244            # So if we make an instance of Descendent, we have to make an
 245            # instance of Ancestor to hold the allOf properties.
 246            # This code detects that use case and makes the instance of Ancestor
 247            # For example:
 248            # When making an instance of Dog, _visited_composed_classes = (Dog,)
 249            # then we make an instance of Animal to include in dog._composed_instances
 250            # so when we are here, cls is Animal
 251            # cls.discriminator != None
 252            # cls not in _visited_composed_classes
 253            # new_cls = Dog
 254            # but we know we know that we already have Dog
 255            # because it is in visited_composed_classes
 256            # so make Animal here
 257            return super(OpenApiModel, cls).__new__(cls)
 258
 259        # Build a list containing all oneOf and anyOf descendants.
 260        oneof_anyof_classes = None
 261        if cls._composed_schemas is not None:
 262            oneof_anyof_classes = cls._composed_schemas.get("oneOf", ()) + cls._composed_schemas.get("anyOf", ())
 263        oneof_anyof_child = new_cls in oneof_anyof_classes
 264        kwargs["_visited_composed_classes"] = visited_composed_classes + (cls,)
 265
 266        if cls._composed_schemas.get("allOf") and oneof_anyof_child:
 267            # Validate that we can make self because when we make the
 268            # new_cls it will not include the allOf validations in self
 269            self_inst = super(OpenApiModel, cls).__new__(cls)
 270            self_inst.__init__(*args, **kwargs)
 271
 272        new_inst = new_cls.__new__(new_cls, *args, **kwargs)
 273        new_inst.__init__(*args, **kwargs)
 274        return new_inst
 275
 276    @classmethod
 277    @convert_js_args_to_python_args
 278    def _new_from_openapi_data(cls, *args, **kwargs):
 279        # this function uses the discriminator to
 280        # pick a new schema/class to instantiate because a discriminator
 281        # propertyName value was passed in
 282
 283        if len(args) == 1:
 284            arg = args[0]
 285            if arg is None and is_type_nullable(cls):
 286                # The input data is the 'null' value and the type is nullable.
 287                return None
 288
 289            if issubclass(cls, ModelComposed) and allows_single_value_input(cls):
 290                model_kwargs = {}
 291                oneof_instance = get_oneof_instance(cls, model_kwargs, kwargs, model_arg=arg)
 292                return oneof_instance
 293
 294        visited_composed_classes = kwargs.get("_visited_composed_classes", ())
 295        if cls.discriminator is None or cls in visited_composed_classes:
 296            # Use case 1: this openapi schema (cls) does not have a discriminator
 297            # Use case 2: we have already visited this class before and are sure that we
 298            # want to instantiate it this time. We have visited this class deserializing
 299            # a payload with a discriminator. During that process we traveled through
 300            # this class but did not make an instance of it. Now we are making an
 301            # instance of a composed class which contains cls in it, so this time make an instance of cls.
 302            #
 303            # Here's an example of use case 2: If Animal has a discriminator
 304            # petType and we pass in "Dog", and the class Dog
 305            # allOf includes Animal, we move through Animal
 306            # once using the discriminator, and pick Dog.
 307            # Then in the composed schema dog Dog, we will make an instance of the
 308            # Animal class (because Dal has allOf: Animal) but this time we won't travel
 309            # through Animal's discriminator because we passed in
 310            # _visited_composed_classes = (Animal,)
 311
 312            return cls._from_openapi_data(*args, **kwargs)
 313
 314        # Get the name and value of the discriminator property.
 315        # The discriminator name is obtained from the discriminator meta-data
 316        # and the discriminator value is obtained from the input data.
 317        discr_propertyname_py = list(cls.discriminator.keys())[0]
 318        discr_propertyname_js = cls.attribute_map[discr_propertyname_py]
 319        if discr_propertyname_js in kwargs:
 320            discr_value = kwargs[discr_propertyname_js]
 321        elif discr_propertyname_py in kwargs:
 322            discr_value = kwargs[discr_propertyname_py]
 323        else:
 324            # The input data does not contain the discriminator property.
 325            path_to_item = kwargs.get("_path_to_item", ())
 326            raise ApiValueError(
 327                "Cannot deserialize input data due to missing discriminator. "
 328                "The discriminator property '%s' is missing at path: %s" % (discr_propertyname_js, path_to_item)
 329            )
 330
 331        # Implementation note: the last argument to get_discriminator_class
 332        # is a list of visited classes. get_discriminator_class may recursively
 333        # call itself and update the list of visited classes, and the initial
 334        # value must be an empty list. Hence not using 'visited_composed_classes'
 335        new_cls = get_discriminator_class(cls, discr_propertyname_py, discr_value, [])
 336        if new_cls is None:
 337            path_to_item = kwargs.get("_path_to_item", ())
 338            disc_prop_value = kwargs.get(discr_propertyname_js, kwargs.get(discr_propertyname_py))
 339            raise ApiValueError(
 340                "Cannot deserialize input data due to invalid discriminator "
 341                "value. The OpenAPI document has no mapping for discriminator "
 342                "property '%s'='%s' at path: %s" % (discr_propertyname_js, disc_prop_value, path_to_item)
 343            )
 344
 345        if new_cls in visited_composed_classes:
 346            # if we are making an instance of a composed schema Descendent
 347            # which allOf includes Ancestor, then Ancestor contains
 348            # a discriminator that includes Descendent.
 349            # So if we make an instance of Descendent, we have to make an
 350            # instance of Ancestor to hold the allOf properties.
 351            # This code detects that use case and makes the instance of Ancestor
 352            # For example:
 353            # When making an instance of Dog, _visited_composed_classes = (Dog,)
 354            # then we make an instance of Animal to include in dog._composed_instances
 355            # so when we are here, cls is Animal
 356            # cls.discriminator != None
 357            # cls not in _visited_composed_classes
 358            # new_cls = Dog
 359            # but we know we know that we already have Dog
 360            # because it is in visited_composed_classes
 361            # so make Animal here
 362            return cls._from_openapi_data(*args, **kwargs)
 363
 364        # Build a list containing all oneOf and anyOf descendants.
 365        oneof_anyof_classes = None
 366        if cls._composed_schemas is not None:
 367            oneof_anyof_classes = cls._composed_schemas.get("oneOf", ()) + cls._composed_schemas.get("anyOf", ())
 368        oneof_anyof_child = new_cls in oneof_anyof_classes
 369        kwargs["_visited_composed_classes"] = visited_composed_classes + (cls,)
 370
 371        if cls._composed_schemas.get("allOf") and oneof_anyof_child:
 372            # Validate that we can make self because when we make the
 373            # new_cls it will not include the allOf validations in self
 374            self_inst = cls._from_openapi_data(*args, **kwargs)
 375
 376        new_inst = new_cls._new_from_openapi_data(*args, **kwargs)
 377        return new_inst
 378
 379
 380class ModelSimple(OpenApiModel):
 381    """the parent class of models whose type != object in their
 382    swagger/openapi"""
 383
 384    def __setitem__(self, name, value):
 385        """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
 386        if name in self.required_properties:
 387            self.__dict__[name] = value
 388            return
 389
 390        self.set_attribute(name, value)
 391
 392    def get(self, name, default=None):
 393        """returns the value of an attribute or some default value if the attribute was not set"""
 394        if name in self.required_properties:
 395            return self.__dict__[name]
 396
 397        return self.__dict__["_data_store"].get(name, default)
 398
 399    def __getitem__(self, name):
 400        """get the value of an attribute using square-bracket notation: `instance[attr]`"""
 401        if name in self:
 402            return self.get(name)
 403
 404        raise ApiAttributeError(
 405            "{0} has no attribute '{1}'".format(type(self).__name__, name), [e for e in [self._path_to_item, name] if e]
 406        )
 407
 408    def __contains__(self, name):
 409        """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
 410        if name in self.required_properties:
 411            return name in self.__dict__
 412
 413        return name in self.__dict__["_data_store"]
 414
 415    def to_str(self):
 416        """Returns the string representation of the model"""
 417        return str(self.value)
 418
 419    def __eq__(self, other):
 420        """Returns true if both objects are equal"""
 421        if not isinstance(other, self.__class__):
 422            return False
 423
 424        this_val = self._data_store["value"]
 425        that_val = other._data_store["value"]
 426        types = set()
 427        types.add(this_val.__class__)
 428        types.add(that_val.__class__)
 429        vals_equal = this_val == that_val
 430        return vals_equal
 431
 432
 433class ModelNormal(OpenApiModel):
 434    """the parent class of models whose type == object in their
 435    swagger/openapi"""
 436
 437    def __setitem__(self, name, value):
 438        """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
 439        if name in self.required_properties:
 440            self.__dict__[name] = value
 441            return
 442
 443        self.set_attribute(name, value)
 444
 445    def get(self, name, default=None):
 446        """returns the value of an attribute or some default value if the attribute was not set"""
 447        if name in self.required_properties:
 448            return self.__dict__[name]
 449
 450        return self.__dict__["_data_store"].get(name, default)
 451
 452    def __getitem__(self, name):
 453        """get the value of an attribute using square-bracket notation: `instance[attr]`"""
 454        if name in self:
 455            return self.get(name)
 456
 457        raise ApiAttributeError(
 458            "{0} has no attribute '{1}'".format(type(self).__name__, name), [e for e in [self._path_to_item, name] if e]
 459        )
 460
 461    def __contains__(self, name):
 462        """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
 463        if name in self.required_properties:
 464            return name in self.__dict__
 465
 466        return name in self.__dict__["_data_store"]
 467
 468    def to_dict(self):
 469        """Returns the model properties as a dict"""
 470        return model_to_dict(self, serialize=False)
 471
 472    def to_str(self):
 473        """Returns the string representation of the model"""
 474        return pprint.pformat(self.to_dict())
 475
 476    def __eq__(self, other):
 477        """Returns true if both objects are equal"""
 478        if not isinstance(other, self.__class__):
 479            return False
 480
 481        if not set(self._data_store.keys()) == set(other._data_store.keys()):
 482            return False
 483        for _var_name, this_val in self._data_store.items():
 484            that_val = other._data_store[_var_name]
 485            types = set()
 486            types.add(this_val.__class__)
 487            types.add(that_val.__class__)
 488            vals_equal = this_val == that_val
 489            if not vals_equal:
 490                return False
 491        return True
 492
 493
 494class ModelComposed(OpenApiModel):
 495    """the parent class of models whose type == object in their
 496    swagger/openapi and have oneOf/allOf/anyOf
 497
 498    When one sets a property we use var_name_to_model_instances to store the value in
 499    the correct class instances + run any type checking + validation code.
 500    When one gets a property we use var_name_to_model_instances to get the value
 501    from the correct class instances.
 502    This allows multiple composed schemas to contain the same property with additive
 503    constraints on the value.
 504
 505    _composed_schemas (dict) stores the anyOf/allOf/oneOf classes
 506    key (str): allOf/oneOf/anyOf
 507    value (list): the classes in the XOf definition.
 508        Note: none_type can be included when the openapi document version >= 3.1.0
 509    _composed_instances (list): stores a list of instances of the composed schemas
 510    defined in _composed_schemas. When properties are accessed in the self instance,
 511    they are returned from the self._data_store or the data stores in the instances
 512    in self._composed_schemas
 513    _var_name_to_model_instances (dict): maps between a variable name on self and
 514    the composed instances (self included) which contain that data
 515    key (str): property name
 516    value (list): list of class instances, self or instances in _composed_instances
 517    which contain the value that the key is referring to.
 518    """
 519
 520    def __setitem__(self, name, value):
 521        """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
 522        if name in self.required_properties:
 523            self.__dict__[name] = value
 524            return
 525
 526        """
 527        Use cases:
 528        1. additional_properties_type is None (additionalProperties == False in spec)
 529            Check for property presence in self.openapi_types
 530            if not present then throw an error
 531            if present set in self, set attribute
 532            always set on composed schemas
 533        2.  additional_properties_type exists
 534            set attribute on self
 535            always set on composed schemas
 536        """
 537        if self.additional_properties_type is None:
 538            """
 539            For an attribute to exist on a composed schema it must:
 540            - fulfill schema_requirements in the self composed schema not considering oneOf/anyOf/allOf schemas AND
 541            - fulfill schema_requirements in each oneOf/anyOf/allOf schemas
 542
 543            schema_requirements:
 544            For an attribute to exist on a schema it must:
 545            - be present in properties at the schema OR
 546            - have additionalProperties unset (defaults additionalProperties = any type) OR
 547            - have additionalProperties set
 548            """
 549            if name not in self.openapi_types:
 550                raise ApiAttributeError(
 551                    "{0} has no attribute '{1}'".format(type(self).__name__, name),
 552                    [e for e in [self._path_to_item, name] if e],
 553                )
 554        # attribute must be set on self and composed instances
 555        self.set_attribute(name, value)
 556        for model_instance in self._composed_instances:
 557            setattr(model_instance, name, value)
 558        if name not in self._var_name_to_model_instances:
 559            # we assigned an additional property
 560            self.__dict__["_var_name_to_model_instances"][name] = self._composed_instances + [self]
 561        return None
 562
 563    __unset_attribute_value__ = object()
 564
 565    def get(self, name, default=None):
 566        """returns the value of an attribute or some default value if the attribute was not set"""
 567        if name in self.required_properties:
 568            return self.__dict__[name]
 569
 570        # get the attribute from the correct instance
 571        model_instances = self._var_name_to_model_instances.get(name)
 572        values = []
 573        # A composed model stores self and child (oneof/anyOf/allOf) models under
 574        # self._var_name_to_model_instances.
 575        # Any property must exist in self and all model instances
 576        # The value stored in all model instances must be the same
 577        if model_instances:
 578            for model_instance in model_instances:
 579                if name in model_instance._data_store:
 580                    v = model_instance._data_store[name]
 581                    if v not in values:
 582                        values.append(v)
 583        len_values = len(values)
 584        if len_values == 0:
 585            return default
 586        elif len_values == 1:
 587            return values[0]
 588        elif len_values > 1:
 589            raise ApiValueError(
 590                "Values stored for property {0} in {1} differ when looking "
 591                "at self and self's composed instances. All values must be "
 592                "the same".format(name, type(self).__name__),
 593                [e for e in [self._path_to_item, name] if e],
 594            )
 595
 596    def __getitem__(self, name):
 597        """get the value of an attribute using square-bracket notation: `instance[attr]`"""
 598        value = self.get(name, self.__unset_attribute_value__)
 599        if value is self.__unset_attribute_value__:
 600            raise ApiAttributeError(
 601                "{0} has no attribute '{1}'".format(type(self).__name__, name),
 602                [e for e in [self._path_to_item, name] if e],
 603            )
 604        return value
 605
 606    def __contains__(self, name):
 607        """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
 608
 609        if name in self.required_properties:
 610            return name in self.__dict__
 611
 612        model_instances = self._var_name_to_model_instances.get(name, self._additional_properties_model_instances)
 613
 614        if model_instances:
 615            for model_instance in model_instances:
 616                if name in model_instance._data_store:
 617                    return True
 618
 619        return False
 620
 621    def to_dict(self):
 622        """Returns the model properties as a dict"""
 623        return model_to_dict(self, serialize=False)
 624
 625    def to_str(self):
 626        """Returns the string representation of the model"""
 627        return pprint.pformat(self.to_dict())
 628
 629    def __eq__(self, other):
 630        """Returns true if both objects are equal"""
 631        if not isinstance(other, self.__class__):
 632            return False
 633
 634        if not set(self._data_store.keys()) == set(other._data_store.keys()):
 635            return False
 636        for _var_name, this_val in self._data_store.items():
 637            that_val = other._data_store[_var_name]
 638            types = set()
 639            types.add(this_val.__class__)
 640            types.add(that_val.__class__)
 641            vals_equal = this_val == that_val
 642            if not vals_equal:
 643                return False
 644        return True
 645
 646
 647COERCION_INDEX_BY_TYPE = {
 648    ModelComposed: 0,
 649    ModelNormal: 1,
 650    ModelSimple: 2,
 651    none_type: 3,  # The type of 'None'.
 652    list: 4,
 653    dict: 5,
 654    float: 6,
 655    int: 7,
 656    bool: 8,
 657    datetime: 9,
 658    date: 10,
 659    str: 11,
 660    file_type: 12,  # 'file_type' is an alias for the built-in 'file' or 'io.IOBase' type.
 661}
 662
 663# these are used to limit what type conversions we try to do
 664# when we have a valid type already and we want to try converting
 665# to another type
 666UPCONVERSION_TYPE_PAIRS = (
 667    (str, datetime),
 668    (str, date),
 669    (int, float),  # A float may be serialized as an integer, e.g. '3' is a valid serialized float.
 670    (list, ModelComposed),
 671    (dict, ModelComposed),
 672    (str, ModelComposed),
 673    (int, ModelComposed),
 674    (float, ModelComposed),
 675    (list, ModelComposed),
 676    (list, ModelNormal),
 677    (dict, ModelNormal),
 678    (str, ModelSimple),
 679    (int, ModelSimple),
 680    (float, ModelSimple),
 681    (list, ModelSimple),
 682)
 683
 684COERCIBLE_TYPE_PAIRS = {
 685    False: (  # client instantiation of a model with client data
 686        # (dict, ModelComposed),
 687        # (list, ModelComposed),
 688        # (dict, ModelNormal),
 689        # (list, ModelNormal),
 690        # (str, ModelSimple),
 691        # (int, ModelSimple),
 692        # (float, ModelSimple),
 693        # (list, ModelSimple),
 694        # (str, int),
 695        # (str, float),
 696        # (str, datetime),
 697        # (str, date),
 698        # (int, str),
 699        # (float, str),
 700    ),
 701    True: (  # server -> client data
 702        (dict, ModelComposed),
 703        (list, ModelComposed),
 704        (dict, ModelNormal),
 705        (list, ModelNormal),
 706        (str, ModelSimple),
 707        (int, ModelSimple),
 708        (float, ModelSimple),
 709        (list, ModelSimple),
 710        # (str, int),
 711        # (str, float),
 712        (str, datetime),
 713        (str, date),
 714        # (int, str),
 715        # (float, str),
 716        (str, file_type),
 717    ),
 718}
 719
 720
 721def get_simple_class(input_value):
 722    """Returns an input_value's simple class that we will use for type checking
 723    Python2:
 724    float and int will return int, where int is the python3 int backport
 725    str and unicode will return str, where str is the python3 str backport
 726    Note: float and int ARE both instances of int backport
 727    Note: str_py2 and unicode_py2 are NOT both instances of str backport
 728
 729    Args:
 730        input_value (class/class_instance): the item for which we will return
 731                                            the simple class
 732    """
 733    if isinstance(input_value, type):
 734        # input_value is a class
 735        return input_value
 736    elif isinstance(input_value, tuple):
 737        return tuple
 738    elif isinstance(input_value, list):
 739        return list
 740    elif isinstance(input_value, dict):
 741        return dict
 742    elif isinstance(input_value, none_type):
 743        return none_type
 744    elif isinstance(input_value, file_type):
 745        return file_type
 746    elif isinstance(input_value, bool):
 747        # this must be higher than the int check because
 748        # isinstance(True, int) == True
 749        return bool
 750    elif isinstance(input_value, int):
 751        return int
 752    elif isinstance(input_value, datetime):
 753        # this must be higher than the date check because
 754        # isinstance(datetime_instance, date) == True
 755        return datetime
 756    elif isinstance(input_value, date):
 757        return date
 758    elif isinstance(input_value, str):
 759        return str
 760    return type(input_value)
 761
 762
 763def check_allowed_values(allowed_values, input_variable_path, input_values):
 764    """Raises an exception if the input_values are not allowed
 765
 766    Args:
 767        allowed_values (dict): the allowed_values dict
 768        input_variable_path (tuple): the path to the input variable
 769        input_values (list/str/int/float/date/datetime): the values that we
 770            are checking to see if they are in allowed_values
 771    """
 772    these_allowed_values = list(allowed_values[input_variable_path].values())
 773    if isinstance(input_values, list) and not set(input_values).issubset(set(these_allowed_values)):
 774        invalid_values = (", ".join(map(str, set(input_values) - set(these_allowed_values))),)
 775        raise ApiValueError(
 776            "Invalid values for `%s` [%s], must be a subset of [%s]"
 777            % (input_variable_path[0], invalid_values, ", ".join(map(str, these_allowed_values)))
 778        )
 779    elif isinstance(input_values, dict) and not set(input_values.keys()).issubset(set(these_allowed_values)):
 780        invalid_values = ", ".join(map(str, set(input_values.keys()) - set(these_allowed_values)))
 781        raise ApiValueError(
 782            "Invalid keys in `%s` [%s], must be a subset of [%s]"
 783            % (input_variable_path[0], invalid_values, ", ".join(map(str, these_allowed_values)))
 784        )
 785    elif not isinstance(input_values, (list, dict)) and input_values not in these_allowed_values:
 786        raise ApiValueError(
 787            "Invalid value for `%s` (%s), must be one of %s"
 788            % (input_variable_path[0], input_values, these_allowed_values)
 789        )
 790
 791
 792def is_json_validation_enabled(schema_keyword, configuration=None):
 793    """Returns true if JSON schema validation is enabled for the specified
 794    validation keyword. This can be used to skip JSON schema structural validation
 795    as requested in the configuration.
 796
 797    Args:
 798        schema_keyword (string): the name of a JSON schema validation keyword.
 799        configuration (Configuration): the configuration class.
 800    """
 801
 802    return (
 803        configuration is None
 804        or not hasattr(configuration, "_disabled_client_side_validations")
 805        or schema_keyword not in configuration._disabled_client_side_validations
 806    )
 807
 808
 809def check_validations(validations, input_variable_path, input_values, configuration=None):
 810    """Raises an exception if the input_values are invalid
 811
 812    Args:
 813        validations (dict): the validation dictionary.
 814        input_variable_path (tuple): the path to the input variable.
 815        input_values (list/str/int/float/date/datetime): the values that we
 816            are checking.
 817        configuration (Configuration): the configuration class.
 818    """
 819
 820    if input_values is None:
 821        return
 822
 823    current_validations = validations[input_variable_path]
 824    if (
 825        is_json_validation_enabled("multipleOf", configuration)
 826        and "multiple_of" in current_validations
 827        and isinstance(input_values, (int, float))
 828        and not (float(input_values) / current_validations["multiple_of"]).is_integer()
 829    ):
 830        # Note 'multipleOf' will be as good as the floating point arithmetic.
 831        raise ApiValueError(
 832            "Invalid value for `%s`, value must be a multiple of "
 833            "`%s`" % (input_variable_path[0], current_validations["multiple_of"])
 834        )
 835
 836    if (
 837        is_json_validation_enabled("maxLength", configuration)
 838        and "max_length" in current_validations
 839        and len(input_values) > current_validations["max_length"]
 840    ):
 841        raise ApiValueError(
 842            "Invalid value for `%s`, length must be less than or equal to "
 843            "`%s`" % (input_variable_path[0], current_validations["max_length"])
 844        )
 845
 846    if (
 847        is_json_validation_enabled("minLength", configuration)
 848        and "min_length" in current_validations
 849        and len(input_values) < current_validations["min_length"]
 850    ):
 851        raise ApiValueError(
 852            "Invalid value for `%s`, length must be greater than or equal to "
 853            "`%s`" % (input_variable_path[0], current_validations["min_length"])
 854        )
 855
 856    if (
 857        is_json_validation_enabled("maxItems", configuration)
 858        and "max_items" in current_validations
 859        and len(input_values) > current_validations["max_items"]
 860    ):
 861        raise ApiValueError(
 862            "Invalid value for `%s`, number of items must be less than or "
 863            "equal to `%s`" % (input_variable_path[0], current_validations["max_items"])
 864        )
 865
 866    if (
 867        is_json_validation_enabled("minItems", configuration)
 868        and "min_items" in current_validations
 869        and len(input_values) < current_validations["min_items"]
 870    ):
 871        raise ValueError(
 872            "Invalid value for `%s`, number of items must be greater than or "
 873            "equal to `%s`" % (input_variable_path[0], current_validations["min_items"])
 874        )
 875
 876    items = ("exclusive_maximum", "inclusive_maximum", "exclusive_minimum", "inclusive_minimum")
 877    if any(item in current_validations for item in items):
 878        if isinstance(input_values, list):
 879            max_val = max(input_values)
 880            min_val = min(input_values)
 881        elif isinstance(input_values, dict):
 882            max_val = max(input_values.values())
 883            min_val = min(input_values.values())
 884        else:
 885            max_val = input_values
 886            min_val = input_values
 887
 888    if (
 889        is_json_validation_enabled("exclusiveMaximum", configuration)
 890        and "exclusive_maximum" in current_validations
 891        and max_val >= current_validations["exclusive_maximum"]
 892    ):
 893        raise ApiValueError(
 894            "Invalid value for `%s`, must be a value less than `%s`"
 895            % (input_variable_path[0], current_validations["exclusive_maximum"])
 896        )
 897
 898    if (
 899        is_json_validation_enabled("maximum", configuration)
 900        and "inclusive_maximum" in current_validations
 901        and max_val > current_validations["inclusive_maximum"]
 902    ):
 903        raise ApiValueError(
 904            "Invalid value for `%s`, must be a value less than or equal to "
 905            "`%s`" % (input_variable_path[0], current_validations["inclusive_maximum"])
 906        )
 907
 908    if (
 909        is_json_validation_enabled("exclusiveMinimum", configuration)
 910        and "exclusive_minimum" in current_validations
 911        and min_val <= current_validations["exclusive_minimum"]
 912    ):
 913        raise ApiValueError(
 914            "Invalid value for `%s`, must be a value greater than `%s`"
 915            % (input_variable_path[0], current_validations["exclusive_maximum"])
 916        )
 917
 918    if (
 919        is_json_validation_enabled("minimum", configuration)
 920        and "inclusive_minimum" in current_validations
 921        and min_val < current_validations["inclusive_minimum"]
 922    ):
 923        raise ApiValueError(
 924            "Invalid value for `%s`, must be a value greater than or equal "
 925            "to `%s`" % (input_variable_path[0], current_validations["inclusive_minimum"])
 926        )
 927    flags = current_validations.get("regex", {}).get("flags", 0)
 928    if (
 929        is_json_validation_enabled("pattern", configuration)
 930        and "regex" in current_validations
 931        and not re.search(current_validations["regex"]["pattern"], input_values, flags=flags)
 932    ):
 933        err_msg = r"Invalid value for `%s`, must match regular expression `%s`" % (
 934            input_variable_path[0],
 935            current_validations["regex"]["pattern"],
 936        )
 937        if flags != 0:
 938            # Don't print the regex flags if the flags are not
 939            # specified in the OAS document.
 940            err_msg = r"%s with flags=`%s`" % (err_msg, flags)
 941        raise ApiValueError(err_msg)
 942
 943
 944def order_response_types(required_types):
 945    """Returns the required types sorted in coercion order
 946
 947    Args:
 948        required_types (list/tuple): collection of classes or instance of
 949            list or dict with class information inside it.
 950
 951    Returns:
 952        (list): coercion order sorted collection of classes or instance
 953            of list or dict with class information inside it.
 954    """
 955
 956    def index_getter(class_or_instance):
 957        if isinstance(class_or_instance, list):
 958            return COERCION_INDEX_BY_TYPE[list]
 959        elif isinstance(class_or_instance, dict):
 960            return COERCION_INDEX_BY_TYPE[dict]
 961        elif inspect.isclass(class_or_instance) and issubclass(class_or_instance, ModelComposed):
 962            return COERCION_INDEX_BY_TYPE[ModelComposed]
 963        elif inspect.isclass(class_or_instance) and issubclass(class_or_instance, ModelNormal):
 964            return COERCION_INDEX_BY_TYPE[ModelNormal]
 965        elif inspect.isclass(class_or_instance) and issubclass(class_or_instance, ModelSimple):
 966            return COERCION_INDEX_BY_TYPE[ModelSimple]
 967        elif class_or_instance in COERCION_INDEX_BY_TYPE:
 968            return COERCION_INDEX_BY_TYPE[class_or_instance]
 969        raise ApiValueError("Unsupported type: %s" % class_or_instance)
 970
 971    sorted_types = sorted(required_types, key=lambda class_or_instance: index_getter(class_or_instance))
 972    return sorted_types
 973
 974
 975def remove_uncoercible(required_types_classes, current_item, spec_property_naming, must_convert=True):
 976    """Only keeps the type conversions that are possible
 977
 978    Args:
 979        required_types_classes (tuple): tuple of classes that are required
 980                          these should be ordered by COERCION_INDEX_BY_TYPE
 981        spec_property_naming (bool): True if the variable names in the input
 982            data are serialized names as specified in the OpenAPI document.
 983            False if the variables names in the input data are python
 984            variable names in PEP-8 snake case.
 985        current_item (any): the current item (input data) to be converted
 986
 987    Keyword Args:
 988        must_convert (bool): if True the item to convert is of the wrong
 989                          type and we want a big list of coercibles
 990                          if False, we want a limited list of coercibles
 991
 992    Returns:
 993        (list): the remaining coercible required types, classes only
 994    """
 995    current_type_simple = get_simple_class(current_item)
 996
 997    results_classes = []
 998    for required_type_class in required_types_classes:
 999        # convert our models to OpenApiModel
1000        required_type_class_simplified = required_type_class
1001        if isinstance(required_type_class_simplified, type):
1002            if issubclass(required_type_class_simplified, ModelComposed):
1003                required_type_class_simplified = ModelComposed
1004            elif issubclass(required_type_class_simplified, ModelNormal):
1005                required_type_class_simplified = ModelNormal
1006            elif issubclass(required_type_class_simplified, ModelSimple):
1007                required_type_class_simplified = ModelSimple
1008
1009        if required_type_class_simplified == current_type_simple:
1010            # don't consider converting to one's own class
1011            continue
1012
1013        class_pair = (current_type_simple, required_type_class_simplified)
1014        if must_convert and class_pair in COERCIBLE_TYPE_PAIRS[spec_property_naming]:
1015            results_classes.append(required_type_class)
1016        elif class_pair in UPCONVERSION_TYPE_PAIRS:
1017            results_classes.append(required_type_class)
1018    return results_classes
1019
1020
1021def get_discriminated_classes(cls):
1022    """
1023    Returns all the classes that a discriminator converts to
1024    TODO: lru_cache this
1025    """
1026    possible_classes = []
1027    key = list(cls.discriminator.keys())[0]
1028    if is_type_nullable(cls):
1029        possible_classes.append(cls)
1030    for discr_cls in cls.discriminator[key].values():
1031        if hasattr(discr_cls, "discriminator") and discr_cls.discriminator is not None:
1032            possible_classes.extend(get_discriminated_classes(discr_cls))
1033        else:
1034            possible_classes.append(discr_cls)
1035    return possible_classes
1036
1037
1038def get_possible_classes(cls, from_server_context):
1039    # TODO: lru_cache this
1040    possible_classes = [cls]
1041    if from_server_context:
1042        return possible_classes
1043    if hasattr(cls, "discriminator") and cls.discriminator is not None:
1044        possible_classes = []
1045        possible_classes.extend(get_discriminated_classes(cls))
1046    elif issubclass(cls, ModelComposed):
1047        possible_classes.extend(composed_model_input_classes(cls))
1048    return possible_classes
1049
1050
1051def get_required_type_classes(required_types_mixed, spec_property_naming):
1052    """Converts the tuple required_types into a tuple and a dict described
1053    below
1054
1055    Args:
1056        required_types_mixed (tuple/list): will contain either classes or
1057            instance of list or dict
1058        spec_property_naming (bool): if True these values came from the
1059            server, and we use the data types in our endpoints.
1060            If False, we are client side and we need to include
1061            oneOf and discriminator classes inside the data types in our endpoints
1062
1063    Returns:
1064        (valid_classes, dict_valid_class_to_child_types_mixed):
1065            valid_classes (tuple): the valid classes that the current item
1066                                   should be
1067            dict_valid_class_to_child_types_mixed (dict):
1068                valid_class (class): this is the key
1069                child_types_mixed (list/dict/tuple): describes the valid child
1070                    types
1071    """
1072    valid_classes = []
1073    child_req_types_by_current_type = {}
1074    for required_type in required_types_mixed:
1075        if isinstance(required_type, list):
1076            valid_classes.append(list)
1077            child_req_types_by_current_type[list] = required_type
1078        elif isinstance(required_type, tuple):
1079            valid_classes.append(tuple)
1080            child_req_types_by_current_type[tuple] = required_type
1081        elif isinstance(required_type, dict):
1082            valid_classes.append(dict)
1083            child_req_types_by_current_type[dict] = required_type[str]
1084        else:
1085            valid_classes.extend(get_possible_classes(required_type, spec_property_naming))
1086    return tuple(valid_classes), child_req_types_by_current_type
1087
1088
1089def change_keys_js_to_python(input_dict, model_class):
1090    """
1091    Converts from javascript_key keys in the input_dict to python_keys in
1092    the output dict using the mapping in model_class.
1093    If the input_dict contains a key which does not declared in the model_class,
1094    the key is added to the output dict as is. The assumption is the model_class
1095    may have undeclared properties (additionalProperties attribute in the OAS
1096    document).
1097    """
1098
1099    if getattr(model_class, "attribute_map", None) is None:
1100        return input_dict
1101    output_dict = {}
1102    reversed_attr_map = {value: key for key, value in model_class.attribute_map.items()}
1103    for javascript_key, value in input_dict.items():
1104        python_key = reversed_attr_map.get(javascript_key)
1105        if python_key is None:
1106            # if the key is unknown, it is in error or it is an
1107            # additionalProperties variable
1108            python_key = javascript_key
1109        output_dict[python_key] = value
1110    return output_dict
1111
1112
1113def get_type_error(var_value, path_to_item, valid_classes, key_type=False):
1114    error_msg = type_error_message(
1115        var_name=path_to_item[-1], var_value=var_value, valid_classes=valid_classes, key_type=key_type
1116    )
1117    return ApiTypeError(error_msg, path_to_item=path_to_item, valid_classes=valid_classes, key_type=key_type)
1118
1119
1120def deserialize_primitive(data, klass, path_to_item):
1121    """Deserializes string to primitive type.
1122
1123    :param data: str/int/float
1124    :param klass: str/class the class to convert to
1125
1126    :return: int, float, str, bool, date, datetime
1127    """
1128    additional_message = ""
1129    try:
1130        if klass in {datetime, date}:
1131            additional_message = (
1132                "If you need your parameter to have a fallback "
1133                "string value, please set its type as `type: {}` in your "
1134                "spec. That allows the value to be any type. "
1135            )
1136            if klass == datetime:
1137                if len(data) < 8:
1138                    raise ValueError("This is not a datetime")
1139                # The string should be in iso8601 datetime format.
1140                parsed_datetime = parse(data)
1141                date_only = (
1142                    parsed_datetime.hour == 0
1143                    and parsed_datetime.minute == 0
1144                    and parsed_datetime.second == 0
1145                    and parsed_datetime.tzinfo is None
1146                    and 8 <= len(data) <= 10
1147                )
1148                if date_only:
1149                    raise ValueError("This is a date, not a datetime")
1150                return parsed_datetime
1151            elif klass == date:
1152                if len(data) < 8:
1153                    raise ValueError("This is not a date")
1154                return parse(data).date()
1155        else:
1156            converted_value = klass(data)
1157            if isinstance(data, str) and klass == float:
1158                if str(converted_value) != data:
1159                    # '7' -> 7.0 -> '7.0' != '7'
1160                    raise ValueError("This is not a float")
1161            return converted_value
1162    except (OverflowError, ValueError) as ex:
1163        # parse can raise OverflowError
1164        raise ApiValueError(
1165            "{0}Failed to parse {1} as {2}".format(additional_message, repr(data), klass.__name__),
1166            path_to_item=path_to_item,
1167        ) from ex
1168
1169
1170def get_discriminator_class(model_class, discr_name, discr_value, cls_visited):
1171    """Returns the child class specified by the discriminator.
1172
1173    Args:
1174        model_class (OpenApiModel): the model class.
1175        discr_name (string): the name of the discriminator property.
1176        discr_value (any): the discriminator value.
1177        cls_visited (list): list of model classes that have been visited.
1178            Used to determine the discriminator class without
1179            visiting circular references indefinitely.
1180
1181    Returns:
1182        used_model_class (class/None): the chosen child class that will be used
1183            to deserialize the data, for example dog.Dog.
1184            If a class is not found, None is returned.
1185    """
1186
1187    if model_class in cls_visited:
1188        # The class has already been visited and no suitable class was found.
1189        return None
1190    cls_visited.append(model_class)
1191    used_model_class = None
1192    if discr_name in model_class.discriminator:
1193        class_name_to_discr_class = model_class.discriminator[discr_name]
1194        used_model_class = class_name_to_discr_class.get(discr_value)
1195    if used_model_class is None:
1196        # We didn't find a discriminated class in class_name_to_discr_class.
1197        # So look in the ancestor or descendant discriminators
1198        # The discriminator mapping may exist in a descendant (anyOf, oneOf)
1199        # or ancestor (allOf).
1200        # Ancestor example: in the GrandparentAnimal -> ParentPet -> ChildCat
1201        #   hierarchy, the discriminator mappings may be defined at any level
1202        #   in the hierarchy.
1203        # Descendant example:  mammal -> whale/zebra/Pig -> BasquePig/DanishPig
1204        #   if we try to make BasquePig from mammal, we need to travel through
1205        #   the oneOf descendant discriminators to find BasquePig
1206        descendant_classes = model_class._composed_schemas.get("oneOf", ()) + model_class._composed_schemas.get(
1207            "anyOf", ()
1208        )
1209        ancestor_classes = model_class._composed_schemas.get("allOf", ())
1210        possible_classes = descendant_classes + ancestor_classes
1211        for cls in possible_classes:
1212            # Check if the schema has inherited discriminators.
1213            if hasattr(cls, "discriminator") and cls.discriminator is not None:
1214                used_model_class = get_discriminator_class(cls, discr_name, discr_value, cls_visited)
1215                if used_model_class is not None:
1216                    return used_model_class
1217    return used_model_class
1218
1219
1220def deserialize_model(model_data, model_class, path_to_item, check_type, configuration, spec_property_naming):
1221    """Deserializes model_data to model instance.
1222
1223    Args:
1224        model_data (int/str/float/bool/none_type/list/dict): data to instantiate the model
1225        model_class (OpenApiModel): the model class
1226        path_to_item (list): path to the model in the received data
1227        check_type (bool): whether to check the data tupe for the values in
1228            the model
1229        configuration (Configuration): the instance to use to convert files
1230        spec_property_naming (bool): True if the variable names in the input
1231            data are serialized names as specified in the OpenAPI document.
1232            False if the variables names in the input data are python
1233            variable names in PEP-8 snake case.
1234
1235    Returns:
1236        model instance
1237
1238    Raise:
1239        ApiTypeError
1240        ApiValueError
1241        ApiKeyError
1242    """
1243
1244    kw_args = dict(
1245        _check_type=check_type,
1246        _path_to_item=path_to_item,
1247        _configuration=configuration,
1248        _spec_property_naming=spec_property_naming,
1249    )
1250
1251    if issubclass(model_class, ModelSimple):
1252        return model_class._new_from_openapi_data(model_data, **kw_args)
1253    elif isinstance(model_data, list):
1254        return model_class._new_from_openapi_data(*model_data, **kw_args)
1255    if isinstance(model_data, dict):
1256        kw_args.update(model_data)
1257        return model_class._new_from_openapi_data(**kw_args)
1258    elif isinstance(model_data, PRIMITIVE_TYPES):
1259        return model_class._new_from_openapi_data(model_data, **kw_args)
1260
1261
1262def deserialize_file(response_data, configuration, content_disposition=None):
1263    """Deserializes body to file
1264
1265    Saves response body into a file in a temporary folder,
1266    using the filename from the `Content-Disposition` header if provided.
1267
1268    Args:
1269        param response_data (str):  the file data to write
1270        configuration (Configuration): the instance to use to convert files
1271
1272    Keyword Args:
1273        content_disposition (str):  the value of the Content-Disposition
1274            header
1275
1276    Returns:
1277        (file_type): the deserialized file which is open
1278            The user is responsible for closing and reading the file
1279    """
1280    fd, path = tempfile.mkstemp(dir=configuration.temp_folder_path)
1281    os.close(fd)
1282    os.remove(path)
1283
1284    if content_disposition:
1285        filename = re.search(r'filename=[\'"]?([^\'"\s]+)[\'"]?', content_disposition).group(1)
1286        path = os.path.join(os.path.dirname(path), filename)
1287
1288    with open(path, "wb") as f:
1289        if isinstance(response_data, str):
1290            # change str to bytes so we can write it
1291            response_data = response_data.encode("utf-8")
1292        f.write(response_data)
1293
1294    f = open(path, "rb")
1295    return f
1296
1297
1298def attempt_convert_item(
1299    input_value,
1300    valid_classes,
1301    path_to_item,
1302    configuration,
1303    spec_property_naming,
1304    key_type=False,
1305    must_convert=False,
1306    check_type=True,
1307):
1308    """
1309    Args:
1310        input_value (any): the data to convert
1311        valid_classes (any): the classes that are valid
1312        path_to_item (list): the path to the item to convert
1313        configuration (Configuration): the instance to use to convert files
1314        spec_property_naming (bool): True if the variable names in the input
1315            data are serialized names as specified in the OpenAPI document.
1316            False if the variables names in the input data are python
1317            variable names in PEP-8 snake case.
1318        key_type (bool): if True we need to convert a key type (not supported)
1319        must_convert (bool): if True we must convert
1320        check_type (bool): if True we check the type or the returned data in
1321            ModelComposed/ModelNormal/ModelSimple instances
1322
1323    Returns:
1324        instance (any) the fixed item
1325
1326    Raises:
1327        ApiTypeError
1328        ApiValueError
1329        ApiKeyError
1330    """
1331    valid_classes_ordered = order_response_types(valid_classes)
1332    valid_classes_coercible = remove_uncoercible(valid_classes_ordered, input_value, spec_property_naming)
1333    if not valid_classes_coercible or key_type:
1334        # we do not handle keytype errors, json will take care
1335        # of this for us
1336        if configuration is None or not configuration.discard_unknown_keys:
1337            raise get_type_error(input_value, path_to_item, valid_classes, key_type=key_type)
1338    for valid_class in valid_classes_coercible:
1339        try:
1340            if issubclass(valid_class, OpenApiModel):
1341                return deserialize_model(
1342                    input_value, valid_class, path_to_item, check_type, configuration, spec_property_naming
1343                )
1344            elif valid_class == file_type:
1345                return deserialize_file(input_value, configuration)
1346            return deserialize_primitive(input_value, valid_class, path_to_item)
1347        except (ApiTypeError, ApiValueError, ApiKeyError) as conversion_exc:
1348            if must_convert:
1349                raise conversion_exc
1350            # if we have conversion errors when must_convert == False
1351            # we ignore the exception and move on to the next class
1352            continue
1353    # we were unable to convert, must_convert == False
1354    return input_value
1355
1356
1357def is_type_nullable(input_type):
1358    """
1359    Returns true if None is an allowed value for the specified input_type.
1360
1361    A type is nullable if at least one of the following conditions is true:
1362    1. The OAS 'nullable' attribute has been specified,
1363    1. The type is the 'null' type,
1364    1. The type is a anyOf/oneOf composed schema, and a child schema is
1365       the 'null' type.
1366    Args:
1367        input_type (type): the class of the input_value that we are
1368            checking
1369    Returns:
1370        bool
1371    """
1372    if input_type is none_type:
1373        return True
1374    if issubclass(input_type, OpenApiModel) and input_type._nullable:
1375        return True
1376    if issubclass(input_type, ModelComposed):
1377        # If oneOf/anyOf, check if the 'null' type is one of the allowed types.
1378        for t in input_type._composed_schemas.get("oneOf", ()):
1379            if is_type_nullable(t):
1380                return True
1381        for t in input_type._composed_schemas.get("anyOf", ()):
1382            if is_type_nullable(t):
1383                return True
1384    return False
1385
1386
1387def is_valid_type(input_class_simple, valid_classes):
1388    """
1389    Args:
1390        input_class_simple (class): the class of the input_value that we are
1391            checking
1392        valid_classes (tuple): the valid classes that the current item
1393            should be
1394    Returns:
1395        bool
1396    """
1397    valid_type = input_class_simple in valid_classes
1398    if not valid_type and (issubclass(input_class_simple, OpenApiModel) or input_class_simple is none_type):
1399        for valid_class in valid_classes:
1400            if input_class_simple is none_type and is_type_nullable(valid_class):
1401                # Schema is oneOf/anyOf and the 'null' type is one of the allowed types.
1402                return True
1403            if not (issubclass(valid_class, OpenApiModel) and valid_class.discriminator):
1404                continue
1405            discr_propertyname_py = list(valid_class.discriminator.keys())[0]
1406            discriminator_classes = valid_class.discriminator[discr_propertyname_py].values()
1407            valid_type = is_valid_type(input_class_simple, discriminator_classes)
1408            if valid_type:
1409                return True
1410    return valid_type
1411
1412
1413def validate_and_convert_types(
1414    input_value, required_types_mixed, path_to_item, spec_property_naming, _check_type, configuration=None
1415):
1416    """Raises a TypeError is there is a problem, otherwise returns value
1417
1418    Args:
1419        input_value (any): the data to validate/convert
1420        required_types_mixed (list/dict/tuple): A list of
1421            valid classes, or a list tuples of valid classes, or a dict where
1422            the value is a tuple of value classes
1423        path_to_item: (list) the path to the data being validated
1424            this stores a list of keys or indices to get to the data being
1425            validated
1426        spec_property_naming (bool): True if the variable names in the input
1427            data are serialized names as specified in the OpenAPI document.
1428            False if the variables names in the input data are python
1429            variable names in PEP-8 snake case.
1430        _check_type: (boolean) if true, type will be checked and conversion
1431            will be attempted.
1432        configuration: (Configuration): the configuration class to use
1433            when converting file_type items.
1434            If passed, conversion will be attempted when possible
1435            If not passed, no conversions will be attempted and
1436            exceptions will be raised
1437
1438    Returns:
1439        the correctly typed value
1440
1441    Raises:
1442        ApiTypeError
1443    """
1444    results = get_required_type_classes(required_types_mixed, spec_property_naming)
1445    valid_classes, child_req_types_by_current_type = results
1446
1447    input_class_simple = get_simple_class(input_value)
1448    valid_type = is_valid_type(input_class_simple, valid_classes)
1449    if not valid_type:
1450        if configuration:
1451            # if input_value is not valid_type try to convert it
1452            converted_instance = attempt_convert_item(
1453                input_value,
1454                valid_classes,
1455                path_to_item,
1456                configuration,
1457                spec_property_naming,
1458                key_type=False,
1459                must_convert=True,
1460                check_type=_check_type,
1461            )
1462            return converted_instance
1463        else:
1464            raise get_type_error(input_value, path_to_item, valid_classes, key_type=False)
1465
1466    # input_value's type is in valid_classes
1467    if len(valid_classes) > 1 and configuration:
1468        # there are valid classes which are not the current class
1469        valid_classes_coercible = remove_uncoercible(
1470            valid_classes, input_value, spec_property_naming, must_convert=False
1471        )
1472        if valid_classes_coercible:
1473            converted_instance = attempt_convert_item(
1474                input_value,
1475                valid_classes_coercible,
1476                path_to_item,
1477                configuration,
1478                spec_property_naming,
1479                key_type=False,
1480                must_convert=False,
1481                check_type=_check_type,
1482            )
1483            return converted_instance
1484
1485    if child_req_types_by_current_type == {}:
1486        # all types are of the required types and there are no more inner
1487        # variables left to look at
1488        return input_value
1489    inner_required_types = child_req_types_by_current_type.get(type(input_value))
1490    if inner_required_types is None:
1491        # for this type, there are not more inner variables left to look at
1492        return input_value
1493    if isinstance(input_value, list):
1494        if input_value == []:
1495            # allow an empty list
1496            return input_value
1497        for index, inner_value in enumerate(input_value):
1498            inner_path = list(path_to_item)
1499            inner_path.append(index)
1500            input_value[index] = validate_and_convert_types(
1501                inner_value,
1502                inner_required_types,
1503                inner_path,
1504                spec_property_naming,
1505                _check_type,
1506                configuration=configuration,
1507            )
1508    elif isinstance(input_value, dict):
1509        if input_value == {}:
1510            # allow an empty dict
1511            return input_value
1512        for inner_key, inner_val in input_value.items():
1513            inner_path = list(path_to_item)
1514            inner_path.append(inner_key)
1515            if get_simple_class(inner_key) != str:
1516                raise get_type_error(inner_key, inner_path, valid_classes, key_type=True)
1517            input_value[inner_key] = validate_and_convert_types(
1518                inner_val,
1519                inner_required_types,
1520                inner_path,
1521                spec_property_naming,
1522                _check_type,
1523                configuration=configuration,
1524            )
1525    return input_value
1526
1527
1528def model_to_dict(model_instance, serialize=True):
1529    """Returns the model properties as a dict
1530
1531    Args:
1532        model_instance (one of your model instances): the model instance that
1533            will be converted to a dict.
1534
1535    Keyword Args:
1536        serialize (bool): if True, the keys in the dict will be values from
1537            attribute_map
1538    """
1539    result = {}
1540
1541    model_instances = [model_instance]
1542    if model_instance._composed_schemas:
1543        model_instances.extend(model_instance._composed_instances)
1544    seen_json_attribute_names = set()
1545    used_fallback_python_attribute_names = set()
1546    py_to_json_map = {}
1547    for model_instance in model_instances:
1548        for attr, value in model_instance._data_store.items():
1549            if serialize:
1550                # we use get here because additional property key names do not
1551                # exist in attribute_map
1552                try:
1553                    attr = model_instance.attribute_map[attr]
1554                    py_to_json_map.update(model_instance.attribute_map)
1555                    seen_json_attribute_names.add(attr)
1556                except KeyError:
1557                    used_fallback_python_attribute_names.add(attr)
1558            if isinstance(value, list):
1559                if not value:
1560                    # empty list or None
1561                    result[attr] = value
1562                else:
1563                    res = []
1564                    for v in value:
1565                        if isinstance(v, PRIMITIVE_TYPES) or v is None:
1566                            res.append(v)
1567                        elif isinstance(v, ModelSimple):
1568                            res.append(v.value)
1569                        else:
1570                            res.append(model_to_dict(v, serialize=serialize))
1571                    result[attr] = res
1572            elif isinstance(value, dict):
1573                result[attr] = dict(
1574                    map(
1575                        lambda item: (item[0], model_to_dict(item[1], serialize=serialize))
1576                        if hasattr(item[1], "_data_store")
1577                        else item,
1578                        value.items(),
1579                    )
1580                )
1581            elif isinstance(value, ModelSimple):
1582                result[attr] = value.value
1583            elif hasattr(value, "_data_store"):
1584                result[attr] = model_to_dict(value, serialize=serialize)
1585            else:
1586                result[attr] = value
1587    if serialize:
1588        for python_key in used_fallback_python_attribute_names:
1589            json_key = py_to_json_map.get(python_key)
1590            if json_key is None:
1591                continue
1592            if python_key == json_key:
1593                continue
1594            json_key_assigned_no_need_for_python_key = json_key in seen_json_attribute_names
1595            if json_key_assigned_no_need_for_python_key:
1596                del result[python_key]
1597
1598    return result
1599
1600
1601def type_error_message(var_value=None, var_name=None, valid_classes=None, key_type=None):
1602    """
1603    Keyword Args:
1604        var_value (any): the variable which has the type_error
1605        var_name (str): the name of the variable which has the typ error
1606        valid_classes (tuple): the accepted classes for current_item's
1607                                  value
1608        key_type (bool): False if our value is a value in a dict
1609                         True if it is a key in a dict
1610                         False if our item is an item in a list
1611    """
1612    key_or_value = "value"
1613    if key_type:
1614        key_or_value = "key"
1615    valid_classes_phrase = get_valid_classes_phrase(valid_classes)
1616    msg = "Invalid type for variable '{0}'. Required {1} type {2} and " "passed type was {3}".format(
1617        var_name,
1618        key_or_value,
1619        valid_classes_phrase,
1620        type(var_value).__name__,
1621    )
1622    return msg
1623
1624
1625def get_valid_classes_phrase(input_classes):
1626    """Returns a string phrase describing what types are allowed"""
1627    all_classes = list(input_classes)
1628    all_classes = sorted(all_classes, key=lambda cls: cls.__name__)
1629    all_class_names = [cls.__name__ for cls in all_classes]
1630    if len(all_class_names) == 1:
1631        return "is {0}".format(all_class_names[0])
1632    return "is one of [{0}]".format(", ".join(all_class_names))
1633
1634
1635def get_allof_instances(self, model_args, constant_args):
1636    """
1637    Args:
1638        self: the class we are handling
1639        model_args (dict): var_name to var_value
1640            used to make instances
1641        constant_args (dict):
1642            metadata arguments:
1643            _check_type
1644            _path_to_item
1645            _spec_property_naming
1646            _configuration
1647            _visited_composed_classes
1648
1649    Returns
1650        composed_instances (list)
1651    """
1652    composed_instances = []
1653    for allof_class in self._composed_schemas["allOf"]:
1654        try:
1655            allof_instance = allof_class(**model_args, **constant_args)
1656            composed_instances.append(allof_instance)
1657        except Exception as ex:
1658            raise ApiValueError(
1659                "Invalid inputs given to generate an instance of '%s'. The "
1660                "input data was invalid for the allOf schema '%s' in the composed "
1661                "schema '%s'. Error=%s" % (allof_class.__name__, allof_class.__name__, self.__class__.__name__, str(ex))
1662            ) from ex
1663    return composed_instances
1664
1665
1666def get_oneof_instance(cls, model_kwargs, constant_kwargs, model_arg=None):
1667    """
1668    Find the oneOf schema that matches the input data (e.g. payload).
1669    If exactly one schema matches the input data, an instance of that schema
1670    is returned.
1671    If zero or more than one schema match the input data, an exception is raised.
1672    In OAS 3.x, the payload MUST, by validation, match exactly one of the
1673    schemas described by oneOf.
1674
1675    Args:
1676        cls: the class we are handling
1677        model_kwargs (dict): var_name to var_value
1678            The input data, e.g. the payload that must match a oneOf schema
1679            in the OpenAPI document.
1680        constant_kwargs (dict): var_name to var_value
1681            args that every model requires, including configuration, server
1682            and path to item.
1683
1684    Kwargs:
1685        model_arg: (int, float, bool, str, date, datetime, ModelSimple, None):
1686            the value to assign to a primitive class or ModelSimple class
1687            Notes:
1688            - this is only passed in when oneOf includes types which are not object
1689            - None is used to suppress handling of model_arg, nullable models are handled in __new__
1690
1691    Returns
1692        oneof_instance (instance)
1693    """
1694    if len(cls._composed_schemas["oneOf"]) == 0:
1695        return None
1696
1697    oneof_instances = []
1698    # Iterate over each oneOf schema and determine if the input data
1699    # matches the oneOf schemas.
1700    for oneof_class in cls._composed_schemas["oneOf"]:
1701        # The composed oneOf schema allows the 'null' type and the input data
1702        # is the null value. This is a OAS >= 3.1 feature.
1703        if oneof_class is none_type:
1704            # skip none_types because we are deserializing dict data.
1705            # none_type deserialization is handled in the __new__ method
1706            continue
1707
1708        single_value_input = allows_single_value_input(oneof_class)
1709
1710        try:
1711            if not single_value_input:
1712                oneof_instance = oneof_class(**model_kwargs, **constant_kwargs)
1713            else:
1714                if issubclass(oneof_class, ModelSimple):
1715                    oneof_instance = oneof_class(model_arg, **constant_kwargs)
1716                elif oneof_class in PRIMITIVE_TYPES:
1717                    oneof_instance = validate_and_convert_types(
1718                        model_arg,
1719                        (oneof_class,),
1720                        constant_kwargs["_path_to_item"],
1721                        constant_kwargs["_spec_property_naming"],
1722                        constant_kwargs["_check_type"],
1723                        configuration=constant_kwargs["_configuration"],
1724                    )
1725            oneof_instances.append(oneof_instance)
1726        except Exception:
1727            pass
1728    if len(oneof_instances) == 0:
1729        raise ApiValueError(
1730            "Invalid inputs given to generate an instance of %s. None "
1731            "of the oneOf schemas matched the input data." % cls.__name__
1732        )
1733    elif len(oneof_instances) > 1:
1734        raise ApiValueError(
1735            "Invalid inputs given to generate an instance of %s. Multiple "
1736            "oneOf schemas matched the inputs, but a max of one is allowed." % cls.__name__
1737        )
1738    return oneof_instances[0]
1739
1740
1741def get_anyof_instances(self, model_args, constant_args):
1742    """
1743    Args:
1744        self: the class we are handling
1745        model_args (dict): var_name to var_value
1746            The input data, e.g. the payload that must match at least one
1747            anyOf child schema in the OpenAPI document.
1748        constant_args (dict): var_name to var_value
1749            args that every model requires, including configuration, server
1750            and path to item.
1751
1752    Returns
1753        anyof_instances (list)
1754    """
1755    anyof_instances = []
1756    if len(self._composed_schemas["anyOf"]) == 0:
1757        return anyof_instances
1758
1759    for anyof_class in self._composed_schemas["anyOf"]:
1760        # The composed oneOf schema allows the 'null' type and the input data
1761        # is the null value. This is a OAS >= 3.1 feature.
1762        if anyof_class is none_type:
1763            # skip none_types because we are deserializing dict data.
1764            # none_type deserialization is handled in the __new__ method
1765            continue
1766
1767        try:
1768            anyof_instance = anyof_class(**model_args, **constant_args)
1769            anyof_instances.append(anyof_instance)
1770        except Exception:
1771            pass
1772    if len(anyof_instances) == 0:
1773        raise ApiValueError(
1774            "Invalid inputs given to generate an instance of %s. None of the "
1775            "anyOf schemas matched the inputs." % self.__class__.__name__
1776        )
1777    return anyof_instances
1778
1779
1780def get_discarded_args(self, composed_instances, model_args):
1781    """
1782    Gathers the args that were discarded by configuration.discard_unknown_keys
1783    """
1784    model_arg_keys = model_args.keys()
1785    discarded_args = set()
1786    # arguments passed to self were already converted to python names
1787    # before __init__ was called
1788    for instance in composed_instances:
1789        if instance.__class__ in self._composed_schemas["allOf"]:
1790            try:
1791                keys = instance.to_dict().keys()
1792                discarded_keys = model_args - keys
1793                discarded_args.update(discarded_keys)
1794            except Exception:
1795                # allOf integer schema will throw exception
1796                pass
1797        else:
1798            try:
1799                all_keys = set(model_to_dict(instance, serialize=False).keys())
1800                js_keys = model_to_dict(instance, serialize=True).keys()
1801                all_keys.update(js_keys)
1802                discarded_keys = model_arg_keys - all_keys
1803                discarded_args.update(discarded_keys)
1804            except Exception:
1805                # allOf integer schema will throw exception
1806                pass
1807    return discarded_args
1808
1809
1810def validate_get_composed_info(constant_args, model_args, self):
1811    """
1812    For composed schemas, generate schema instances for
1813    all schemas in the oneOf/anyOf/allOf definition. If additional
1814    properties are allowed, also assign those properties on
1815    all matched schemas that contain additionalProperties.
1816    Openapi schemas are python classes.
1817
1818    Exceptions are raised if:
1819    - 0 or > 1 oneOf schema matches the model_args input data
1820    - no anyOf schema matches the model_args input data
1821    - any of the allOf schemas do not match the model_args input data
1822
1823    Args:
1824        constant_args (dict): these are the args that every model requires
1825        model_args (dict): these are the required and optional spec args that
1826            were passed in to make this model
1827        self (class): the class that we are instantiating
1828            This class contains self._composed_schemas
1829
1830    Returns:
1831        composed_info (list): length three
1832            composed_instances (list): the composed instances which are not
1833                self
1834            var_name_to_model_instances (dict): a dict going from var_name
1835                to the model_instance which holds that var_name
1836                the model_instance may be self or an instance of one of the
1837                classes in self.composed_instances()
1838            additional_properties_model_instances (list): a list of the
1839                model instances which have the property
1840                additional_properties_type. This list can include self
1841    """
1842    # create composed_instances
1843    composed_instances = []
1844    allof_instances = get_allof_instances(self, model_args, constant_args)
1845    composed_instances.extend(allof_instances)
1846    oneof_instance = get_oneof_instance(self.__class__, model_args, constant_args)
1847    if oneof_instance is not None:
1848        composed_instances.append(oneof_instance)
1849    anyof_instances = get_anyof_instances(self, model_args, constant_args)
1850    composed_instances.extend(anyof_instances)
1851    """
1852    set additional_properties_model_instances
1853    additional properties must be evaluated at the schema level
1854    so self's additional properties are most important
1855    If self is a composed schema with:
1856    - no properties defined in self
1857    - additionalProperties: False
1858    Then for object payloads every property is an additional property
1859    and they are not allowed, so only empty dict is allowed
1860
1861    Properties must be set on all matching schemas
1862    so when a property is assigned toa composed instance, it must be set on all
1863    composed instances regardless of additionalProperties presence
1864    keeping it to prevent breaking changes in v5.0.1
1865    TODO remove cls._additional_properties_model_instances in 6.0.0
1866    """
1867    additional_properties_model_instances = []
1868    if self.additional_properties_type is not None:
1869        additional_properties_model_instances = [self]
1870
1871    """
1872    no need to set properties on self in here, they will be set in __init__
1873    By here all composed schema oneOf/anyOf/allOf instances have their properties set using
1874    model_args
1875    """
1876    discarded_args = get_discarded_args(self, composed_instances, model_args)
1877
1878    # map variable names to composed_instances
1879    var_name_to_model_instances = {}
1880    for prop_name in model_args:
1881        if prop_name not in discarded_args:
1882            var_name_to_model_instances[prop_name] = [self] + composed_instances
1883
1884    return [composed_instances, var_name_to_model_instances, additional_properties_model_instances, discarded_args]
none_type = <class 'NoneType'>
file_type = <class 'io.IOBase'>
def convert_js_args_to_python_args(fn):
34def convert_js_args_to_python_args(fn):
35    from functools import wraps
36
37    @wraps(fn)
38    def wrapped_init(_self, *args, **kwargs):
39        """
40        An attribute named `self` received from the api will conflicts with the reserved `self`
41        parameter of a class method. During generation, `self` attributes are mapped
42        to `_self` in models. Here, we name `_self` instead of `self` to avoid conflicts.
43        """
44        spec_property_naming = kwargs.get("_spec_property_naming", False)
45        if spec_property_naming:
46            kwargs = change_keys_js_to_python(kwargs, _self if isinstance(_self, type) else _self.__class__)
47        return fn(_self, *args, **kwargs)
48
49    return wrapped_init
class cached_property:
52class cached_property(object):
53    # this caches the result of the function call for fn with no inputs
54    # use this as a decorator on function methods that you want converted
55    # into cached properties
56    result_key = "_results"
57
58    def __init__(self, fn):
59        self._fn = fn
60
61    def __get__(self, instance, cls=None):
62        if self.result_key in vars(self):
63            return vars(self)[self.result_key]
64        else:
65            result = self._fn()
66            setattr(self, self.result_key, result)
67            return result
cached_property(fn)
58    def __init__(self, fn):
59        self._fn = fn
result_key = '_results'
PRIMITIVE_TYPES = (<class 'list'>, <class 'float'>, <class 'int'>, <class 'bool'>, <class 'datetime.datetime'>, <class 'datetime.date'>, <class 'str'>, <class 'io.IOBase'>)
def allows_single_value_input(cls):
73def allows_single_value_input(cls):
74    """
75    This function returns True if the input composed schema model or any
76    descendant model allows a value only input
77    This is true for cases where oneOf contains items like:
78    oneOf:
79      - float
80      - NumberWithValidation
81      - StringEnum
82      - ArrayModel
83      - null
84    TODO: lru_cache this
85    """
86    if issubclass(cls, ModelSimple) or cls in PRIMITIVE_TYPES:
87        return True
88    elif issubclass(cls, ModelComposed):
89        if not cls._composed_schemas["oneOf"]:
90            return False
91        return any(allows_single_value_input(c) for c in cls._composed_schemas["oneOf"])
92    return False

This function returns True if the input composed schema model or any descendant model allows a value only input This is true for cases where oneOf contains items like: oneOf:

  • float
  • NumberWithValidation
  • StringEnum
  • ArrayModel
  • null TODO: lru_cache this
def composed_model_input_classes(cls):
 95def composed_model_input_classes(cls):
 96    """
 97    This function returns a list of the possible models that can be accepted as
 98    inputs.
 99    TODO: lru_cache this
100    """
101    if issubclass(cls, ModelSimple) or cls in PRIMITIVE_TYPES:
102        return [cls]
103    elif issubclass(cls, ModelNormal):
104        if cls.discriminator is None:
105            return [cls]
106        else:
107            return get_discriminated_classes(cls)
108    elif issubclass(cls, ModelComposed):
109        if not cls._composed_schemas["oneOf"]:
110            return []
111        if cls.discriminator is None:
112            input_classes = []
113            for c in cls._composed_schemas["oneOf"]:
114                input_classes.extend(composed_model_input_classes(c))
115            return input_classes
116        else:
117            return get_discriminated_classes(cls)
118    return []

This function returns a list of the possible models that can be accepted as inputs. TODO: lru_cache this

class OpenApiModel:
121class OpenApiModel(object):
122    """The base class for all OpenAPIModels"""
123
124    def set_attribute(self, name, value):
125        # this is only used to set properties on self
126
127        path_to_item = []
128        if self._path_to_item:
129            path_to_item.extend(self._path_to_item)
130        path_to_item.append(name)
131
132        if name in self.openapi_types:
133            required_types_mixed = self.openapi_types[name]
134        elif self.additional_properties_type is None:
135            raise ApiAttributeError("{0} has no attribute '{1}'".format(type(self).__name__, name), path_to_item)
136        elif self.additional_properties_type is not None:
137            required_types_mixed = self.additional_properties_type
138
139        if get_simple_class(name) != str:
140            error_msg = type_error_message(var_name=name, var_value=name, valid_classes=(str,), key_type=True)
141            raise ApiTypeError(error_msg, path_to_item=path_to_item, valid_classes=(str,), key_type=True)
142
143        if self._check_type:
144            value = validate_and_convert_types(
145                value,
146                required_types_mixed,
147                path_to_item,
148                self._spec_property_naming,
149                self._check_type,
150                configuration=self._configuration,
151            )
152        if (name,) in self.allowed_values:
153            check_allowed_values(self.allowed_values, (name,), value)
154        if (name,) in self.validations:
155            check_validations(self.validations, (name,), value, self._configuration)
156        self.__dict__["_data_store"][name] = value
157
158    def __repr__(self):
159        """For `print` and `pprint`"""
160        return self.to_str()
161
162    def __ne__(self, other):
163        """Returns true if both objects are not equal"""
164        return not self == other
165
166    def __setattr__(self, attr, value):
167        """set the value of an attribute using dot notation: `instance.attr = val`"""
168        self[attr] = value
169
170    def __getattr__(self, attr):
171        """get the value of an attribute using dot notation: `instance.attr`"""
172        return self.get(attr)
173
174    def __new__(cls, *args, **kwargs):
175        # this function uses the discriminator to
176        # pick a new schema/class to instantiate because a discriminator
177        # propertyName value was passed in
178
179        if len(args) == 1:
180            arg = args[0]
181            if arg is None and is_type_nullable(cls):
182                # The input data is the 'null' value and the type is nullable.
183                return None
184
185            if issubclass(cls, ModelComposed) and allows_single_value_input(cls):
186                model_kwargs = {}
187                oneof_instance = get_oneof_instance(cls, model_kwargs, kwargs, model_arg=arg)
188                return oneof_instance
189
190        visited_composed_classes = kwargs.get("_visited_composed_classes", ())
191        if cls.discriminator is None or cls in visited_composed_classes:
192            # Use case 1: this openapi schema (cls) does not have a discriminator
193            # Use case 2: we have already visited this class before and are sure that we
194            # want to instantiate it this time. We have visited this class deserializing
195            # a payload with a discriminator. During that process we traveled through
196            # this class but did not make an instance of it. Now we are making an
197            # instance of a composed class which contains cls in it, so this time make an instance of cls.
198            #
199            # Here's an example of use case 2: If Animal has a discriminator
200            # petType and we pass in "Dog", and the class Dog
201            # allOf includes Animal, we move through Animal
202            # once using the discriminator, and pick Dog.
203            # Then in the composed schema dog Dog, we will make an instance of the
204            # Animal class (because Dal has allOf: Animal) but this time we won't travel
205            # through Animal's discriminator because we passed in
206            # _visited_composed_classes = (Animal,)
207
208            return super(OpenApiModel, cls).__new__(cls)
209
210        # Get the name and value of the discriminator property.
211        # The discriminator name is obtained from the discriminator meta-data
212        # and the discriminator value is obtained from the input data.
213        discr_propertyname_py = list(cls.discriminator.keys())[0]
214        discr_propertyname_js = cls.attribute_map[discr_propertyname_py]
215        if discr_propertyname_js in kwargs:
216            discr_value = kwargs[discr_propertyname_js]
217        elif discr_propertyname_py in kwargs:
218            discr_value = kwargs[discr_propertyname_py]
219        else:
220            # The input data does not contain the discriminator property.
221            path_to_item = kwargs.get("_path_to_item", ())
222            raise ApiValueError(
223                "Cannot deserialize input data due to missing discriminator. "
224                "The discriminator property '%s' is missing at path: %s" % (discr_propertyname_js, path_to_item)
225            )
226
227        # Implementation note: the last argument to get_discriminator_class
228        # is a list of visited classes. get_discriminator_class may recursively
229        # call itself and update the list of visited classes, and the initial
230        # value must be an empty list. Hence not using 'visited_composed_classes'
231        new_cls = get_discriminator_class(cls, discr_propertyname_py, discr_value, [])
232        if new_cls is None:
233            path_to_item = kwargs.get("_path_to_item", ())
234            disc_prop_value = kwargs.get(discr_propertyname_js, kwargs.get(discr_propertyname_py))
235            raise ApiValueError(
236                "Cannot deserialize input data due to invalid discriminator "
237                "value. The OpenAPI document has no mapping for discriminator "
238                "property '%s'='%s' at path: %s" % (discr_propertyname_js, disc_prop_value, path_to_item)
239            )
240
241        if new_cls in visited_composed_classes:
242            # if we are making an instance of a composed schema Descendent
243            # which allOf includes Ancestor, then Ancestor contains
244            # a discriminator that includes Descendent.
245            # So if we make an instance of Descendent, we have to make an
246            # instance of Ancestor to hold the allOf properties.
247            # This code detects that use case and makes the instance of Ancestor
248            # For example:
249            # When making an instance of Dog, _visited_composed_classes = (Dog,)
250            # then we make an instance of Animal to include in dog._composed_instances
251            # so when we are here, cls is Animal
252            # cls.discriminator != None
253            # cls not in _visited_composed_classes
254            # new_cls = Dog
255            # but we know we know that we already have Dog
256            # because it is in visited_composed_classes
257            # so make Animal here
258            return super(OpenApiModel, cls).__new__(cls)
259
260        # Build a list containing all oneOf and anyOf descendants.
261        oneof_anyof_classes = None
262        if cls._composed_schemas is not None:
263            oneof_anyof_classes = cls._composed_schemas.get("oneOf", ()) + cls._composed_schemas.get("anyOf", ())
264        oneof_anyof_child = new_cls in oneof_anyof_classes
265        kwargs["_visited_composed_classes"] = visited_composed_classes + (cls,)
266
267        if cls._composed_schemas.get("allOf") and oneof_anyof_child:
268            # Validate that we can make self because when we make the
269            # new_cls it will not include the allOf validations in self
270            self_inst = super(OpenApiModel, cls).__new__(cls)
271            self_inst.__init__(*args, **kwargs)
272
273        new_inst = new_cls.__new__(new_cls, *args, **kwargs)
274        new_inst.__init__(*args, **kwargs)
275        return new_inst
276
277    @classmethod
278    @convert_js_args_to_python_args
279    def _new_from_openapi_data(cls, *args, **kwargs):
280        # this function uses the discriminator to
281        # pick a new schema/class to instantiate because a discriminator
282        # propertyName value was passed in
283
284        if len(args) == 1:
285            arg = args[0]
286            if arg is None and is_type_nullable(cls):
287                # The input data is the 'null' value and the type is nullable.
288                return None
289
290            if issubclass(cls, ModelComposed) and allows_single_value_input(cls):
291                model_kwargs = {}
292                oneof_instance = get_oneof_instance(cls, model_kwargs, kwargs, model_arg=arg)
293                return oneof_instance
294
295        visited_composed_classes = kwargs.get("_visited_composed_classes", ())
296        if cls.discriminator is None or cls in visited_composed_classes:
297            # Use case 1: this openapi schema (cls) does not have a discriminator
298            # Use case 2: we have already visited this class before and are sure that we
299            # want to instantiate it this time. We have visited this class deserializing
300            # a payload with a discriminator. During that process we traveled through
301            # this class but did not make an instance of it. Now we are making an
302            # instance of a composed class which contains cls in it, so this time make an instance of cls.
303            #
304            # Here's an example of use case 2: If Animal has a discriminator
305            # petType and we pass in "Dog", and the class Dog
306            # allOf includes Animal, we move through Animal
307            # once using the discriminator, and pick Dog.
308            # Then in the composed schema dog Dog, we will make an instance of the
309            # Animal class (because Dal has allOf: Animal) but this time we won't travel
310            # through Animal's discriminator because we passed in
311            # _visited_composed_classes = (Animal,)
312
313            return cls._from_openapi_data(*args, **kwargs)
314
315        # Get the name and value of the discriminator property.
316        # The discriminator name is obtained from the discriminator meta-data
317        # and the discriminator value is obtained from the input data.
318        discr_propertyname_py = list(cls.discriminator.keys())[0]
319        discr_propertyname_js = cls.attribute_map[discr_propertyname_py]
320        if discr_propertyname_js in kwargs:
321            discr_value = kwargs[discr_propertyname_js]
322        elif discr_propertyname_py in kwargs:
323            discr_value = kwargs[discr_propertyname_py]
324        else:
325            # The input data does not contain the discriminator property.
326            path_to_item = kwargs.get("_path_to_item", ())
327            raise ApiValueError(
328                "Cannot deserialize input data due to missing discriminator. "
329                "The discriminator property '%s' is missing at path: %s" % (discr_propertyname_js, path_to_item)
330            )
331
332        # Implementation note: the last argument to get_discriminator_class
333        # is a list of visited classes. get_discriminator_class may recursively
334        # call itself and update the list of visited classes, and the initial
335        # value must be an empty list. Hence not using 'visited_composed_classes'
336        new_cls = get_discriminator_class(cls, discr_propertyname_py, discr_value, [])
337        if new_cls is None:
338            path_to_item = kwargs.get("_path_to_item", ())
339            disc_prop_value = kwargs.get(discr_propertyname_js, kwargs.get(discr_propertyname_py))
340            raise ApiValueError(
341                "Cannot deserialize input data due to invalid discriminator "
342                "value. The OpenAPI document has no mapping for discriminator "
343                "property '%s'='%s' at path: %s" % (discr_propertyname_js, disc_prop_value, path_to_item)
344            )
345
346        if new_cls in visited_composed_classes:
347            # if we are making an instance of a composed schema Descendent
348            # which allOf includes Ancestor, then Ancestor contains
349            # a discriminator that includes Descendent.
350            # So if we make an instance of Descendent, we have to make an
351            # instance of Ancestor to hold the allOf properties.
352            # This code detects that use case and makes the instance of Ancestor
353            # For example:
354            # When making an instance of Dog, _visited_composed_classes = (Dog,)
355            # then we make an instance of Animal to include in dog._composed_instances
356            # so when we are here, cls is Animal
357            # cls.discriminator != None
358            # cls not in _visited_composed_classes
359            # new_cls = Dog
360            # but we know we know that we already have Dog
361            # because it is in visited_composed_classes
362            # so make Animal here
363            return cls._from_openapi_data(*args, **kwargs)
364
365        # Build a list containing all oneOf and anyOf descendants.
366        oneof_anyof_classes = None
367        if cls._composed_schemas is not None:
368            oneof_anyof_classes = cls._composed_schemas.get("oneOf", ()) + cls._composed_schemas.get("anyOf", ())
369        oneof_anyof_child = new_cls in oneof_anyof_classes
370        kwargs["_visited_composed_classes"] = visited_composed_classes + (cls,)
371
372        if cls._composed_schemas.get("allOf") and oneof_anyof_child:
373            # Validate that we can make self because when we make the
374            # new_cls it will not include the allOf validations in self
375            self_inst = cls._from_openapi_data(*args, **kwargs)
376
377        new_inst = new_cls._new_from_openapi_data(*args, **kwargs)
378        return new_inst

The base class for all OpenAPIModels

def set_attribute(self, name, value):
124    def set_attribute(self, name, value):
125        # this is only used to set properties on self
126
127        path_to_item = []
128        if self._path_to_item:
129            path_to_item.extend(self._path_to_item)
130        path_to_item.append(name)
131
132        if name in self.openapi_types:
133            required_types_mixed = self.openapi_types[name]
134        elif self.additional_properties_type is None:
135            raise ApiAttributeError("{0} has no attribute '{1}'".format(type(self).__name__, name), path_to_item)
136        elif self.additional_properties_type is not None:
137            required_types_mixed = self.additional_properties_type
138
139        if get_simple_class(name) != str:
140            error_msg = type_error_message(var_name=name, var_value=name, valid_classes=(str,), key_type=True)
141            raise ApiTypeError(error_msg, path_to_item=path_to_item, valid_classes=(str,), key_type=True)
142
143        if self._check_type:
144            value = validate_and_convert_types(
145                value,
146                required_types_mixed,
147                path_to_item,
148                self._spec_property_naming,
149                self._check_type,
150                configuration=self._configuration,
151            )
152        if (name,) in self.allowed_values:
153            check_allowed_values(self.allowed_values, (name,), value)
154        if (name,) in self.validations:
155            check_validations(self.validations, (name,), value, self._configuration)
156        self.__dict__["_data_store"][name] = value
class ModelSimple(OpenApiModel):
381class ModelSimple(OpenApiModel):
382    """the parent class of models whose type != object in their
383    swagger/openapi"""
384
385    def __setitem__(self, name, value):
386        """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
387        if name in self.required_properties:
388            self.__dict__[name] = value
389            return
390
391        self.set_attribute(name, value)
392
393    def get(self, name, default=None):
394        """returns the value of an attribute or some default value if the attribute was not set"""
395        if name in self.required_properties:
396            return self.__dict__[name]
397
398        return self.__dict__["_data_store"].get(name, default)
399
400    def __getitem__(self, name):
401        """get the value of an attribute using square-bracket notation: `instance[attr]`"""
402        if name in self:
403            return self.get(name)
404
405        raise ApiAttributeError(
406            "{0} has no attribute '{1}'".format(type(self).__name__, name), [e for e in [self._path_to_item, name] if e]
407        )
408
409    def __contains__(self, name):
410        """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
411        if name in self.required_properties:
412            return name in self.__dict__
413
414        return name in self.__dict__["_data_store"]
415
416    def to_str(self):
417        """Returns the string representation of the model"""
418        return str(self.value)
419
420    def __eq__(self, other):
421        """Returns true if both objects are equal"""
422        if not isinstance(other, self.__class__):
423            return False
424
425        this_val = self._data_store["value"]
426        that_val = other._data_store["value"]
427        types = set()
428        types.add(this_val.__class__)
429        types.add(that_val.__class__)
430        vals_equal = this_val == that_val
431        return vals_equal

the parent class of models whose type != object in their swagger/openapi

def get(self, name, default=None):
393    def get(self, name, default=None):
394        """returns the value of an attribute or some default value if the attribute was not set"""
395        if name in self.required_properties:
396            return self.__dict__[name]
397
398        return self.__dict__["_data_store"].get(name, default)

returns the value of an attribute or some default value if the attribute was not set

def to_str(self):
416    def to_str(self):
417        """Returns the string representation of the model"""
418        return str(self.value)

Returns the string representation of the model

Inherited Members
OpenApiModel
set_attribute
class ModelNormal(OpenApiModel):
434class ModelNormal(OpenApiModel):
435    """the parent class of models whose type == object in their
436    swagger/openapi"""
437
438    def __setitem__(self, name, value):
439        """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
440        if name in self.required_properties:
441            self.__dict__[name] = value
442            return
443
444        self.set_attribute(name, value)
445
446    def get(self, name, default=None):
447        """returns the value of an attribute or some default value if the attribute was not set"""
448        if name in self.required_properties:
449            return self.__dict__[name]
450
451        return self.__dict__["_data_store"].get(name, default)
452
453    def __getitem__(self, name):
454        """get the value of an attribute using square-bracket notation: `instance[attr]`"""
455        if name in self:
456            return self.get(name)
457
458        raise ApiAttributeError(
459            "{0} has no attribute '{1}'".format(type(self).__name__, name), [e for e in [self._path_to_item, name] if e]
460        )
461
462    def __contains__(self, name):
463        """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
464        if name in self.required_properties:
465            return name in self.__dict__
466
467        return name in self.__dict__["_data_store"]
468
469    def to_dict(self):
470        """Returns the model properties as a dict"""
471        return model_to_dict(self, serialize=False)
472
473    def to_str(self):
474        """Returns the string representation of the model"""
475        return pprint.pformat(self.to_dict())
476
477    def __eq__(self, other):
478        """Returns true if both objects are equal"""
479        if not isinstance(other, self.__class__):
480            return False
481
482        if not set(self._data_store.keys()) == set(other._data_store.keys()):
483            return False
484        for _var_name, this_val in self._data_store.items():
485            that_val = other._data_store[_var_name]
486            types = set()
487            types.add(this_val.__class__)
488            types.add(that_val.__class__)
489            vals_equal = this_val == that_val
490            if not vals_equal:
491                return False
492        return True

the parent class of models whose type == object in their swagger/openapi

def get(self, name, default=None):
446    def get(self, name, default=None):
447        """returns the value of an attribute or some default value if the attribute was not set"""
448        if name in self.required_properties:
449            return self.__dict__[name]
450
451        return self.__dict__["_data_store"].get(name, default)

returns the value of an attribute or some default value if the attribute was not set

def to_dict(self):
469    def to_dict(self):
470        """Returns the model properties as a dict"""
471        return model_to_dict(self, serialize=False)

Returns the model properties as a dict

def to_str(self):
473    def to_str(self):
474        """Returns the string representation of the model"""
475        return pprint.pformat(self.to_dict())

Returns the string representation of the model

Inherited Members
OpenApiModel
set_attribute
class ModelComposed(OpenApiModel):
495class ModelComposed(OpenApiModel):
496    """the parent class of models whose type == object in their
497    swagger/openapi and have oneOf/allOf/anyOf
498
499    When one sets a property we use var_name_to_model_instances to store the value in
500    the correct class instances + run any type checking + validation code.
501    When one gets a property we use var_name_to_model_instances to get the value
502    from the correct class instances.
503    This allows multiple composed schemas to contain the same property with additive
504    constraints on the value.
505
506    _composed_schemas (dict) stores the anyOf/allOf/oneOf classes
507    key (str): allOf/oneOf/anyOf
508    value (list): the classes in the XOf definition.
509        Note: none_type can be included when the openapi document version >= 3.1.0
510    _composed_instances (list): stores a list of instances of the composed schemas
511    defined in _composed_schemas. When properties are accessed in the self instance,
512    they are returned from the self._data_store or the data stores in the instances
513    in self._composed_schemas
514    _var_name_to_model_instances (dict): maps between a variable name on self and
515    the composed instances (self included) which contain that data
516    key (str): property name
517    value (list): list of class instances, self or instances in _composed_instances
518    which contain the value that the key is referring to.
519    """
520
521    def __setitem__(self, name, value):
522        """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
523        if name in self.required_properties:
524            self.__dict__[name] = value
525            return
526
527        """
528        Use cases:
529        1. additional_properties_type is None (additionalProperties == False in spec)
530            Check for property presence in self.openapi_types
531            if not present then throw an error
532            if present set in self, set attribute
533            always set on composed schemas
534        2.  additional_properties_type exists
535            set attribute on self
536            always set on composed schemas
537        """
538        if self.additional_properties_type is None:
539            """
540            For an attribute to exist on a composed schema it must:
541            - fulfill schema_requirements in the self composed schema not considering oneOf/anyOf/allOf schemas AND
542            - fulfill schema_requirements in each oneOf/anyOf/allOf schemas
543
544            schema_requirements:
545            For an attribute to exist on a schema it must:
546            - be present in properties at the schema OR
547            - have additionalProperties unset (defaults additionalProperties = any type) OR
548            - have additionalProperties set
549            """
550            if name not in self.openapi_types:
551                raise ApiAttributeError(
552                    "{0} has no attribute '{1}'".format(type(self).__name__, name),
553                    [e for e in [self._path_to_item, name] if e],
554                )
555        # attribute must be set on self and composed instances
556        self.set_attribute(name, value)
557        for model_instance in self._composed_instances:
558            setattr(model_instance, name, value)
559        if name not in self._var_name_to_model_instances:
560            # we assigned an additional property
561            self.__dict__["_var_name_to_model_instances"][name] = self._composed_instances + [self]
562        return None
563
564    __unset_attribute_value__ = object()
565
566    def get(self, name, default=None):
567        """returns the value of an attribute or some default value if the attribute was not set"""
568        if name in self.required_properties:
569            return self.__dict__[name]
570
571        # get the attribute from the correct instance
572        model_instances = self._var_name_to_model_instances.get(name)
573        values = []
574        # A composed model stores self and child (oneof/anyOf/allOf) models under
575        # self._var_name_to_model_instances.
576        # Any property must exist in self and all model instances
577        # The value stored in all model instances must be the same
578        if model_instances:
579            for model_instance in model_instances:
580                if name in model_instance._data_store:
581                    v = model_instance._data_store[name]
582                    if v not in values:
583                        values.append(v)
584        len_values = len(values)
585        if len_values == 0:
586            return default
587        elif len_values == 1:
588            return values[0]
589        elif len_values > 1:
590            raise ApiValueError(
591                "Values stored for property {0} in {1} differ when looking "
592                "at self and self's composed instances. All values must be "
593                "the same".format(name, type(self).__name__),
594                [e for e in [self._path_to_item, name] if e],
595            )
596
597    def __getitem__(self, name):
598        """get the value of an attribute using square-bracket notation: `instance[attr]`"""
599        value = self.get(name, self.__unset_attribute_value__)
600        if value is self.__unset_attribute_value__:
601            raise ApiAttributeError(
602                "{0} has no attribute '{1}'".format(type(self).__name__, name),
603                [e for e in [self._path_to_item, name] if e],
604            )
605        return value
606
607    def __contains__(self, name):
608        """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
609
610        if name in self.required_properties:
611            return name in self.__dict__
612
613        model_instances = self._var_name_to_model_instances.get(name, self._additional_properties_model_instances)
614
615        if model_instances:
616            for model_instance in model_instances:
617                if name in model_instance._data_store:
618                    return True
619
620        return False
621
622    def to_dict(self):
623        """Returns the model properties as a dict"""
624        return model_to_dict(self, serialize=False)
625
626    def to_str(self):
627        """Returns the string representation of the model"""
628        return pprint.pformat(self.to_dict())
629
630    def __eq__(self, other):
631        """Returns true if both objects are equal"""
632        if not isinstance(other, self.__class__):
633            return False
634
635        if not set(self._data_store.keys()) == set(other._data_store.keys()):
636            return False
637        for _var_name, this_val in self._data_store.items():
638            that_val = other._data_store[_var_name]
639            types = set()
640            types.add(this_val.__class__)
641            types.add(that_val.__class__)
642            vals_equal = this_val == that_val
643            if not vals_equal:
644                return False
645        return True

the parent class of models whose type == object in their swagger/openapi and have oneOf/allOf/anyOf

When one sets a property we use var_name_to_model_instances to store the value in the correct class instances + run any type checking + validation code. When one gets a property we use var_name_to_model_instances to get the value from the correct class instances. This allows multiple composed schemas to contain the same property with additive constraints on the value.

_composed_schemas (dict) stores the anyOf/allOf/oneOf classes key (str): allOf/oneOf/anyOf value (list): the classes in the XOf definition. Note: none_type can be included when the openapi document version >= 3.1.0 _composed_instances (list): stores a list of instances of the composed schemas defined in _composed_schemas. When properties are accessed in the self instance, they are returned from the self._data_store or the data stores in the instances in self._composed_schemas _var_name_to_model_instances (dict): maps between a variable name on self and the composed instances (self included) which contain that data key (str): property name value (list): list of class instances, self or instances in _composed_instances which contain the value that the key is referring to.

def get(self, name, default=None):
566    def get(self, name, default=None):
567        """returns the value of an attribute or some default value if the attribute was not set"""
568        if name in self.required_properties:
569            return self.__dict__[name]
570
571        # get the attribute from the correct instance
572        model_instances = self._var_name_to_model_instances.get(name)
573        values = []
574        # A composed model stores self and child (oneof/anyOf/allOf) models under
575        # self._var_name_to_model_instances.
576        # Any property must exist in self and all model instances
577        # The value stored in all model instances must be the same
578        if model_instances:
579            for model_instance in model_instances:
580                if name in model_instance._data_store:
581                    v = model_instance._data_store[name]
582                    if v not in values:
583                        values.append(v)
584        len_values = len(values)
585        if len_values == 0:
586            return default
587        elif len_values == 1:
588            return values[0]
589        elif len_values > 1:
590            raise ApiValueError(
591                "Values stored for property {0} in {1} differ when looking "
592                "at self and self's composed instances. All values must be "
593                "the same".format(name, type(self).__name__),
594                [e for e in [self._path_to_item, name] if e],
595            )

returns the value of an attribute or some default value if the attribute was not set

def to_dict(self):
622    def to_dict(self):
623        """Returns the model properties as a dict"""
624        return model_to_dict(self, serialize=False)

Returns the model properties as a dict

def to_str(self):
626    def to_str(self):
627        """Returns the string representation of the model"""
628        return pprint.pformat(self.to_dict())

Returns the string representation of the model

Inherited Members
OpenApiModel
set_attribute
COERCION_INDEX_BY_TYPE = {<class 'ModelComposed'>: 0, <class 'ModelNormal'>: 1, <class 'ModelSimple'>: 2, <class 'NoneType'>: 3, <class 'list'>: 4, <class 'dict'>: 5, <class 'float'>: 6, <class 'int'>: 7, <class 'bool'>: 8, <class 'datetime.datetime'>: 9, <class 'datetime.date'>: 10, <class 'str'>: 11, <class 'io.IOBase'>: 12}
UPCONVERSION_TYPE_PAIRS = ((<class 'str'>, <class 'datetime.datetime'>), (<class 'str'>, <class 'datetime.date'>), (<class 'int'>, <class 'float'>), (<class 'list'>, <class 'ModelComposed'>), (<class 'dict'>, <class 'ModelComposed'>), (<class 'str'>, <class 'ModelComposed'>), (<class 'int'>, <class 'ModelComposed'>), (<class 'float'>, <class 'ModelComposed'>), (<class 'list'>, <class 'ModelComposed'>), (<class 'list'>, <class 'ModelNormal'>), (<class 'dict'>, <class 'ModelNormal'>), (<class 'str'>, <class 'ModelSimple'>), (<class 'int'>, <class 'ModelSimple'>), (<class 'float'>, <class 'ModelSimple'>), (<class 'list'>, <class 'ModelSimple'>))
COERCIBLE_TYPE_PAIRS = {False: (), True: ((<class 'dict'>, <class 'ModelComposed'>), (<class 'list'>, <class 'ModelComposed'>), (<class 'dict'>, <class 'ModelNormal'>), (<class 'list'>, <class 'ModelNormal'>), (<class 'str'>, <class 'ModelSimple'>), (<class 'int'>, <class 'ModelSimple'>), (<class 'float'>, <class 'ModelSimple'>), (<class 'list'>, <class 'ModelSimple'>), (<class 'str'>, <class 'datetime.datetime'>), (<class 'str'>, <class 'datetime.date'>), (<class 'str'>, <class 'io.IOBase'>))}
def get_simple_class(input_value):
722def get_simple_class(input_value):
723    """Returns an input_value's simple class that we will use for type checking
724    Python2:
725    float and int will return int, where int is the python3 int backport
726    str and unicode will return str, where str is the python3 str backport
727    Note: float and int ARE both instances of int backport
728    Note: str_py2 and unicode_py2 are NOT both instances of str backport
729
730    Args:
731        input_value (class/class_instance): the item for which we will return
732                                            the simple class
733    """
734    if isinstance(input_value, type):
735        # input_value is a class
736        return input_value
737    elif isinstance(input_value, tuple):
738        return tuple
739    elif isinstance(input_value, list):
740        return list
741    elif isinstance(input_value, dict):
742        return dict
743    elif isinstance(input_value, none_type):
744        return none_type
745    elif isinstance(input_value, file_type):
746        return file_type
747    elif isinstance(input_value, bool):
748        # this must be higher than the int check because
749        # isinstance(True, int) == True
750        return bool
751    elif isinstance(input_value, int):
752        return int
753    elif isinstance(input_value, datetime):
754        # this must be higher than the date check because
755        # isinstance(datetime_instance, date) == True
756        return datetime
757    elif isinstance(input_value, date):
758        return date
759    elif isinstance(input_value, str):
760        return str
761    return type(input_value)

Returns an input_value's simple class that we will use for type checking Python2: float and int will return int, where int is the python3 int backport str and unicode will return str, where str is the python3 str backport Note: float and int ARE both instances of int backport Note: str_py2 and unicode_py2 are NOT both instances of str backport

Arguments:
  • input_value (class/class_instance): the item for which we will return the simple class
def check_allowed_values(allowed_values, input_variable_path, input_values):
764def check_allowed_values(allowed_values, input_variable_path, input_values):
765    """Raises an exception if the input_values are not allowed
766
767    Args:
768        allowed_values (dict): the allowed_values dict
769        input_variable_path (tuple): the path to the input variable
770        input_values (list/str/int/float/date/datetime): the values that we
771            are checking to see if they are in allowed_values
772    """
773    these_allowed_values = list(allowed_values[input_variable_path].values())
774    if isinstance(input_values, list) and not set(input_values).issubset(set(these_allowed_values)):
775        invalid_values = (", ".join(map(str, set(input_values) - set(these_allowed_values))),)
776        raise ApiValueError(
777            "Invalid values for `%s` [%s], must be a subset of [%s]"
778            % (input_variable_path[0], invalid_values, ", ".join(map(str, these_allowed_values)))
779        )
780    elif isinstance(input_values, dict) and not set(input_values.keys()).issubset(set(these_allowed_values)):
781        invalid_values = ", ".join(map(str, set(input_values.keys()) - set(these_allowed_values)))
782        raise ApiValueError(
783            "Invalid keys in `%s` [%s], must be a subset of [%s]"
784            % (input_variable_path[0], invalid_values, ", ".join(map(str, these_allowed_values)))
785        )
786    elif not isinstance(input_values, (list, dict)) and input_values not in these_allowed_values:
787        raise ApiValueError(
788            "Invalid value for `%s` (%s), must be one of %s"
789            % (input_variable_path[0], input_values, these_allowed_values)
790        )

Raises an exception if the input_values are not allowed

Arguments:
  • allowed_values (dict): the allowed_values dict
  • input_variable_path (tuple): the path to the input variable
  • input_values (list/str/int/float/date/datetime): the values that we are checking to see if they are in allowed_values
def is_json_validation_enabled(schema_keyword, configuration=None):
793def is_json_validation_enabled(schema_keyword, configuration=None):
794    """Returns true if JSON schema validation is enabled for the specified
795    validation keyword. This can be used to skip JSON schema structural validation
796    as requested in the configuration.
797
798    Args:
799        schema_keyword (string): the name of a JSON schema validation keyword.
800        configuration (Configuration): the configuration class.
801    """
802
803    return (
804        configuration is None
805        or not hasattr(configuration, "_disabled_client_side_validations")
806        or schema_keyword not in configuration._disabled_client_side_validations
807    )

Returns true if JSON schema validation is enabled for the specified validation keyword. This can be used to skip JSON schema structural validation as requested in the configuration.

Arguments:
  • schema_keyword (string): the name of a JSON schema validation keyword.
  • configuration (Configuration): the configuration class.
def check_validations(validations, input_variable_path, input_values, configuration=None):
810def check_validations(validations, input_variable_path, input_values, configuration=None):
811    """Raises an exception if the input_values are invalid
812
813    Args:
814        validations (dict): the validation dictionary.
815        input_variable_path (tuple): the path to the input variable.
816        input_values (list/str/int/float/date/datetime): the values that we
817            are checking.
818        configuration (Configuration): the configuration class.
819    """
820
821    if input_values is None:
822        return
823
824    current_validations = validations[input_variable_path]
825    if (
826        is_json_validation_enabled("multipleOf", configuration)
827        and "multiple_of" in current_validations
828        and isinstance(input_values, (int, float))
829        and not (float(input_values) / current_validations["multiple_of"]).is_integer()
830    ):
831        # Note 'multipleOf' will be as good as the floating point arithmetic.
832        raise ApiValueError(
833            "Invalid value for `%s`, value must be a multiple of "
834            "`%s`" % (input_variable_path[0], current_validations["multiple_of"])
835        )
836
837    if (
838        is_json_validation_enabled("maxLength", configuration)
839        and "max_length" in current_validations
840        and len(input_values) > current_validations["max_length"]
841    ):
842        raise ApiValueError(
843            "Invalid value for `%s`, length must be less than or equal to "
844            "`%s`" % (input_variable_path[0], current_validations["max_length"])
845        )
846
847    if (
848        is_json_validation_enabled("minLength", configuration)
849        and "min_length" in current_validations
850        and len(input_values) < current_validations["min_length"]
851    ):
852        raise ApiValueError(
853            "Invalid value for `%s`, length must be greater than or equal to "
854            "`%s`" % (input_variable_path[0], current_validations["min_length"])
855        )
856
857    if (
858        is_json_validation_enabled("maxItems", configuration)
859        and "max_items" in current_validations
860        and len(input_values) > current_validations["max_items"]
861    ):
862        raise ApiValueError(
863            "Invalid value for `%s`, number of items must be less than or "
864            "equal to `%s`" % (input_variable_path[0], current_validations["max_items"])
865        )
866
867    if (
868        is_json_validation_enabled("minItems", configuration)
869        and "min_items" in current_validations
870        and len(input_values) < current_validations["min_items"]
871    ):
872        raise ValueError(
873            "Invalid value for `%s`, number of items must be greater than or "
874            "equal to `%s`" % (input_variable_path[0], current_validations["min_items"])
875        )
876
877    items = ("exclusive_maximum", "inclusive_maximum", "exclusive_minimum", "inclusive_minimum")
878    if any(item in current_validations for item in items):
879        if isinstance(input_values, list):
880            max_val = max(input_values)
881            min_val = min(input_values)
882        elif isinstance(input_values, dict):
883            max_val = max(input_values.values())
884            min_val = min(input_values.values())
885        else:
886            max_val = input_values
887            min_val = input_values
888
889    if (
890        is_json_validation_enabled("exclusiveMaximum", configuration)
891        and "exclusive_maximum" in current_validations
892        and max_val >= current_validations["exclusive_maximum"]
893    ):
894        raise ApiValueError(
895            "Invalid value for `%s`, must be a value less than `%s`"
896            % (input_variable_path[0], current_validations["exclusive_maximum"])
897        )
898
899    if (
900        is_json_validation_enabled("maximum", configuration)
901        and "inclusive_maximum" in current_validations
902        and max_val > current_validations["inclusive_maximum"]
903    ):
904        raise ApiValueError(
905            "Invalid value for `%s`, must be a value less than or equal to "
906            "`%s`" % (input_variable_path[0], current_validations["inclusive_maximum"])
907        )
908
909    if (
910        is_json_validation_enabled("exclusiveMinimum", configuration)
911        and "exclusive_minimum" in current_validations
912        and min_val <= current_validations["exclusive_minimum"]
913    ):
914        raise ApiValueError(
915            "Invalid value for `%s`, must be a value greater than `%s`"
916            % (input_variable_path[0], current_validations["exclusive_maximum"])
917        )
918
919    if (
920        is_json_validation_enabled("minimum", configuration)
921        and "inclusive_minimum" in current_validations
922        and min_val < current_validations["inclusive_minimum"]
923    ):
924        raise ApiValueError(
925            "Invalid value for `%s`, must be a value greater than or equal "
926            "to `%s`" % (input_variable_path[0], current_validations["inclusive_minimum"])
927        )
928    flags = current_validations.get("regex", {}).get("flags", 0)
929    if (
930        is_json_validation_enabled("pattern", configuration)
931        and "regex" in current_validations
932        and not re.search(current_validations["regex"]["pattern"], input_values, flags=flags)
933    ):
934        err_msg = r"Invalid value for `%s`, must match regular expression `%s`" % (
935            input_variable_path[0],
936            current_validations["regex"]["pattern"],
937        )
938        if flags != 0:
939            # Don't print the regex flags if the flags are not
940            # specified in the OAS document.
941            err_msg = r"%s with flags=`%s`" % (err_msg, flags)
942        raise ApiValueError(err_msg)

Raises an exception if the input_values are invalid

Arguments:
  • validations (dict): the validation dictionary.
  • input_variable_path (tuple): the path to the input variable.
  • input_values (list/str/int/float/date/datetime): the values that we are checking.
  • configuration (Configuration): the configuration class.
def order_response_types(required_types):
945def order_response_types(required_types):
946    """Returns the required types sorted in coercion order
947
948    Args:
949        required_types (list/tuple): collection of classes or instance of
950            list or dict with class information inside it.
951
952    Returns:
953        (list): coercion order sorted collection of classes or instance
954            of list or dict with class information inside it.
955    """
956
957    def index_getter(class_or_instance):
958        if isinstance(class_or_instance, list):
959            return COERCION_INDEX_BY_TYPE[list]
960        elif isinstance(class_or_instance, dict):
961            return COERCION_INDEX_BY_TYPE[dict]
962        elif inspect.isclass(class_or_instance) and issubclass(class_or_instance, ModelComposed):
963            return COERCION_INDEX_BY_TYPE[ModelComposed]
964        elif inspect.isclass(class_or_instance) and issubclass(class_or_instance, ModelNormal):
965            return COERCION_INDEX_BY_TYPE[ModelNormal]
966        elif inspect.isclass(class_or_instance) and issubclass(class_or_instance, ModelSimple):
967            return COERCION_INDEX_BY_TYPE[ModelSimple]
968        elif class_or_instance in COERCION_INDEX_BY_TYPE:
969            return COERCION_INDEX_BY_TYPE[class_or_instance]
970        raise ApiValueError("Unsupported type: %s" % class_or_instance)
971
972    sorted_types = sorted(required_types, key=lambda class_or_instance: index_getter(class_or_instance))
973    return sorted_types

Returns the required types sorted in coercion order

Arguments:
  • required_types (list/tuple): collection of classes or instance of list or dict with class information inside it.
Returns:

(list): coercion order sorted collection of classes or instance of list or dict with class information inside it.

def remove_uncoercible( required_types_classes, current_item, spec_property_naming, must_convert=True):
 976def remove_uncoercible(required_types_classes, current_item, spec_property_naming, must_convert=True):
 977    """Only keeps the type conversions that are possible
 978
 979    Args:
 980        required_types_classes (tuple): tuple of classes that are required
 981                          these should be ordered by COERCION_INDEX_BY_TYPE
 982        spec_property_naming (bool): True if the variable names in the input
 983            data are serialized names as specified in the OpenAPI document.
 984            False if the variables names in the input data are python
 985            variable names in PEP-8 snake case.
 986        current_item (any): the current item (input data) to be converted
 987
 988    Keyword Args:
 989        must_convert (bool): if True the item to convert is of the wrong
 990                          type and we want a big list of coercibles
 991                          if False, we want a limited list of coercibles
 992
 993    Returns:
 994        (list): the remaining coercible required types, classes only
 995    """
 996    current_type_simple = get_simple_class(current_item)
 997
 998    results_classes = []
 999    for required_type_class in required_types_classes:
1000        # convert our models to OpenApiModel
1001        required_type_class_simplified = required_type_class
1002        if isinstance(required_type_class_simplified, type):
1003            if issubclass(required_type_class_simplified, ModelComposed):
1004                required_type_class_simplified = ModelComposed
1005            elif issubclass(required_type_class_simplified, ModelNormal):
1006                required_type_class_simplified = ModelNormal
1007            elif issubclass(required_type_class_simplified, ModelSimple):
1008                required_type_class_simplified = ModelSimple
1009
1010        if required_type_class_simplified == current_type_simple:
1011            # don't consider converting to one's own class
1012            continue
1013
1014        class_pair = (current_type_simple, required_type_class_simplified)
1015        if must_convert and class_pair in COERCIBLE_TYPE_PAIRS[spec_property_naming]:
1016            results_classes.append(required_type_class)
1017        elif class_pair in UPCONVERSION_TYPE_PAIRS:
1018            results_classes.append(required_type_class)
1019    return results_classes

Only keeps the type conversions that are possible

Arguments:
  • required_types_classes (tuple): tuple of classes that are required these should be ordered by COERCION_INDEX_BY_TYPE
  • spec_property_naming (bool): True if the variable names in the input data are serialized names as specified in the OpenAPI document. False if the variables names in the input data are python variable names in PEP-8 snake case.
  • current_item (any): the current item (input data) to be converted
Keyword Args:

must_convert (bool): if True the item to convert is of the wrong type and we want a big list of coercibles if False, we want a limited list of coercibles

Returns:

(list): the remaining coercible required types, classes only

def get_discriminated_classes(cls):
1022def get_discriminated_classes(cls):
1023    """
1024    Returns all the classes that a discriminator converts to
1025    TODO: lru_cache this
1026    """
1027    possible_classes = []
1028    key = list(cls.discriminator.keys())[0]
1029    if is_type_nullable(cls):
1030        possible_classes.append(cls)
1031    for discr_cls in cls.discriminator[key].values():
1032        if hasattr(discr_cls, "discriminator") and discr_cls.discriminator is not None:
1033            possible_classes.extend(get_discriminated_classes(discr_cls))
1034        else:
1035            possible_classes.append(discr_cls)
1036    return possible_classes

Returns all the classes that a discriminator converts to TODO: lru_cache this

def get_possible_classes(cls, from_server_context):
1039def get_possible_classes(cls, from_server_context):
1040    # TODO: lru_cache this
1041    possible_classes = [cls]
1042    if from_server_context:
1043        return possible_classes
1044    if hasattr(cls, "discriminator") and cls.discriminator is not None:
1045        possible_classes = []
1046        possible_classes.extend(get_discriminated_classes(cls))
1047    elif issubclass(cls, ModelComposed):
1048        possible_classes.extend(composed_model_input_classes(cls))
1049    return possible_classes
def get_required_type_classes(required_types_mixed, spec_property_naming):
1052def get_required_type_classes(required_types_mixed, spec_property_naming):
1053    """Converts the tuple required_types into a tuple and a dict described
1054    below
1055
1056    Args:
1057        required_types_mixed (tuple/list): will contain either classes or
1058            instance of list or dict
1059        spec_property_naming (bool): if True these values came from the
1060            server, and we use the data types in our endpoints.
1061            If False, we are client side and we need to include
1062            oneOf and discriminator classes inside the data types in our endpoints
1063
1064    Returns:
1065        (valid_classes, dict_valid_class_to_child_types_mixed):
1066            valid_classes (tuple): the valid classes that the current item
1067                                   should be
1068            dict_valid_class_to_child_types_mixed (dict):
1069                valid_class (class): this is the key
1070                child_types_mixed (list/dict/tuple): describes the valid child
1071                    types
1072    """
1073    valid_classes = []
1074    child_req_types_by_current_type = {}
1075    for required_type in required_types_mixed:
1076        if isinstance(required_type, list):
1077            valid_classes.append(list)
1078            child_req_types_by_current_type[list] = required_type
1079        elif isinstance(required_type, tuple):
1080            valid_classes.append(tuple)
1081            child_req_types_by_current_type[tuple] = required_type
1082        elif isinstance(required_type, dict):
1083            valid_classes.append(dict)
1084            child_req_types_by_current_type[dict] = required_type[str]
1085        else:
1086            valid_classes.extend(get_possible_classes(required_type, spec_property_naming))
1087    return tuple(valid_classes), child_req_types_by_current_type

Converts the tuple required_types into a tuple and a dict described below

Arguments:
  • required_types_mixed (tuple/list): will contain either classes or instance of list or dict
  • spec_property_naming (bool): if True these values came from the server, and we use the data types in our endpoints. If False, we are client side and we need to include oneOf and discriminator classes inside the data types in our endpoints
Returns:

(valid_classes, dict_valid_class_to_child_types_mixed): valid_classes (tuple): the valid classes that the current item should be dict_valid_class_to_child_types_mixed (dict): valid_class (class): this is the key child_types_mixed (list/dict/tuple): describes the valid child types

def change_keys_js_to_python(input_dict, model_class):
1090def change_keys_js_to_python(input_dict, model_class):
1091    """
1092    Converts from javascript_key keys in the input_dict to python_keys in
1093    the output dict using the mapping in model_class.
1094    If the input_dict contains a key which does not declared in the model_class,
1095    the key is added to the output dict as is. The assumption is the model_class
1096    may have undeclared properties (additionalProperties attribute in the OAS
1097    document).
1098    """
1099
1100    if getattr(model_class, "attribute_map", None) is None:
1101        return input_dict
1102    output_dict = {}
1103    reversed_attr_map = {value: key for key, value in model_class.attribute_map.items()}
1104    for javascript_key, value in input_dict.items():
1105        python_key = reversed_attr_map.get(javascript_key)
1106        if python_key is None:
1107            # if the key is unknown, it is in error or it is an
1108            # additionalProperties variable
1109            python_key = javascript_key
1110        output_dict[python_key] = value
1111    return output_dict

Converts from javascript_key keys in the input_dict to python_keys in the output dict using the mapping in model_class. If the input_dict contains a key which does not declared in the model_class, the key is added to the output dict as is. The assumption is the model_class may have undeclared properties (additionalProperties attribute in the OAS document).

def get_type_error(var_value, path_to_item, valid_classes, key_type=False):
1114def get_type_error(var_value, path_to_item, valid_classes, key_type=False):
1115    error_msg = type_error_message(
1116        var_name=path_to_item[-1], var_value=var_value, valid_classes=valid_classes, key_type=key_type
1117    )
1118    return ApiTypeError(error_msg, path_to_item=path_to_item, valid_classes=valid_classes, key_type=key_type)
def deserialize_primitive(data, klass, path_to_item):
1121def deserialize_primitive(data, klass, path_to_item):
1122    """Deserializes string to primitive type.
1123
1124    :param data: str/int/float
1125    :param klass: str/class the class to convert to
1126
1127    :return: int, float, str, bool, date, datetime
1128    """
1129    additional_message = ""
1130    try:
1131        if klass in {datetime, date}:
1132            additional_message = (
1133                "If you need your parameter to have a fallback "
1134                "string value, please set its type as `type: {}` in your "
1135                "spec. That allows the value to be any type. "
1136            )
1137            if klass == datetime:
1138                if len(data) < 8:
1139                    raise ValueError("This is not a datetime")
1140                # The string should be in iso8601 datetime format.
1141                parsed_datetime = parse(data)
1142                date_only = (
1143                    parsed_datetime.hour == 0
1144                    and parsed_datetime.minute == 0
1145                    and parsed_datetime.second == 0
1146                    and parsed_datetime.tzinfo is None
1147                    and 8 <= len(data) <= 10
1148                )
1149                if date_only:
1150                    raise ValueError("This is a date, not a datetime")
1151                return parsed_datetime
1152            elif klass == date:
1153                if len(data) < 8:
1154                    raise ValueError("This is not a date")
1155                return parse(data).date()
1156        else:
1157            converted_value = klass(data)
1158            if isinstance(data, str) and klass == float:
1159                if str(converted_value) != data:
1160                    # '7' -> 7.0 -> '7.0' != '7'
1161                    raise ValueError("This is not a float")
1162            return converted_value
1163    except (OverflowError, ValueError) as ex:
1164        # parse can raise OverflowError
1165        raise ApiValueError(
1166            "{0}Failed to parse {1} as {2}".format(additional_message, repr(data), klass.__name__),
1167            path_to_item=path_to_item,
1168        ) from ex

Deserializes string to primitive type.

Parameters
  • data: str/int/float
  • klass: str/class the class to convert to
Returns

int, float, str, bool, date, datetime

def get_discriminator_class(model_class, discr_name, discr_value, cls_visited):
1171def get_discriminator_class(model_class, discr_name, discr_value, cls_visited):
1172    """Returns the child class specified by the discriminator.
1173
1174    Args:
1175        model_class (OpenApiModel): the model class.
1176        discr_name (string): the name of the discriminator property.
1177        discr_value (any): the discriminator value.
1178        cls_visited (list): list of model classes that have been visited.
1179            Used to determine the discriminator class without
1180            visiting circular references indefinitely.
1181
1182    Returns:
1183        used_model_class (class/None): the chosen child class that will be used
1184            to deserialize the data, for example dog.Dog.
1185            If a class is not found, None is returned.
1186    """
1187
1188    if model_class in cls_visited:
1189        # The class has already been visited and no suitable class was found.
1190        return None
1191    cls_visited.append(model_class)
1192    used_model_class = None
1193    if discr_name in model_class.discriminator:
1194        class_name_to_discr_class = model_class.discriminator[discr_name]
1195        used_model_class = class_name_to_discr_class.get(discr_value)
1196    if used_model_class is None:
1197        # We didn't find a discriminated class in class_name_to_discr_class.
1198        # So look in the ancestor or descendant discriminators
1199        # The discriminator mapping may exist in a descendant (anyOf, oneOf)
1200        # or ancestor (allOf).
1201        # Ancestor example: in the GrandparentAnimal -> ParentPet -> ChildCat
1202        #   hierarchy, the discriminator mappings may be defined at any level
1203        #   in the hierarchy.
1204        # Descendant example:  mammal -> whale/zebra/Pig -> BasquePig/DanishPig
1205        #   if we try to make BasquePig from mammal, we need to travel through
1206        #   the oneOf descendant discriminators to find BasquePig
1207        descendant_classes = model_class._composed_schemas.get("oneOf", ()) + model_class._composed_schemas.get(
1208            "anyOf", ()
1209        )
1210        ancestor_classes = model_class._composed_schemas.get("allOf", ())
1211        possible_classes = descendant_classes + ancestor_classes
1212        for cls in possible_classes:
1213            # Check if the schema has inherited discriminators.
1214            if hasattr(cls, "discriminator") and cls.discriminator is not None:
1215                used_model_class = get_discriminator_class(cls, discr_name, discr_value, cls_visited)
1216                if used_model_class is not None:
1217                    return used_model_class
1218    return used_model_class

Returns the child class specified by the discriminator.

Arguments:
  • model_class (OpenApiModel): the model class.
  • discr_name (string): the name of the discriminator property.
  • discr_value (any): the discriminator value.
  • cls_visited (list): list of model classes that have been visited. Used to determine the discriminator class without visiting circular references indefinitely.
Returns:

used_model_class (class/None): the chosen child class that will be used to deserialize the data, for example dog.Dog. If a class is not found, None is returned.

def deserialize_model( model_data, model_class, path_to_item, check_type, configuration, spec_property_naming):
1221def deserialize_model(model_data, model_class, path_to_item, check_type, configuration, spec_property_naming):
1222    """Deserializes model_data to model instance.
1223
1224    Args:
1225        model_data (int/str/float/bool/none_type/list/dict): data to instantiate the model
1226        model_class (OpenApiModel): the model class
1227        path_to_item (list): path to the model in the received data
1228        check_type (bool): whether to check the data tupe for the values in
1229            the model
1230        configuration (Configuration): the instance to use to convert files
1231        spec_property_naming (bool): True if the variable names in the input
1232            data are serialized names as specified in the OpenAPI document.
1233            False if the variables names in the input data are python
1234            variable names in PEP-8 snake case.
1235
1236    Returns:
1237        model instance
1238
1239    Raise:
1240        ApiTypeError
1241        ApiValueError
1242        ApiKeyError
1243    """
1244
1245    kw_args = dict(
1246        _check_type=check_type,
1247        _path_to_item=path_to_item,
1248        _configuration=configuration,
1249        _spec_property_naming=spec_property_naming,
1250    )
1251
1252    if issubclass(model_class, ModelSimple):
1253        return model_class._new_from_openapi_data(model_data, **kw_args)
1254    elif isinstance(model_data, list):
1255        return model_class._new_from_openapi_data(*model_data, **kw_args)
1256    if isinstance(model_data, dict):
1257        kw_args.update(model_data)
1258        return model_class._new_from_openapi_data(**kw_args)
1259    elif isinstance(model_data, PRIMITIVE_TYPES):
1260        return model_class._new_from_openapi_data(model_data, **kw_args)

Deserializes model_data to model instance.

Arguments:
  • model_data (int/str/float/bool/none_type/list/dict): data to instantiate the model
  • model_class (OpenApiModel): the model class
  • path_to_item (list): path to the model in the received data
  • check_type (bool): whether to check the data tupe for the values in the model
  • configuration (Configuration): the instance to use to convert files
  • spec_property_naming (bool): True if the variable names in the input data are serialized names as specified in the OpenAPI document. False if the variables names in the input data are python variable names in PEP-8 snake case.
Returns:

model instance

Raise:

ApiTypeError ApiValueError ApiKeyError

def deserialize_file(response_data, configuration, content_disposition=None):
1263def deserialize_file(response_data, configuration, content_disposition=None):
1264    """Deserializes body to file
1265
1266    Saves response body into a file in a temporary folder,
1267    using the filename from the `Content-Disposition` header if provided.
1268
1269    Args:
1270        param response_data (str):  the file data to write
1271        configuration (Configuration): the instance to use to convert files
1272
1273    Keyword Args:
1274        content_disposition (str):  the value of the Content-Disposition
1275            header
1276
1277    Returns:
1278        (file_type): the deserialized file which is open
1279            The user is responsible for closing and reading the file
1280    """
1281    fd, path = tempfile.mkstemp(dir=configuration.temp_folder_path)
1282    os.close(fd)
1283    os.remove(path)
1284
1285    if content_disposition:
1286        filename = re.search(r'filename=[\'"]?([^\'"\s]+)[\'"]?', content_disposition).group(1)
1287        path = os.path.join(os.path.dirname(path), filename)
1288
1289    with open(path, "wb") as f:
1290        if isinstance(response_data, str):
1291            # change str to bytes so we can write it
1292            response_data = response_data.encode("utf-8")
1293        f.write(response_data)
1294
1295    f = open(path, "rb")
1296    return f

Deserializes body to file

Saves response body into a file in a temporary folder, using the filename from the Content-Disposition header if provided.

Arguments:
  • param response_data (str): the file data to write
  • configuration (Configuration): the instance to use to convert files
Keyword Args:

content_disposition (str): the value of the Content-Disposition header

Returns:

(file_type): the deserialized file which is open The user is responsible for closing and reading the file

def attempt_convert_item( input_value, valid_classes, path_to_item, configuration, spec_property_naming, key_type=False, must_convert=False, check_type=True):
1299def attempt_convert_item(
1300    input_value,
1301    valid_classes,
1302    path_to_item,
1303    configuration,
1304    spec_property_naming,
1305    key_type=False,
1306    must_convert=False,
1307    check_type=True,
1308):
1309    """
1310    Args:
1311        input_value (any): the data to convert
1312        valid_classes (any): the classes that are valid
1313        path_to_item (list): the path to the item to convert
1314        configuration (Configuration): the instance to use to convert files
1315        spec_property_naming (bool): True if the variable names in the input
1316            data are serialized names as specified in the OpenAPI document.
1317            False if the variables names in the input data are python
1318            variable names in PEP-8 snake case.
1319        key_type (bool): if True we need to convert a key type (not supported)
1320        must_convert (bool): if True we must convert
1321        check_type (bool): if True we check the type or the returned data in
1322            ModelComposed/ModelNormal/ModelSimple instances
1323
1324    Returns:
1325        instance (any) the fixed item
1326
1327    Raises:
1328        ApiTypeError
1329        ApiValueError
1330        ApiKeyError
1331    """
1332    valid_classes_ordered = order_response_types(valid_classes)
1333    valid_classes_coercible = remove_uncoercible(valid_classes_ordered, input_value, spec_property_naming)
1334    if not valid_classes_coercible or key_type:
1335        # we do not handle keytype errors, json will take care
1336        # of this for us
1337        if configuration is None or not configuration.discard_unknown_keys:
1338            raise get_type_error(input_value, path_to_item, valid_classes, key_type=key_type)
1339    for valid_class in valid_classes_coercible:
1340        try:
1341            if issubclass(valid_class, OpenApiModel):
1342                return deserialize_model(
1343                    input_value, valid_class, path_to_item, check_type, configuration, spec_property_naming
1344                )
1345            elif valid_class == file_type:
1346                return deserialize_file(input_value, configuration)
1347            return deserialize_primitive(input_value, valid_class, path_to_item)
1348        except (ApiTypeError, ApiValueError, ApiKeyError) as conversion_exc:
1349            if must_convert:
1350                raise conversion_exc
1351            # if we have conversion errors when must_convert == False
1352            # we ignore the exception and move on to the next class
1353            continue
1354    # we were unable to convert, must_convert == False
1355    return input_value
Arguments:
  • input_value (any): the data to convert
  • valid_classes (any): the classes that are valid
  • path_to_item (list): the path to the item to convert
  • configuration (Configuration): the instance to use to convert files
  • spec_property_naming (bool): True if the variable names in the input data are serialized names as specified in the OpenAPI document. False if the variables names in the input data are python variable names in PEP-8 snake case.
  • key_type (bool): if True we need to convert a key type (not supported)
  • must_convert (bool): if True we must convert
  • check_type (bool): if True we check the type or the returned data in ModelComposed/ModelNormal/ModelSimple instances
Returns:

instance (any) the fixed item

Raises:
  • ApiTypeError
  • ApiValueError
  • ApiKeyError
def is_type_nullable(input_type):
1358def is_type_nullable(input_type):
1359    """
1360    Returns true if None is an allowed value for the specified input_type.
1361
1362    A type is nullable if at least one of the following conditions is true:
1363    1. The OAS 'nullable' attribute has been specified,
1364    1. The type is the 'null' type,
1365    1. The type is a anyOf/oneOf composed schema, and a child schema is
1366       the 'null' type.
1367    Args:
1368        input_type (type): the class of the input_value that we are
1369            checking
1370    Returns:
1371        bool
1372    """
1373    if input_type is none_type:
1374        return True
1375    if issubclass(input_type, OpenApiModel) and input_type._nullable:
1376        return True
1377    if issubclass(input_type, ModelComposed):
1378        # If oneOf/anyOf, check if the 'null' type is one of the allowed types.
1379        for t in input_type._composed_schemas.get("oneOf", ()):
1380            if is_type_nullable(t):
1381                return True
1382        for t in input_type._composed_schemas.get("anyOf", ()):
1383            if is_type_nullable(t):
1384                return True
1385    return False

Returns true if None is an allowed value for the specified input_type.

A type is nullable if at least one of the following conditions is true:

  1. The OAS 'nullable' attribute has been specified,
  2. The type is the 'null' type,
  3. The type is a anyOf/oneOf composed schema, and a child schema is the 'null' type.
Arguments:
  • input_type (type): the class of the input_value that we are checking
Returns:

bool

def is_valid_type(input_class_simple, valid_classes):
1388def is_valid_type(input_class_simple, valid_classes):
1389    """
1390    Args:
1391        input_class_simple (class): the class of the input_value that we are
1392            checking
1393        valid_classes (tuple): the valid classes that the current item
1394            should be
1395    Returns:
1396        bool
1397    """
1398    valid_type = input_class_simple in valid_classes
1399    if not valid_type and (issubclass(input_class_simple, OpenApiModel) or input_class_simple is none_type):
1400        for valid_class in valid_classes:
1401            if input_class_simple is none_type and is_type_nullable(valid_class):
1402                # Schema is oneOf/anyOf and the 'null' type is one of the allowed types.
1403                return True
1404            if not (issubclass(valid_class, OpenApiModel) and valid_class.discriminator):
1405                continue
1406            discr_propertyname_py = list(valid_class.discriminator.keys())[0]
1407            discriminator_classes = valid_class.discriminator[discr_propertyname_py].values()
1408            valid_type = is_valid_type(input_class_simple, discriminator_classes)
1409            if valid_type:
1410                return True
1411    return valid_type
Arguments:
  • input_class_simple (class): the class of the input_value that we are checking
  • valid_classes (tuple): the valid classes that the current item should be
Returns:

bool

def validate_and_convert_types( input_value, required_types_mixed, path_to_item, spec_property_naming, _check_type, configuration=None):
1414def validate_and_convert_types(
1415    input_value, required_types_mixed, path_to_item, spec_property_naming, _check_type, configuration=None
1416):
1417    """Raises a TypeError is there is a problem, otherwise returns value
1418
1419    Args:
1420        input_value (any): the data to validate/convert
1421        required_types_mixed (list/dict/tuple): A list of
1422            valid classes, or a list tuples of valid classes, or a dict where
1423            the value is a tuple of value classes
1424        path_to_item: (list) the path to the data being validated
1425            this stores a list of keys or indices to get to the data being
1426            validated
1427        spec_property_naming (bool): True if the variable names in the input
1428            data are serialized names as specified in the OpenAPI document.
1429            False if the variables names in the input data are python
1430            variable names in PEP-8 snake case.
1431        _check_type: (boolean) if true, type will be checked and conversion
1432            will be attempted.
1433        configuration: (Configuration): the configuration class to use
1434            when converting file_type items.
1435            If passed, conversion will be attempted when possible
1436            If not passed, no conversions will be attempted and
1437            exceptions will be raised
1438
1439    Returns:
1440        the correctly typed value
1441
1442    Raises:
1443        ApiTypeError
1444    """
1445    results = get_required_type_classes(required_types_mixed, spec_property_naming)
1446    valid_classes, child_req_types_by_current_type = results
1447
1448    input_class_simple = get_simple_class(input_value)
1449    valid_type = is_valid_type(input_class_simple, valid_classes)
1450    if not valid_type:
1451        if configuration:
1452            # if input_value is not valid_type try to convert it
1453            converted_instance = attempt_convert_item(
1454                input_value,
1455                valid_classes,
1456                path_to_item,
1457                configuration,
1458                spec_property_naming,
1459                key_type=False,
1460                must_convert=True,
1461                check_type=_check_type,
1462            )
1463            return converted_instance
1464        else:
1465            raise get_type_error(input_value, path_to_item, valid_classes, key_type=False)
1466
1467    # input_value's type is in valid_classes
1468    if len(valid_classes) > 1 and configuration:
1469        # there are valid classes which are not the current class
1470        valid_classes_coercible = remove_uncoercible(
1471            valid_classes, input_value, spec_property_naming, must_convert=False
1472        )
1473        if valid_classes_coercible:
1474            converted_instance = attempt_convert_item(
1475                input_value,
1476                valid_classes_coercible,
1477                path_to_item,
1478                configuration,
1479                spec_property_naming,
1480                key_type=False,
1481                must_convert=False,
1482                check_type=_check_type,
1483            )
1484            return converted_instance
1485
1486    if child_req_types_by_current_type == {}:
1487        # all types are of the required types and there are no more inner
1488        # variables left to look at
1489        return input_value
1490    inner_required_types = child_req_types_by_current_type.get(type(input_value))
1491    if inner_required_types is None:
1492        # for this type, there are not more inner variables left to look at
1493        return input_value
1494    if isinstance(input_value, list):
1495        if input_value == []:
1496            # allow an empty list
1497            return input_value
1498        for index, inner_value in enumerate(input_value):
1499            inner_path = list(path_to_item)
1500            inner_path.append(index)
1501            input_value[index] = validate_and_convert_types(
1502                inner_value,
1503                inner_required_types,
1504                inner_path,
1505                spec_property_naming,
1506                _check_type,
1507                configuration=configuration,
1508            )
1509    elif isinstance(input_value, dict):
1510        if input_value == {}:
1511            # allow an empty dict
1512            return input_value
1513        for inner_key, inner_val in input_value.items():
1514            inner_path = list(path_to_item)
1515            inner_path.append(inner_key)
1516            if get_simple_class(inner_key) != str:
1517                raise get_type_error(inner_key, inner_path, valid_classes, key_type=True)
1518            input_value[inner_key] = validate_and_convert_types(
1519                inner_val,
1520                inner_required_types,
1521                inner_path,
1522                spec_property_naming,
1523                _check_type,
1524                configuration=configuration,
1525            )
1526    return input_value

Raises a TypeError is there is a problem, otherwise returns value

Arguments:
  • input_value (any): the data to validate/convert
  • required_types_mixed (list/dict/tuple): A list of valid classes, or a list tuples of valid classes, or a dict where the value is a tuple of value classes
  • path_to_item: (list) the path to the data being validated this stores a list of keys or indices to get to the data being validated
  • spec_property_naming (bool): True if the variable names in the input data are serialized names as specified in the OpenAPI document. False if the variables names in the input data are python variable names in PEP-8 snake case.
  • _check_type: (boolean) if true, type will be checked and conversion will be attempted.
  • configuration: (Configuration): the configuration class to use when converting file_type items. If passed, conversion will be attempted when possible If not passed, no conversions will be attempted and exceptions will be raised
Returns:

the correctly typed value

Raises:
  • ApiTypeError
def model_to_dict(model_instance, serialize=True):
1529def model_to_dict(model_instance, serialize=True):
1530    """Returns the model properties as a dict
1531
1532    Args:
1533        model_instance (one of your model instances): the model instance that
1534            will be converted to a dict.
1535
1536    Keyword Args:
1537        serialize (bool): if True, the keys in the dict will be values from
1538            attribute_map
1539    """
1540    result = {}
1541
1542    model_instances = [model_instance]
1543    if model_instance._composed_schemas:
1544        model_instances.extend(model_instance._composed_instances)
1545    seen_json_attribute_names = set()
1546    used_fallback_python_attribute_names = set()
1547    py_to_json_map = {}
1548    for model_instance in model_instances:
1549        for attr, value in model_instance._data_store.items():
1550            if serialize:
1551                # we use get here because additional property key names do not
1552                # exist in attribute_map
1553                try:
1554                    attr = model_instance.attribute_map[attr]
1555                    py_to_json_map.update(model_instance.attribute_map)
1556                    seen_json_attribute_names.add(attr)
1557                except KeyError:
1558                    used_fallback_python_attribute_names.add(attr)
1559            if isinstance(value, list):
1560                if not value:
1561                    # empty list or None
1562                    result[attr] = value
1563                else:
1564                    res = []
1565                    for v in value:
1566                        if isinstance(v, PRIMITIVE_TYPES) or v is None:
1567                            res.append(v)
1568                        elif isinstance(v, ModelSimple):
1569                            res.append(v.value)
1570                        else:
1571                            res.append(model_to_dict(v, serialize=serialize))
1572                    result[attr] = res
1573            elif isinstance(value, dict):
1574                result[attr] = dict(
1575                    map(
1576                        lambda item: (item[0], model_to_dict(item[1], serialize=serialize))
1577                        if hasattr(item[1], "_data_store")
1578                        else item,
1579                        value.items(),
1580                    )
1581                )
1582            elif isinstance(value, ModelSimple):
1583                result[attr] = value.value
1584            elif hasattr(value, "_data_store"):
1585                result[attr] = model_to_dict(value, serialize=serialize)
1586            else:
1587                result[attr] = value
1588    if serialize:
1589        for python_key in used_fallback_python_attribute_names:
1590            json_key = py_to_json_map.get(python_key)
1591            if json_key is None:
1592                continue
1593            if python_key == json_key:
1594                continue
1595            json_key_assigned_no_need_for_python_key = json_key in seen_json_attribute_names
1596            if json_key_assigned_no_need_for_python_key:
1597                del result[python_key]
1598
1599    return result

Returns the model properties as a dict

Arguments:
  • model_instance (one of your model instances): the model instance that will be converted to a dict.
Keyword Args:

serialize (bool): if True, the keys in the dict will be values from attribute_map

def type_error_message(var_value=None, var_name=None, valid_classes=None, key_type=None):
1602def type_error_message(var_value=None, var_name=None, valid_classes=None, key_type=None):
1603    """
1604    Keyword Args:
1605        var_value (any): the variable which has the type_error
1606        var_name (str): the name of the variable which has the typ error
1607        valid_classes (tuple): the accepted classes for current_item's
1608                                  value
1609        key_type (bool): False if our value is a value in a dict
1610                         True if it is a key in a dict
1611                         False if our item is an item in a list
1612    """
1613    key_or_value = "value"
1614    if key_type:
1615        key_or_value = "key"
1616    valid_classes_phrase = get_valid_classes_phrase(valid_classes)
1617    msg = "Invalid type for variable '{0}'. Required {1} type {2} and " "passed type was {3}".format(
1618        var_name,
1619        key_or_value,
1620        valid_classes_phrase,
1621        type(var_value).__name__,
1622    )
1623    return msg
Keyword Args:

var_value (any): the variable which has the type_error var_name (str): the name of the variable which has the typ error valid_classes (tuple): the accepted classes for current_item's value key_type (bool): False if our value is a value in a dict True if it is a key in a dict False if our item is an item in a list

def get_valid_classes_phrase(input_classes):
1626def get_valid_classes_phrase(input_classes):
1627    """Returns a string phrase describing what types are allowed"""
1628    all_classes = list(input_classes)
1629    all_classes = sorted(all_classes, key=lambda cls: cls.__name__)
1630    all_class_names = [cls.__name__ for cls in all_classes]
1631    if len(all_class_names) == 1:
1632        return "is {0}".format(all_class_names[0])
1633    return "is one of [{0}]".format(", ".join(all_class_names))

Returns a string phrase describing what types are allowed

def get_allof_instances(self, model_args, constant_args):
1636def get_allof_instances(self, model_args, constant_args):
1637    """
1638    Args:
1639        self: the class we are handling
1640        model_args (dict): var_name to var_value
1641            used to make instances
1642        constant_args (dict):
1643            metadata arguments:
1644            _check_type
1645            _path_to_item
1646            _spec_property_naming
1647            _configuration
1648            _visited_composed_classes
1649
1650    Returns
1651        composed_instances (list)
1652    """
1653    composed_instances = []
1654    for allof_class in self._composed_schemas["allOf"]:
1655        try:
1656            allof_instance = allof_class(**model_args, **constant_args)
1657            composed_instances.append(allof_instance)
1658        except Exception as ex:
1659            raise ApiValueError(
1660                "Invalid inputs given to generate an instance of '%s'. The "
1661                "input data was invalid for the allOf schema '%s' in the composed "
1662                "schema '%s'. Error=%s" % (allof_class.__name__, allof_class.__name__, self.__class__.__name__, str(ex))
1663            ) from ex
1664    return composed_instances
Arguments:
  • self: the class we are handling
  • model_args (dict): var_name to var_value used to make instances
  • constant_args (dict): metadata arguments: _check_type _path_to_item _spec_property_naming _configuration _visited_composed_classes

Returns composed_instances (list)

def get_oneof_instance(cls, model_kwargs, constant_kwargs, model_arg=None):
1667def get_oneof_instance(cls, model_kwargs, constant_kwargs, model_arg=None):
1668    """
1669    Find the oneOf schema that matches the input data (e.g. payload).
1670    If exactly one schema matches the input data, an instance of that schema
1671    is returned.
1672    If zero or more than one schema match the input data, an exception is raised.
1673    In OAS 3.x, the payload MUST, by validation, match exactly one of the
1674    schemas described by oneOf.
1675
1676    Args:
1677        cls: the class we are handling
1678        model_kwargs (dict): var_name to var_value
1679            The input data, e.g. the payload that must match a oneOf schema
1680            in the OpenAPI document.
1681        constant_kwargs (dict): var_name to var_value
1682            args that every model requires, including configuration, server
1683            and path to item.
1684
1685    Kwargs:
1686        model_arg: (int, float, bool, str, date, datetime, ModelSimple, None):
1687            the value to assign to a primitive class or ModelSimple class
1688            Notes:
1689            - this is only passed in when oneOf includes types which are not object
1690            - None is used to suppress handling of model_arg, nullable models are handled in __new__
1691
1692    Returns
1693        oneof_instance (instance)
1694    """
1695    if len(cls._composed_schemas["oneOf"]) == 0:
1696        return None
1697
1698    oneof_instances = []
1699    # Iterate over each oneOf schema and determine if the input data
1700    # matches the oneOf schemas.
1701    for oneof_class in cls._composed_schemas["oneOf"]:
1702        # The composed oneOf schema allows the 'null' type and the input data
1703        # is the null value. This is a OAS >= 3.1 feature.
1704        if oneof_class is none_type:
1705            # skip none_types because we are deserializing dict data.
1706            # none_type deserialization is handled in the __new__ method
1707            continue
1708
1709        single_value_input = allows_single_value_input(oneof_class)
1710
1711        try:
1712            if not single_value_input:
1713                oneof_instance = oneof_class(**model_kwargs, **constant_kwargs)
1714            else:
1715                if issubclass(oneof_class, ModelSimple):
1716                    oneof_instance = oneof_class(model_arg, **constant_kwargs)
1717                elif oneof_class in PRIMITIVE_TYPES:
1718                    oneof_instance = validate_and_convert_types(
1719                        model_arg,
1720                        (oneof_class,),
1721                        constant_kwargs["_path_to_item"],
1722                        constant_kwargs["_spec_property_naming"],
1723                        constant_kwargs["_check_type"],
1724                        configuration=constant_kwargs["_configuration"],
1725                    )
1726            oneof_instances.append(oneof_instance)
1727        except Exception:
1728            pass
1729    if len(oneof_instances) == 0:
1730        raise ApiValueError(
1731            "Invalid inputs given to generate an instance of %s. None "
1732            "of the oneOf schemas matched the input data." % cls.__name__
1733        )
1734    elif len(oneof_instances) > 1:
1735        raise ApiValueError(
1736            "Invalid inputs given to generate an instance of %s. Multiple "
1737            "oneOf schemas matched the inputs, but a max of one is allowed." % cls.__name__
1738        )
1739    return oneof_instances[0]

Find the oneOf schema that matches the input data (e.g. payload). If exactly one schema matches the input data, an instance of that schema is returned. If zero or more than one schema match the input data, an exception is raised. In OAS 3.x, the payload MUST, by validation, match exactly one of the schemas described by oneOf.

Arguments:
  • cls: the class we are handling
  • model_kwargs (dict): var_name to var_value The input data, e.g. the payload that must match a oneOf schema in the OpenAPI document.
  • constant_kwargs (dict): var_name to var_value args that every model requires, including configuration, server and path to item.
Kwargs:

model_arg: (int, float, bool, str, date, datetime, ModelSimple, None): the value to assign to a primitive class or ModelSimple class Notes: - this is only passed in when oneOf includes types which are not object - None is used to suppress handling of model_arg, nullable models are handled in __new__

Returns oneof_instance (instance)

def get_anyof_instances(self, model_args, constant_args):
1742def get_anyof_instances(self, model_args, constant_args):
1743    """
1744    Args:
1745        self: the class we are handling
1746        model_args (dict): var_name to var_value
1747            The input data, e.g. the payload that must match at least one
1748            anyOf child schema in the OpenAPI document.
1749        constant_args (dict): var_name to var_value
1750            args that every model requires, including configuration, server
1751            and path to item.
1752
1753    Returns
1754        anyof_instances (list)
1755    """
1756    anyof_instances = []
1757    if len(self._composed_schemas["anyOf"]) == 0:
1758        return anyof_instances
1759
1760    for anyof_class in self._composed_schemas["anyOf"]:
1761        # The composed oneOf schema allows the 'null' type and the input data
1762        # is the null value. This is a OAS >= 3.1 feature.
1763        if anyof_class is none_type:
1764            # skip none_types because we are deserializing dict data.
1765            # none_type deserialization is handled in the __new__ method
1766            continue
1767
1768        try:
1769            anyof_instance = anyof_class(**model_args, **constant_args)
1770            anyof_instances.append(anyof_instance)
1771        except Exception:
1772            pass
1773    if len(anyof_instances) == 0:
1774        raise ApiValueError(
1775            "Invalid inputs given to generate an instance of %s. None of the "
1776            "anyOf schemas matched the inputs." % self.__class__.__name__
1777        )
1778    return anyof_instances
Arguments:
  • self: the class we are handling
  • model_args (dict): var_name to var_value The input data, e.g. the payload that must match at least one anyOf child schema in the OpenAPI document.
  • constant_args (dict): var_name to var_value args that every model requires, including configuration, server and path to item.

Returns anyof_instances (list)

def get_discarded_args(self, composed_instances, model_args):
1781def get_discarded_args(self, composed_instances, model_args):
1782    """
1783    Gathers the args that were discarded by configuration.discard_unknown_keys
1784    """
1785    model_arg_keys = model_args.keys()
1786    discarded_args = set()
1787    # arguments passed to self were already converted to python names
1788    # before __init__ was called
1789    for instance in composed_instances:
1790        if instance.__class__ in self._composed_schemas["allOf"]:
1791            try:
1792                keys = instance.to_dict().keys()
1793                discarded_keys = model_args - keys
1794                discarded_args.update(discarded_keys)
1795            except Exception:
1796                # allOf integer schema will throw exception
1797                pass
1798        else:
1799            try:
1800                all_keys = set(model_to_dict(instance, serialize=False).keys())
1801                js_keys = model_to_dict(instance, serialize=True).keys()
1802                all_keys.update(js_keys)
1803                discarded_keys = model_arg_keys - all_keys
1804                discarded_args.update(discarded_keys)
1805            except Exception:
1806                # allOf integer schema will throw exception
1807                pass
1808    return discarded_args

Gathers the args that were discarded by configuration.discard_unknown_keys

def validate_get_composed_info(constant_args, model_args, self):
1811def validate_get_composed_info(constant_args, model_args, self):
1812    """
1813    For composed schemas, generate schema instances for
1814    all schemas in the oneOf/anyOf/allOf definition. If additional
1815    properties are allowed, also assign those properties on
1816    all matched schemas that contain additionalProperties.
1817    Openapi schemas are python classes.
1818
1819    Exceptions are raised if:
1820    - 0 or > 1 oneOf schema matches the model_args input data
1821    - no anyOf schema matches the model_args input data
1822    - any of the allOf schemas do not match the model_args input data
1823
1824    Args:
1825        constant_args (dict): these are the args that every model requires
1826        model_args (dict): these are the required and optional spec args that
1827            were passed in to make this model
1828        self (class): the class that we are instantiating
1829            This class contains self._composed_schemas
1830
1831    Returns:
1832        composed_info (list): length three
1833            composed_instances (list): the composed instances which are not
1834                self
1835            var_name_to_model_instances (dict): a dict going from var_name
1836                to the model_instance which holds that var_name
1837                the model_instance may be self or an instance of one of the
1838                classes in self.composed_instances()
1839            additional_properties_model_instances (list): a list of the
1840                model instances which have the property
1841                additional_properties_type. This list can include self
1842    """
1843    # create composed_instances
1844    composed_instances = []
1845    allof_instances = get_allof_instances(self, model_args, constant_args)
1846    composed_instances.extend(allof_instances)
1847    oneof_instance = get_oneof_instance(self.__class__, model_args, constant_args)
1848    if oneof_instance is not None:
1849        composed_instances.append(oneof_instance)
1850    anyof_instances = get_anyof_instances(self, model_args, constant_args)
1851    composed_instances.extend(anyof_instances)
1852    """
1853    set additional_properties_model_instances
1854    additional properties must be evaluated at the schema level
1855    so self's additional properties are most important
1856    If self is a composed schema with:
1857    - no properties defined in self
1858    - additionalProperties: False
1859    Then for object payloads every property is an additional property
1860    and they are not allowed, so only empty dict is allowed
1861
1862    Properties must be set on all matching schemas
1863    so when a property is assigned toa composed instance, it must be set on all
1864    composed instances regardless of additionalProperties presence
1865    keeping it to prevent breaking changes in v5.0.1
1866    TODO remove cls._additional_properties_model_instances in 6.0.0
1867    """
1868    additional_properties_model_instances = []
1869    if self.additional_properties_type is not None:
1870        additional_properties_model_instances = [self]
1871
1872    """
1873    no need to set properties on self in here, they will be set in __init__
1874    By here all composed schema oneOf/anyOf/allOf instances have their properties set using
1875    model_args
1876    """
1877    discarded_args = get_discarded_args(self, composed_instances, model_args)
1878
1879    # map variable names to composed_instances
1880    var_name_to_model_instances = {}
1881    for prop_name in model_args:
1882        if prop_name not in discarded_args:
1883            var_name_to_model_instances[prop_name] = [self] + composed_instances
1884
1885    return [composed_instances, var_name_to_model_instances, additional_properties_model_instances, discarded_args]

For composed schemas, generate schema instances for all schemas in the oneOf/anyOf/allOf definition. If additional properties are allowed, also assign those properties on all matched schemas that contain additionalProperties. Openapi schemas are python classes.

Exceptions are raised if:

  • 0 or > 1 oneOf schema matches the model_args input data
  • no anyOf schema matches the model_args input data
  • any of the allOf schemas do not match the model_args input data
Arguments:
  • constant_args (dict): these are the args that every model requires
  • model_args (dict): these are the required and optional spec args that were passed in to make this model
  • self (class): the class that we are instantiating This class contains self._composed_schemas
Returns:

composed_info (list): length three composed_instances (list): the composed instances which are not self var_name_to_model_instances (dict): a dict going from var_name to the model_instance which holds that var_name the model_instance may be self or an instance of one of the classes in self.composed_instances() additional_properties_model_instances (list): a list of the model instances which have the property additional_properties_type. This list can include self