pinecone.openapi_support.model_utils

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

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

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

The base class for all OpenAPIModels

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

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

def get(self, name, default=None):
398    def get(self, name, default=None):
399        """returns the value of an attribute or some default value if the attribute was not set"""
400        if name in self.required_properties:
401            return self.__dict__[name]
402
403        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):
422    def to_str(self):
423        """Returns the string representation of the model"""
424        return str(self.value)

Returns the string representation of the model

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

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

def get(self, name, default=None):
452    def get(self, name, default=None):
453        """returns the value of an attribute or some default value if the attribute was not set"""
454        if name in self.required_properties:
455            return self.__dict__[name]
456
457        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):
476    def to_dict(self):
477        """Returns the model properties as a dict"""
478        return model_to_dict(self, serialize=False)

Returns the model properties as a dict

def to_str(self):
480    def to_str(self):
481        """Returns the string representation of the model"""
482        return pprint.pformat(self.to_dict())

Returns the string representation of the model

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

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

def to_dict(self):
631    def to_dict(self):
632        """Returns the model properties as a dict"""
633        return model_to_dict(self, serialize=False)

Returns the model properties as a dict

def to_str(self):
635    def to_str(self):
636        """Returns the string representation of the model"""
637        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 'str'>: 11, <class 'io.IOBase'>: 12}
UPCONVERSION_TYPE_PAIRS = ((<class 'str'>, <class 'datetime.datetime'>), (<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 'io.IOBase'>))}
def get_simple_class(input_value):
731def get_simple_class(input_value):
732    """Returns an input_value's simple class that we will use for type checking
733    Python2:
734    float and int will return int, where int is the python3 int backport
735    str and unicode will return str, where str is the python3 str backport
736    Note: float and int ARE both instances of int backport
737    Note: str_py2 and unicode_py2 are NOT both instances of str backport
738
739    Args:
740        input_value (class/class_instance): the item for which we will return
741                                            the simple class
742    """
743    if isinstance(input_value, type):
744        # input_value is a class
745        return input_value
746    elif isinstance(input_value, tuple):
747        return tuple
748    elif isinstance(input_value, list):
749        return list
750    elif isinstance(input_value, dict):
751        return dict
752    elif input_value is None:
753        return none_type
754    elif isinstance(input_value, file_type):
755        return file_type
756    elif isinstance(input_value, bool):
757        # this must be higher than the int check because
758        # isinstance(True, int) == True
759        return bool
760    elif isinstance(input_value, int):
761        return int
762    elif isinstance(input_value, datetime):
763        # this must be higher than the date check because
764        # isinstance(datetime_instance, date) == True
765        return datetime
766    elif isinstance(input_value, date):
767        return date
768    elif isinstance(input_value, str):
769        return str
770    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):
773def check_allowed_values(allowed_values, input_variable_path, input_values):
774    """Raises an exception if the input_values are not allowed
775
776    Args:
777        allowed_values (dict): the allowed_values dict
778        input_variable_path (tuple): the path to the input variable
779        input_values (list/str/int/float/date/datetime): the values that we
780            are checking to see if they are in allowed_values
781    """
782    these_allowed_values = list(allowed_values[input_variable_path].values())
783    if isinstance(input_values, list) and not set(input_values).issubset(set(these_allowed_values)):
784        invalid_values = (", ".join(map(str, set(input_values) - set(these_allowed_values))),)
785        raise PineconeApiValueError(
786            "Invalid values for `%s` [%s], must be a subset of [%s]"
787            % (input_variable_path[0], invalid_values, ", ".join(map(str, these_allowed_values)))
788        )
789    elif isinstance(input_values, dict) and not set(input_values.keys()).issubset(
790        set(these_allowed_values)
791    ):
792        invalid_values = ", ".join(map(str, set(input_values.keys()) - set(these_allowed_values)))
793        raise PineconeApiValueError(
794            "Invalid keys in `%s` [%s], must be a subset of [%s]"
795            % (input_variable_path[0], invalid_values, ", ".join(map(str, these_allowed_values)))
796        )
797    elif not isinstance(input_values, (list, dict)) and input_values not in these_allowed_values:
798        raise PineconeApiValueError(
799            "Invalid value for `%s` (%s), must be one of %s"
800            % (input_variable_path[0], input_values, these_allowed_values)
801        )

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):
804def is_json_validation_enabled(schema_keyword, configuration=None):
805    """Returns true if JSON schema validation is enabled for the specified
806    validation keyword. This can be used to skip JSON schema structural validation
807    as requested in the configuration.
808
809    Args:
810        schema_keyword (string): the name of a JSON schema validation keyword.
811        configuration (Configuration): the configuration class.
812    """
813
814    return (
815        configuration is None
816        or not hasattr(configuration, "_disabled_client_side_validations")
817        or schema_keyword not in configuration._disabled_client_side_validations
818    )

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):
821def check_validations(validations, input_variable_path, input_values, configuration=None):
822    """Raises an exception if the input_values are invalid
823
824    Args:
825        validations (dict): the validation dictionary.
826        input_variable_path (tuple): the path to the input variable.
827        input_values (list/str/int/float/date/datetime): the values that we
828            are checking.
829        configuration (Configuration): the configuration class.
830    """
831
832    if input_values is None:
833        return
834
835    current_validations = validations[input_variable_path]
836    if (
837        is_json_validation_enabled("multipleOf", configuration)
838        and "multiple_of" in current_validations
839        and isinstance(input_values, (int, float))
840        and not (float(input_values) / current_validations["multiple_of"]).is_integer()
841    ):
842        # Note 'multipleOf' will be as good as the floating point arithmetic.
843        raise PineconeApiValueError(
844            "Invalid value for `%s`, value must be a multiple of "
845            "`%s`" % (input_variable_path[0], current_validations["multiple_of"])
846        )
847
848    if (
849        is_json_validation_enabled("maxLength", configuration)
850        and "max_length" in current_validations
851        and len(input_values) > current_validations["max_length"]
852    ):
853        raise PineconeApiValueError(
854            "Invalid value for `%s`, length must be less than or equal to "
855            "`%s`" % (input_variable_path[0], current_validations["max_length"])
856        )
857
858    if (
859        is_json_validation_enabled("minLength", configuration)
860        and "min_length" in current_validations
861        and len(input_values) < current_validations["min_length"]
862    ):
863        raise PineconeApiValueError(
864            "Invalid value for `%s`, length must be greater than or equal to "
865            "`%s`" % (input_variable_path[0], current_validations["min_length"])
866        )
867
868    if (
869        is_json_validation_enabled("maxItems", configuration)
870        and "max_items" in current_validations
871        and len(input_values) > current_validations["max_items"]
872    ):
873        raise PineconeApiValueError(
874            "Invalid value for `%s`, number of items must be less than or "
875            "equal to `%s`" % (input_variable_path[0], current_validations["max_items"])
876        )
877
878    if (
879        is_json_validation_enabled("minItems", configuration)
880        and "min_items" in current_validations
881        and len(input_values) < current_validations["min_items"]
882    ):
883        raise ValueError(
884            "Invalid value for `%s`, number of items must be greater than or "
885            "equal to `%s`" % (input_variable_path[0], current_validations["min_items"])
886        )
887
888    items = ("exclusive_maximum", "inclusive_maximum", "exclusive_minimum", "inclusive_minimum")
889    if any(item in current_validations for item in items):
890        if isinstance(input_values, list):
891            max_val = max(input_values)
892            min_val = min(input_values)
893        elif isinstance(input_values, dict):
894            max_val = max(input_values.values())
895            min_val = min(input_values.values())
896        else:
897            max_val = input_values
898            min_val = input_values
899
900    if (
901        is_json_validation_enabled("exclusiveMaximum", configuration)
902        and "exclusive_maximum" in current_validations
903        and max_val >= current_validations["exclusive_maximum"]
904    ):
905        raise PineconeApiValueError(
906            "Invalid value for `%s`, must be a value less than `%s`"
907            % (input_variable_path[0], current_validations["exclusive_maximum"])
908        )
909
910    if (
911        is_json_validation_enabled("maximum", configuration)
912        and "inclusive_maximum" in current_validations
913        and max_val > current_validations["inclusive_maximum"]
914    ):
915        raise PineconeApiValueError(
916            "Invalid value for `%s`, must be a value less than or equal to "
917            "`%s`" % (input_variable_path[0], current_validations["inclusive_maximum"])
918        )
919
920    if (
921        is_json_validation_enabled("exclusiveMinimum", configuration)
922        and "exclusive_minimum" in current_validations
923        and min_val <= current_validations["exclusive_minimum"]
924    ):
925        raise PineconeApiValueError(
926            "Invalid value for `%s`, must be a value greater than `%s`"
927            % (input_variable_path[0], current_validations["exclusive_maximum"])
928        )
929
930    if (
931        is_json_validation_enabled("minimum", configuration)
932        and "inclusive_minimum" in current_validations
933        and min_val < current_validations["inclusive_minimum"]
934    ):
935        raise PineconeApiValueError(
936            "Invalid value for `%s`, must be a value greater than or equal "
937            "to `%s`" % (input_variable_path[0], current_validations["inclusive_minimum"])
938        )
939    flags = current_validations.get("regex", {}).get("flags", 0)
940    if (
941        is_json_validation_enabled("pattern", configuration)
942        and "regex" in current_validations
943        and not re.search(current_validations["regex"]["pattern"], input_values, flags=flags)
944    ):
945        err_msg = r"Invalid value for `%s`, must match regular expression `%s`" % (
946            input_variable_path[0],
947            current_validations["regex"]["pattern"],
948        )
949        if flags != 0:
950            # Don't print the regex flags if the flags are not
951            # specified in the OAS document.
952            err_msg = r"%s with flags=`%s`" % (err_msg, flags)
953        raise PineconeApiValueError(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):
956def order_response_types(required_types):
957    """Returns the required types sorted in coercion order
958
959    Args:
960        required_types (list/tuple): collection of classes or instance of
961            list or dict with class information inside it.
962
963    Returns:
964        (list): coercion order sorted collection of classes or instance
965            of list or dict with class information inside it.
966    """
967
968    def index_getter(class_or_instance):
969        if isinstance(class_or_instance, list):
970            return COERCION_INDEX_BY_TYPE[list]
971        elif isinstance(class_or_instance, dict):
972            return COERCION_INDEX_BY_TYPE[dict]
973        elif inspect.isclass(class_or_instance) and issubclass(class_or_instance, ModelComposed):
974            return COERCION_INDEX_BY_TYPE[ModelComposed]
975        elif inspect.isclass(class_or_instance) and issubclass(class_or_instance, ModelNormal):
976            return COERCION_INDEX_BY_TYPE[ModelNormal]
977        elif inspect.isclass(class_or_instance) and issubclass(class_or_instance, ModelSimple):
978            return COERCION_INDEX_BY_TYPE[ModelSimple]
979        elif class_or_instance in COERCION_INDEX_BY_TYPE:
980            return COERCION_INDEX_BY_TYPE[class_or_instance]
981        raise PineconeApiValueError("Unsupported type: %s" % class_or_instance)
982
983    sorted_types = sorted(
984        required_types, key=lambda class_or_instance: index_getter(class_or_instance)
985    )
986    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):
 989def remove_uncoercible(
 990    required_types_classes, current_item, spec_property_naming, must_convert=True
 991):
 992    """Only keeps the type conversions that are possible
 993
 994    Args:
 995        required_types_classes (tuple): tuple of classes that are required
 996                          these should be ordered by COERCION_INDEX_BY_TYPE
 997        spec_property_naming (bool): True if the variable names in the input
 998            data are serialized names as specified in the OpenAPI document.
 999            False if the variables names in the input data are python
1000            variable names in PEP-8 snake case.
1001        current_item (any): the current item (input data) to be converted
1002
1003    Keyword Args:
1004        must_convert (bool): if True the item to convert is of the wrong
1005                          type and we want a big list of coercibles
1006                          if False, we want a limited list of coercibles
1007
1008    Returns:
1009        (list): the remaining coercible required types, classes only
1010    """
1011    current_type_simple = get_simple_class(current_item)
1012
1013    results_classes = []
1014    for required_type_class in required_types_classes:
1015        # convert our models to OpenApiModel
1016        required_type_class_simplified = required_type_class
1017        if isinstance(required_type_class_simplified, type):
1018            if issubclass(required_type_class_simplified, ModelComposed):
1019                required_type_class_simplified = ModelComposed
1020            elif issubclass(required_type_class_simplified, ModelNormal):
1021                required_type_class_simplified = ModelNormal
1022            elif issubclass(required_type_class_simplified, ModelSimple):
1023                required_type_class_simplified = ModelSimple
1024
1025        if required_type_class_simplified == current_type_simple:
1026            # don't consider converting to one's own class
1027            continue
1028
1029        class_pair = (current_type_simple, required_type_class_simplified)
1030        if must_convert and class_pair in COERCIBLE_TYPE_PAIRS[spec_property_naming]:
1031            results_classes.append(required_type_class)
1032        elif class_pair in UPCONVERSION_TYPE_PAIRS:
1033            results_classes.append(required_type_class)
1034    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):
1037def get_discriminated_classes(cls):
1038    """
1039    Returns all the classes that a discriminator converts to
1040    TODO: lru_cache this
1041    """
1042    possible_classes = []
1043    key = list(cls.discriminator.keys())[0]
1044    if is_type_nullable(cls):
1045        possible_classes.append(cls)
1046    for discr_cls in cls.discriminator[key].values():
1047        if hasattr(discr_cls, "discriminator") and discr_cls.discriminator is not None:
1048            possible_classes.extend(get_discriminated_classes(discr_cls))
1049        else:
1050            possible_classes.append(discr_cls)
1051    return possible_classes

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

