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 ]
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
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
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
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
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
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
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
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
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
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
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
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
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
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.
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
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
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
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
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
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.
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.
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.
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
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
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
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
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).
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 )
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
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.
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
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
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
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:
- The OAS 'nullable' attribute has been specified,
- The type is the 'null' type,
- 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
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
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
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
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
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
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)
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)
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)
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
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