def get_possible_classes(cls, from_server_context):
1054def get_possible_classes(cls, from_server_context):
1055    # TODO: lru_cache this
1056    possible_classes = [cls]
1057    if from_server_context:
1058        return possible_classes
1059    if hasattr(cls, "discriminator") and cls.discriminator is not None:
1060        possible_classes = []
1061        possible_classes.extend(get_discriminated_classes(cls))
1062    elif issubclass(cls, ModelComposed):
1063        possible_classes.extend(composed_model_input_classes(cls))
1064    return possible_classes
def get_required_type_classes(required_types_mixed, spec_property_naming):
1067def get_required_type_classes(required_types_mixed, spec_property_naming):
1068    """Converts the tuple required_types into a tuple and a dict described
1069    below
1070
1071    Args:
1072        required_types_mixed (tuple/list): will contain either classes or
1073            instance of list or dict
1074        spec_property_naming (bool): if True these values came from the
1075            server, and we use the data types in our endpoints.
1076            If False, we are client side and we need to include
1077            oneOf and discriminator classes inside the data types in our endpoints
1078
1079    Returns:
1080        (valid_classes, dict_valid_class_to_child_types_mixed):
1081            valid_classes (tuple): the valid classes that the current item
1082                                   should be
1083            dict_valid_class_to_child_types_mixed (dict):
1084                valid_class (class): this is the key
1085                child_types_mixed (list/dict/tuple): describes the valid child
1086                    types
1087    """
1088    valid_classes = []
1089    child_req_types_by_current_type = {}
1090
1091    for required_type in required_types_mixed:
1092        if isinstance(required_type, list):
1093            valid_classes.append(list)
1094            child_req_types_by_current_type[list] = required_type
1095        elif isinstance(required_type, tuple):
1096            valid_classes.append(tuple)
1097            child_req_types_by_current_type[tuple] = required_type
1098        elif isinstance(required_type, dict):
1099            valid_classes.append(dict)
1100            child_req_types_by_current_type[dict] = required_type[str]
1101        else:
1102            valid_classes.extend(get_possible_classes(required_type, spec_property_naming))
1103    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):
1106def change_keys_js_to_python(input_dict, model_class):
1107    """
1108    Converts from javascript_key keys in the input_dict to python_keys in
1109    the output dict using the mapping in model_class.
1110    If the input_dict contains a key which does not declared in the model_class,
1111    the key is added to the output dict as is. The assumption is the model_class
1112    may have undeclared properties (additionalProperties attribute in the OAS
1113    document).
1114    """
1115
1116    if getattr(model_class, "attribute_map", None) is None:
1117        return input_dict
1118    output_dict = {}
1119    reversed_attr_map = {value: key for key, value in model_class.attribute_map.items()}
1120    for javascript_key, value in input_dict.items():
1121        python_key = reversed_attr_map.get(javascript_key)
1122        if python_key is None:
1123            # if the key is unknown, it is in error or it is an
1124            # additionalProperties variable
1125            python_key = javascript_key
1126        output_dict[python_key] = value
1127    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):
1130def get_type_error(var_value, path_to_item, valid_classes, key_type=False):
1131    error_msg = type_error_message(
1132        var_name=path_to_item[-1],
1133        var_value=var_value,
1134        valid_classes=valid_classes,
1135        key_type=key_type,
1136    )
1137    return PineconeApiTypeError(
1138        error_msg, path_to_item=path_to_item, valid_classes=valid_classes, key_type=key_type
1139    )
def deserialize_primitive(data, klass, path_to_item):
1142def deserialize_primitive(data, klass, path_to_item):
1143    """Deserializes string to primitive type.
1144
1145    :param data: str/int/float
1146    :param klass: str/class the class to convert to
1147
1148    :return: int, float, str, bool
1149    """
1150    additional_message = ""
1151    try:
1152        if klass in {datetime, date}:
1153            additional_message = (
1154                "If you need your parameter to have a fallback "
1155                "string value, please set its type as `type: {}` in your "
1156                "spec. That allows the value to be any type. "
1157            )
1158            if klass == datetime:
1159                if len(data) < 8:
1160                    raise ValueError("This is not a datetime")
1161                # The string should be in iso8601 datetime format.
1162                parsed_datetime = parse(data)
1163                date_only = (
1164                    parsed_datetime.hour == 0
1165                    and parsed_datetime.minute == 0
1166                    and parsed_datetime.second == 0
1167                    and parsed_datetime.tzinfo is None
1168                    and 8 <= len(data) <= 10
1169                )
1170                if date_only:
1171                    raise ValueError("This is a date, not a datetime")
1172                return parsed_datetime
1173            elif klass == date:
1174                if len(data) < 8:
1175                    raise ValueError("This is not a date")
1176                return parse(data).date()
1177        else:
1178            converted_value = klass(data)
1179            if isinstance(data, str) and klass is float:
1180                if str(converted_value) != data:
1181                    # '7' -> 7.0 -> '7.0' != '7'
1182                    raise ValueError("This is not a float")
1183            return converted_value
1184    except (OverflowError, ValueError) as ex:
1185        # parse can raise OverflowError
1186        raise PineconeApiValueError(
1187            "{0}Failed to parse {1} as {2}".format(additional_message, repr(data), klass.__name__),
1188            path_to_item=path_to_item,
1189        ) 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

def get_discriminator_class(model_class, discr_name, discr_value, cls_visited):
1192def get_discriminator_class(model_class, discr_name, discr_value, cls_visited):
1193    """Returns the child class specified by the discriminator.
1194
1195    Args:
1196        model_class (OpenApiModel): the model class.
1197        discr_name (string): the name of the discriminator property.
1198        discr_value (any): the discriminator value.
1199        cls_visited (list): list of model classes that have been visited.
1200            Used to determine the discriminator class without
1201            visiting circular references indefinitely.
1202
1203    Returns:
1204        used_model_class (class/None): the chosen child class that will be used
1205            to deserialize the data, for example dog.Dog.
1206            If a class is not found, None is returned.
1207    """
1208
1209    if model_class in cls_visited:
1210        # The class has already been visited and no suitable class was found.
1211        return None
1212    cls_visited.append(model_class)
1213    used_model_class = None
1214    if discr_name in model_class.discriminator:
1215        class_name_to_discr_class = model_class.discriminator[discr_name]
1216        used_model_class = class_name_to_discr_class.get(discr_value)
1217    if used_model_class is None:
1218        # We didn't find a discriminated class in class_name_to_discr_class.
1219        # So look in the ancestor or descendant discriminators
1220        # The discriminator mapping may exist in a descendant (anyOf, oneOf)
1221        # or ancestor (allOf).
1222        # Ancestor example: in the GrandparentAnimal -> ParentPet -> ChildCat
1223        #   hierarchy, the discriminator mappings may be defined at any level
1224        #   in the hierarchy.
1225        # Descendant example:  mammal -> whale/zebra/Pig -> BasquePig/DanishPig
1226        #   if we try to make BasquePig from mammal, we need to travel through
1227        #   the oneOf descendant discriminators to find BasquePig
1228        descendant_classes = model_class._composed_schemas.get(
1229            "oneOf", ()
1230        ) + model_class._composed_schemas.get("anyOf", ())
1231        ancestor_classes = model_class._composed_schemas.get("allOf", ())
1232        possible_classes = descendant_classes + ancestor_classes
1233        for cls in possible_classes:
1234            # Check if the schema has inherited discriminators.
1235            if hasattr(cls, "discriminator") and cls.discriminator is not None:
1236                used_model_class = get_discriminator_class(
1237                    cls, discr_name, discr_value, cls_visited
1238                )
1239                if used_model_class is not None:
1240                    return used_model_class
1241    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):
1244def deserialize_model(
1245    model_data, model_class, path_to_item, check_type, configuration, spec_property_naming
1246):
1247    """Deserializes model_data to model instance.
1248
1249    Args:
1250        model_data (int/str/float/bool/none_type/list/dict): data to instantiate the model
1251        model_class (OpenApiModel): the model class
1252        path_to_item (list): path to the model in the received data
1253        check_type (bool): whether to check the data tupe for the values in
1254            the model
1255        configuration (Configuration): the instance to use to convert files
1256        spec_property_naming (bool): True if the variable names in the input
1257            data are serialized names as specified in the OpenAPI document.
1258            False if the variables names in the input data are python
1259            variable names in PEP-8 snake case.
1260
1261    Returns:
1262        model instance
1263
1264    Raise:
1265        PineconeApiTypeError
1266        PineconeApiValueError
1267        PineconeApiKeyError
1268    """
1269
1270    kw_args = dict(
1271        _check_type=check_type,
1272        _path_to_item=path_to_item,
1273        _configuration=configuration,
1274        _spec_property_naming=spec_property_naming,
1275    )
1276
1277    if issubclass(model_class, ModelSimple):
1278        return model_class._new_from_openapi_data(model_data, **kw_args)
1279    elif isinstance(model_data, list):
1280        return model_class._new_from_openapi_data(*model_data, **kw_args)
1281    if isinstance(model_data, dict):
1282        kw_args.update(model_data)
1283        return model_class._new_from_openapi_data(**kw_args)
1284    elif isinstance(model_data, PRIMITIVE_TYPES):
1285        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:

PineconeApiTypeError PineconeApiValueError PineconeApiKeyError

def deserialize_file(response_data, configuration, content_disposition=None):
1288def deserialize_file(response_data, configuration, content_disposition=None):
1289    """Deserializes body to file
1290
1291    Saves response body into a file in a temporary folder,
1292    using the filename from the `Content-Disposition` header if provided.
1293
1294    Args:
1295        param response_data (str):  the file data to write
1296        configuration (Configuration): the instance to use to convert files
1297
1298    Keyword Args:
1299        content_disposition (str):  the value of the Content-Disposition
1300            header
1301
1302    Returns:
1303        (file_type): the deserialized file which is open
1304            The user is responsible for closing and reading the file
1305    """
1306    fd, path = tempfile.mkstemp(dir=configuration.temp_folder_path)
1307    os.close(fd)
1308    os.remove(path)
1309
1310    if content_disposition:
1311        filename = re.search(r'filename=[\'"]?([^\'"\s]+)[\'"]?', content_disposition).group(1)
1312        path = os.path.join(os.path.dirname(path), filename)
1313
1314    with open(path, "wb") as f:
1315        if isinstance(response_data, str):
1316            # change str to bytes so we can write it
1317            response_data = response_data.encode("utf-8")
1318        f.write(response_data)
1319
1320    f = open(path, "rb")
1321    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):
1324def attempt_convert_item(
1325    input_value,
1326    valid_classes,
1327    path_to_item,
1328    configuration,
1329    spec_property_naming,
1330    key_type=False,
1331    must_convert=False,
1332    check_type=True,
1333):
1334    """
1335    Args:
1336        input_value (any): the data to convert
1337        valid_classes (any): the classes that are valid
1338        path_to_item (list): the path to the item to convert
1339        configuration (Configuration): the instance to use to convert files
1340        spec_property_naming (bool): True if the variable names in the input
1341            data are serialized names as specified in the OpenAPI document.
1342            False if the variables names in the input data are python
1343            variable names in PEP-8 snake case.
1344        key_type (bool): if True we need to convert a key type (not supported)
1345        must_convert (bool): if True we must convert
1346        check_type (bool): if True we check the type or the returned data in
1347            ModelComposed/ModelNormal/ModelSimple instances
1348
1349    Returns:
1350        instance (any) the fixed item
1351
1352    Raises:
1353        PineconeApiTypeError
1354        PineconeApiValueError
1355        PineconeApiKeyError
1356    """
1357    valid_classes_ordered = order_response_types(valid_classes)
1358    valid_classes_coercible = remove_uncoercible(
1359        valid_classes_ordered, input_value, spec_property_naming
1360    )
1361    if not valid_classes_coercible or key_type:
1362        # we do not handle keytype errors, json will take care
1363        # of this for us
1364        if configuration is None or not configuration.discard_unknown_keys:
1365            raise get_type_error(input_value, path_to_item, valid_classes, key_type=key_type)
1366    for valid_class in valid_classes_coercible:
1367        try:
1368            if issubclass(valid_class, OpenApiModel):
1369                return deserialize_model(
1370                    input_value,
1371                    valid_class,
1372                    path_to_item,
1373                    check_type,
1374                    configuration,
1375                    spec_property_naming,
1376                )
1377            elif valid_class == file_type:
1378                return deserialize_file(input_value, configuration)
1379            return deserialize_primitive(input_value, valid_class, path_to_item)
1380        except (PineconeApiTypeError, PineconeApiValueError, PineconeApiKeyError) as conversion_exc:
1381            if must_convert:
1382                raise conversion_exc
1383            # if we have conversion errors when must_convert == False
1384            # we ignore the exception and move on to the next class
1385            continue
1386    # we were unable to convert, must_convert == False
1387    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:
  • PineconeApiTypeError
  • PineconeApiValueError
  • PineconeApiKeyError
def is_type_nullable(input_type):
1390def is_type_nullable(input_type):
1391    """
1392    Returns true if None is an allowed value for the specified input_type.
1393
1394    A type is nullable if at least one of the following conditions is true:
1395    1. The OAS 'nullable' attribute has been specified,
1396    1. The type is the 'null' type,
1397    1. The type is a anyOf/oneOf composed schema, and a child schema is
1398       the 'null' type.
1399    Args:
1400        input_type (type): the class of the input_value that we are
1401            checking
1402    Returns:
1403        bool
1404    """
1405    if input_type is none_type:
1406        return True
1407    if issubclass(input_type, OpenApiModel) and input_type._nullable:
1408        return True
1409    if issubclass(input_type, ModelComposed):
1410        # If oneOf/anyOf, check if the 'null' type is one of the allowed types.
1411        for t in input_type._composed_schemas.get("oneOf", ()):
1412            if is_type_nullable(t):
1413                return True
1414        for t in input_type._composed_schemas.get("anyOf", ()):
1415            if is_type_nullable(t):
1416                return True
1417    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):
1420def is_valid_type(input_class_simple, valid_classes):
1421    """
1422    Args:
1423        input_class_simple (class): the class of the input_value that we are
1424            checking
1425        valid_classes (tuple): the valid classes that the current item
1426            should be
1427    Returns:
1428        bool
1429    """
1430    valid_type = input_class_simple in valid_classes
1431    if not valid_type and (
1432        issubclass(input_class_simple, OpenApiModel) or input_class_simple is none_type
1433    ):
1434        for valid_class in valid_classes:
1435            if input_class_simple is none_type and is_type_nullable(valid_class):
1436                # Schema is oneOf/anyOf and the 'null' type is one of the allowed types.
1437                return True
1438            if not (issubclass(valid_class, OpenApiModel) and valid_class.discriminator):
1439                continue
1440            discr_propertyname_py = list(valid_class.discriminator.keys())[0]
1441            discriminator_classes = valid_class.discriminator[discr_propertyname_py].values()
1442            valid_type = is_valid_type(input_class_simple, discriminator_classes)
1443            if valid_type:
1444                return True
1445    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):
1448def validate_and_convert_types(
1449    input_value,
1450    required_types_mixed,
1451    path_to_item,
1452    spec_property_naming,
1453    _check_type,
1454    configuration=None,
1455):
1456    """Raises a TypeError is there is a problem, otherwise returns value
1457
1458    Args:
1459        input_value (any): the data to validate/convert
1460        required_types_mixed (list/dict/tuple): A list of
1461            valid classes, or a list tuples of valid classes, or a dict where
1462            the value is a tuple of value classes
1463        path_to_item: (list) the path to the data being validated
1464            this stores a list of keys or indices to get to the data being
1465            validated
1466        spec_property_naming (bool): True if the variable names in the input
1467            data are serialized names as specified in the OpenAPI document.
1468            False if the variables names in the input data are python
1469            variable names in PEP-8 snake case.
1470        _check_type: (boolean) if true, type will be checked and conversion
1471            will be attempted.
1472        configuration: (Configuration): the configuration class to use
1473            when converting file_type items.
1474            If passed, conversion will be attempted when possible
1475            If not passed, no conversions will be attempted and
1476            exceptions will be raised
1477
1478    Returns:
1479        the correctly typed value
1480
1481    Raises:
1482        PineconeApiTypeError
1483    """
1484    results = get_required_type_classes(required_types_mixed, spec_property_naming)
1485    valid_classes, child_req_types_by_current_type = results
1486
1487    input_class_simple = get_simple_class(input_value)
1488    valid_type = is_valid_type(input_class_simple, valid_classes)
1489    if not valid_type:
1490        if configuration:
1491            # if input_value is not valid_type try to convert it
1492            converted_instance = attempt_convert_item(
1493                input_value,
1494                valid_classes,
1495                path_to_item,
1496                configuration,
1497                spec_property_naming,
1498                key_type=False,
1499                must_convert=True,
1500                check_type=_check_type,
1501            )
1502            return converted_instance
1503        else:
1504            raise get_type_error(input_value, path_to_item, valid_classes, key_type=False)
1505
1506    # input_value's type is in valid_classes
1507    if len(valid_classes) > 1 and configuration:
1508        # there are valid classes which are not the current class
1509        valid_classes_coercible = remove_uncoercible(
1510            valid_classes, input_value, spec_property_naming, must_convert=False
1511        )
1512        if valid_classes_coercible:
1513            converted_instance = attempt_convert_item(
1514                input_value,
1515                valid_classes_coercible,
1516                path_to_item,
1517                configuration,
1518                spec_property_naming,
1519                key_type=False,
1520                must_convert=False,
1521                check_type=_check_type,
1522            )
1523            return converted_instance
1524
1525    if child_req_types_by_current_type == {}:
1526        # all types are of the required types and there are no more inner
1527        # variables left to look at
1528        return input_value
1529    inner_required_types = child_req_types_by_current_type.get(type(input_value))
1530    if inner_required_types is None:
1531        # for this type, there are not more inner variables left to look at
1532        return input_value
1533    if isinstance(input_value, list):
1534        if input_value == []:
1535            # allow an empty list
1536            return input_value
1537        for index, inner_value in enumerate(input_value):
1538            inner_path = list(path_to_item)
1539            inner_path.append(index)
1540            input_value[index] = validate_and_convert_types(
1541                inner_value,
1542                inner_required_types,
1543                inner_path,
1544                spec_property_naming,
1545                _check_type,
1546                configuration=configuration,
1547            )
1548    elif isinstance(input_value, dict):
1549        if input_value == {}:
1550            # allow an empty dict
1551            return input_value
1552        for inner_key, inner_val in input_value.items():
1553            inner_path = list(path_to_item)
1554            inner_path.append(inner_key)
1555            if get_simple_class(inner_key) is not str:
1556                raise get_type_error(inner_key, inner_path, valid_classes, key_type=True)
1557            input_value[inner_key] = validate_and_convert_types(
1558                inner_val,
1559                inner_required_types,
1560                inner_path,
1561                spec_property_naming,
1562                _check_type,
1563                configuration=configuration,
1564            )
1565    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:
  • PineconeApiTypeError
def model_to_dict(model_instance, serialize=True):
1568def model_to_dict(model_instance, serialize=True):
1569    """Returns the model properties as a dict
1570
1571    Args:
1572        model_instance (one of your model instances): the model instance that
1573            will be converted to a dict.
1574
1575    Keyword Args:
1576        serialize (bool): if True, the keys in the dict will be values from
1577            attribute_map
1578    """
1579    result = {}
1580
1581    model_instances = [model_instance]
1582    if hasattr(model_instance, "_composed_schemas") and model_instance._composed_schemas:
1583        model_instances.extend(model_instance._composed_instances)
1584    seen_json_attribute_names = set()
1585    used_fallback_python_attribute_names = set()
1586    py_to_json_map = {}
1587    for model_instance in model_instances:
1588        for attr, value in model_instance._data_store.items():
1589            if serialize:
1590                # we use get here because additional property key names do not
1591                # exist in attribute_map
1592                try:
1593                    attr = model_instance.attribute_map[attr]
1594                    py_to_json_map.update(model_instance.attribute_map)
1595                    seen_json_attribute_names.add(attr)
1596                except KeyError:
1597                    used_fallback_python_attribute_names.add(attr)
1598            if isinstance(value, list):
1599                if not value:
1600                    # empty list or None
1601                    result[attr] = value
1602                else:
1603                    res = []
1604                    for v in value:
1605                        if isinstance(v, PRIMITIVE_TYPES) or v is None:
1606                            res.append(v)
1607                        elif isinstance(v, ModelSimple):
1608                            res.append(v.value)
1609                        else:
1610                            res.append(model_to_dict(v, serialize=serialize))
1611                    result[attr] = res
1612            elif isinstance(value, dict):
1613                result[attr] = dict(
1614                    map(
1615                        lambda item: (
1616                            (item[0], model_to_dict(item[1], serialize=serialize))
1617                            if hasattr(item[1], "_data_store")
1618                            else item
1619                        ),
1620                        value.items(),
1621                    )
1622                )
1623            elif isinstance(value, ModelSimple):
1624                result[attr] = value.value
1625            elif hasattr(value, "_data_store"):
1626                result[attr] = model_to_dict(value, serialize=serialize)
1627            else:
1628                result[attr] = value
1629    if serialize:
1630        for python_key in used_fallback_python_attribute_names:
1631            json_key = py_to_json_map.get(python_key)
1632            if json_key is None:
1633                continue
1634            if python_key == json_key:
1635                continue
1636            json_key_assigned_no_need_for_python_key = json_key in seen_json_attribute_names
1637            if json_key_assigned_no_need_for_python_key:
1638                del result[python_key]
1639
1640    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):
1643def type_error_message(var_value=None, var_name=None, valid_classes=None, key_type=None):
1644    """
1645    Keyword Args:
1646        var_value (any): the variable which has the type_error
1647        var_name (str): the name of the variable which has the typ error
1648        valid_classes (tuple): the accepted classes for current_item's
1649                                  value
1650        key_type (bool): False if our value is a value in a dict
1651                         True if it is a key in a dict
1652                         False if our item is an item in a list
1653    """
1654    key_or_value = "value"
1655    if key_type:
1656        key_or_value = "key"
1657    valid_classes_phrase = get_valid_classes_phrase(valid_classes)
1658    msg = "Invalid type for variable '{0}'. Required {1} type {2} and passed type was {3}".format(
1659        var_name, key_or_value, valid_classes_phrase, type(var_value).__name__
1660    )
1661    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):
1664def get_valid_classes_phrase(input_classes):
1665    """Returns a string phrase describing what types are allowed"""
1666    all_classes = list(input_classes)
1667    all_classes = sorted(all_classes, key=lambda cls: cls.__name__)
1668    all_class_names = [cls.__name__ for cls in all_classes]
1669    if len(all_class_names) == 1:
1670        return "is {0}".format(all_class_names[0])
1671    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):
1674def get_allof_instances(self, model_args, constant_args):
1675    """
1676    Args:
1677        self: the class we are handling
1678        model_args (dict): var_name to var_value
1679            used to make instances
1680        constant_args (dict):
1681            metadata arguments:
1682            _check_type
1683            _path_to_item
1684            _spec_property_naming
1685            _configuration
1686            _visited_composed_classes
1687
1688    Returns
1689        composed_instances (list)
1690    """
1691    composed_instances = []
1692    for allof_class in self._composed_schemas["allOf"]:
1693        try:
1694            allof_instance = allof_class(**model_args, **constant_args)
1695            composed_instances.append(allof_instance)
1696        except Exception as ex:
1697            raise PineconeApiValueError(
1698                "Invalid inputs given to generate an instance of '%s'. The "
1699                "input data was invalid for the allOf schema '%s' in the composed "
1700                "schema '%s'. Error=%s"
1701                % (allof_class.__name__, allof_class.__name__, self.__class__.__name__, str(ex))
1702            ) from ex
1703    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):
1706def get_oneof_instance(cls, model_kwargs, constant_kwargs, model_arg=None):
1707    """
1708    Find the oneOf schema that matches the input data (e.g. payload).
1709    If exactly one schema matches the input data, an instance of that schema
1710    is returned.
1711    If zero or more than one schema match the input data, an exception is raised.
1712    In OAS 3.x, the payload MUST, by validation, match exactly one of the
1713    schemas described by oneOf.
1714
1715    Args:
1716        cls: the class we are handling
1717        model_kwargs (dict): var_name to var_value
1718            The input data, e.g. the payload that must match a oneOf schema
1719            in the OpenAPI document.
1720        constant_kwargs (dict): var_name to var_value
1721            args that every model requires, including configuration, server
1722            and path to item.
1723
1724    Kwargs:
1725        model_arg: (int, float, bool, str, ModelSimple, None):
1726            the value to assign to a primitive class or ModelSimple class
1727            Notes:
1728            - this is only passed in when oneOf includes types which are not object
1729            - None is used to suppress handling of model_arg, nullable models are handled in __new__
1730
1731    Returns
1732        oneof_instance (instance)
1733    """
1734    if len(cls._composed_schemas["oneOf"]) == 0:
1735        return None
1736
1737    oneof_instances = []
1738    # Iterate over each oneOf schema and determine if the input data
1739    # matches the oneOf schemas.
1740    for oneof_class in cls._composed_schemas["oneOf"]:
1741        # The composed oneOf schema allows the 'null' type and the input data
1742        # is the null value. This is a OAS >= 3.1 feature.
1743        if oneof_class is none_type:
1744            # skip none_types because we are deserializing dict data.
1745            # none_type deserialization is handled in the __new__ method
1746            continue
1747
1748        single_value_input = allows_single_value_input(oneof_class)
1749
1750        try:
1751            if not single_value_input:
1752                oneof_instance = oneof_class(**model_kwargs, **constant_kwargs)
1753            else:
1754                if issubclass(oneof_class, ModelSimple):
1755                    oneof_instance = oneof_class(model_arg, **constant_kwargs)
1756                elif oneof_class in PRIMITIVE_TYPES:
1757                    oneof_instance = validate_and_convert_types(
1758                        model_arg,
1759                        (oneof_class,),
1760                        constant_kwargs["_path_to_item"],
1761                        constant_kwargs["_spec_property_naming"],
1762                        constant_kwargs["_check_type"],
1763                        configuration=constant_kwargs["_configuration"],
1764                    )
1765            oneof_instances.append(oneof_instance)
1766        except Exception:
1767            pass
1768    if len(oneof_instances) == 0:
1769        raise PineconeApiValueError(
1770            "Invalid inputs given to generate an instance of %s. None "
1771            "of the oneOf schemas matched the input data." % cls.__name__
1772        )
1773    elif len(oneof_instances) > 1:
1774        raise PineconeApiValueError(
1775            "Invalid inputs given to generate an instance of %s. Multiple "
1776            "oneOf schemas matched the inputs, but a max of one is allowed." % cls.__name__
1777        )
1778    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, 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):
1781def get_anyof_instances(self, model_args, constant_args):
1782    """
1783    Args:
1784        self: the class we are handling
1785        model_args (dict): var_name to var_value
1786            The input data, e.g. the payload that must match at least one
1787            anyOf child schema in the OpenAPI document.
1788        constant_args (dict): var_name to var_value
1789            args that every model requires, including configuration, server
1790            and path to item.
1791
1792    Returns
1793        anyof_instances (list)
1794    """
1795    anyof_instances = []
1796    if len(self._composed_schemas["anyOf"]) == 0:
1797        return anyof_instances
1798
1799    for anyof_class in self._composed_schemas["anyOf"]:
1800        # The composed oneOf schema allows the 'null' type and the input data
1801        # is the null value. This is a OAS >= 3.1 feature.
1802        if anyof_class is none_type:
1803            # skip none_types because we are deserializing dict data.
1804            # none_type deserialization is handled in the __new__ method
1805            continue
1806
1807        try:
1808            anyof_instance = anyof_class(**model_args, **constant_args)
1809            anyof_instances.append(anyof_instance)
1810        except Exception:
1811            pass
1812    if len(anyof_instances) == 0:
1813        raise PineconeApiValueError(
1814            "Invalid inputs given to generate an instance of %s. None of the "
1815            "anyOf schemas matched the inputs." % self.__class__.__name__
1816        )
1817    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):
1820def get_discarded_args(self, composed_instances, model_args):
1821    """
1822    Gathers the args that were discarded by configuration.discard_unknown_keys
1823    """
1824    model_arg_keys = model_args.keys()
1825    discarded_args = set()
1826    # arguments passed to self were already converted to python names
1827    # before __init__ was called
1828    for instance in composed_instances:
1829        if instance.__class__ in self._composed_schemas["allOf"]:
1830            try:
1831                keys = instance.to_dict().keys()
1832                discarded_keys = model_args - keys
1833                discarded_args.update(discarded_keys)
1834            except Exception:
1835                # allOf integer schema will throw exception
1836                pass
1837        else:
1838            try:
1839                all_keys = set(model_to_dict(instance, serialize=False).keys())
1840                js_keys = model_to_dict(instance, serialize=True).keys()
1841                all_keys.update(js_keys)
1842                discarded_keys = model_arg_keys - all_keys
1843                discarded_args.update(discarded_keys)
1844            except Exception:
1845                # allOf integer schema will throw exception
1846                pass
1847    return discarded_args

Gathers the args that were discarded by configuration.discard_unknown_keys

def validate_get_composed_info(constant_args, model_args, self):
1850def validate_get_composed_info(constant_args, model_args, self):
1851    """
1852    For composed schemas, generate schema instances for
1853    all schemas in the oneOf/anyOf/allOf definition. If additional
1854    properties are allowed, also assign those properties on
1855    all matched schemas that contain additionalProperties.
1856    Openapi schemas are python classes.
1857
1858    Exceptions are raised if:
1859    - 0 or > 1 oneOf schema matches the model_args input data
1860    - no anyOf schema matches the model_args input data
1861    - any of the allOf schemas do not match the model_args input data
1862
1863    Args:
1864        constant_args (dict): these are the args that every model requires
1865        model_args (dict): these are the required and optional spec args that
1866            were passed in to make this model
1867        self (class): the class that we are instantiating
1868            This class contains self._composed_schemas
1869
1870    Returns:
1871        composed_info (list): length three
1872            composed_instances (list): the composed instances which are not
1873                self
1874            var_name_to_model_instances (dict): a dict going from var_name
1875                to the model_instance which holds that var_name
1876                the model_instance may be self or an instance of one of the
1877                classes in self.composed_instances()
1878            additional_properties_model_instances (list): a list of the
1879                model instances which have the property
1880                additional_properties_type. This list can include self
1881    """
1882    # create composed_instances
1883    composed_instances = []
1884    allof_instances = get_allof_instances(self, model_args, constant_args)
1885    composed_instances.extend(allof_instances)
1886    oneof_instance = get_oneof_instance(self.__class__, model_args, constant_args)
1887    if oneof_instance is not None:
1888        composed_instances.append(oneof_instance)
1889    anyof_instances = get_anyof_instances(self, model_args, constant_args)
1890    composed_instances.extend(anyof_instances)
1891    """
1892    set additional_properties_model_instances
1893    additional properties must be evaluated at the schema level
1894    so self's additional properties are most important
1895    If self is a composed schema with:
1896    - no properties defined in self
1897    - additionalProperties: False
1898    Then for object payloads every property is an additional property
1899    and they are not allowed, so only empty dict is allowed
1900
1901    Properties must be set on all matching schemas
1902    so when a property is assigned toa composed instance, it must be set on all
1903    composed instances regardless of additionalProperties presence
1904    keeping it to prevent breaking changes in v5.0.1
1905    TODO remove cls._additional_properties_model_instances in 6.0.0
1906    """
1907    additional_properties_model_instances = []
1908    if self.additional_properties_type is not None:
1909        additional_properties_model_instances = [self]
1910
1911    """
1912    no need to set properties on self in here, they will be set in __init__
1913    By here all composed schema oneOf/anyOf/allOf instances have their properties set using
1914    model_args
1915    """
1916    discarded_args = get_discarded_args(self, composed_instances, model_args)
1917
1918    # map variable names to composed_instances
1919    var_name_to_model_instances = {}
1920    for prop_name in model_args:
1921        if prop_name not in discarded_args:
1922            var_name_to_model_instances[prop_name] = [self] + composed_instances
1923
1924    return [
1925        composed_instances,
1926        var_name_to_model_instances,
1927        additional_properties_model_instances,
1928        discarded_args,
1929    ]

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