Skip to content

Commit 7d615ce

Browse files
api-clients-generation-pipeline[bot]therveci.datadog-api-spec
authored
Improve resiliency of the Python SDK (#531)
* Handle oneOf and enum errors * Add cassettes * Support replay-only * Handle multiple oneOfs * Move the enum error handling in model utils * Add tests, remove cov options * Fix rebase * Add unparsed check * Regenerate client from commit 9684c06 of spec repo Co-authored-by: Thomas Hervé <[email protected]> Co-authored-by: api-clients-generation-pipeline[bot] <54105614+api-clients-generation-pipeline[bot]@users.noreply.github.com> Co-authored-by: ci.datadog-api-spec <[email protected]>
1 parent 220d1fe commit 7d615ce

11 files changed

+489
-48
lines changed

.apigentools-info

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
"spec_versions": {
55
"v1": {
66
"apigentools_version": "1.4.1.dev11",
7-
"regenerated": "2021-08-09 14:31:45.996631",
8-
"spec_repo_commit": "f7db18b"
7+
"regenerated": "2021-08-10 08:29:52.303572",
8+
"spec_repo_commit": "9684c06"
99
},
1010
"v2": {
1111
"apigentools_version": "1.4.1.dev11",
12-
"regenerated": "2021-08-09 14:32:10.644831",
13-
"spec_repo_commit": "f7db18b"
12+
"regenerated": "2021-08-10 08:30:15.608867",
13+
"spec_repo_commit": "9684c06"
1414
}
1515
}
1616
}

.generator/templates/model_templates/method_set_attribute.mustache

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,12 @@
3636
value, required_types_mixed, path_to_item, self._spec_property_naming,
3737
self._check_type, configuration=self._configuration)
3838
if (name,) in self.allowed_values:
39-
check_allowed_values(
40-
self.allowed_values,
41-
(name,),
42-
value
43-
)
39+
try:
40+
check_allowed_values(self.allowed_values, (name,), value)
41+
except ApiValueError:
42+
self.__dict__["_data_store"][name] = value
43+
self._unparsed = True
44+
return
4445
if (name,) in self.validations:
4546
check_validations(
4647
self.validations,
@@ -49,3 +50,5 @@
4950
self._configuration
5051
)
5152
self.__dict__['_data_store'][name] = value
53+
if isinstance(value, OpenApiModel) and value._unparsed:
54+
self._unparsed = True

.generator/templates/model_utils.mustache

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ class OpenApiModel(object):
355355
self._path_to_item = _path_to_item
356356
self._configuration = _configuration
357357
self._visited_composed_classes = _visited_composed_classes + (self.__class__,)
358+
self._unparsed = False
358359

359360
@classmethod
360361
def _from_openapi_data(cls, kwargs):
@@ -396,6 +397,7 @@ class ModelSimple(OpenApiModel):
396397
'_path_to_item',
397398
'_configuration',
398399
'_visited_composed_classes',
400+
'_unparsed',
399401
])
400402

401403
{{> model_templates/methods_setattr_getattr_normal }}
@@ -414,6 +416,7 @@ class ModelNormal(OpenApiModel):
414416
'_path_to_item',
415417
'_configuration',
416418
'_visited_composed_classes',
419+
'_unparsed',
417420
])
418421

419422
{{> model_templates/methods_setattr_getattr_normal }}
@@ -484,6 +487,7 @@ class ModelComposed(OpenApiModel):
484487
'_composed_instances',
485488
'_var_name_to_model_instances',
486489
'_additional_properties_model_instances',
490+
'_unparsed',
487491
])
488492

489493
def __init__(self, kwargs):
@@ -1654,21 +1658,12 @@ def get_oneof_instance(cls, model_kwargs, constant_kwargs, model_arg=None):
16541658
constant_kwargs['_check_type'],
16551659
configuration=constant_kwargs['_configuration']
16561660
)
1657-
oneof_instances.append(oneof_instance)
1661+
if not oneof_instance._unparsed:
1662+
oneof_instances.append(oneof_instance)
16581663
except Exception:
16591664
pass
1660-
if len(oneof_instances) == 0:
1661-
raise ApiValueError(
1662-
"Invalid inputs given to generate an instance of %s. None "
1663-
"of the oneOf schemas matched the input data." %
1664-
cls.__name__
1665-
)
1666-
elif len(oneof_instances) > 1:
1667-
raise ApiValueError(
1668-
"Invalid inputs given to generate an instance of %s. Multiple "
1669-
"oneOf schemas matched the inputs, but a max of one is allowed." %
1670-
cls.__name__
1671-
)
1665+
if len(oneof_instances) != 1:
1666+
return UnparsedObject(**model_kwargs)
16721667
return oneof_instances[0]
16731668

16741669

@@ -1822,3 +1817,40 @@ def validate_get_composed_info(constant_args, model_args, self):
18221817
additional_properties_model_instances,
18231818
discarded_args
18241819
]
1820+
1821+
1822+
class UnparsedObject(ModelNormal):
1823+
"""A model for an oneOf we don't know about."""
1824+
1825+
allowed_values = {}
1826+
1827+
validations = {}
1828+
1829+
additional_properties_type = None
1830+
1831+
_nullable = False
1832+
1833+
openapi_types = {}
1834+
1835+
discriminator = None
1836+
1837+
attribute_map = {}
1838+
1839+
_composed_schemas = {}
1840+
1841+
required_properties = set(
1842+
[
1843+
"_data_store",
1844+
"_unparsed",
1845+
]
1846+
)
1847+
1848+
@convert_js_args_to_python_args
1849+
def __init__(self, **kwargs):
1850+
1851+
self._data_store = {}
1852+
self._unparsed = True
1853+
1854+
for var_name, var_value in kwargs.items():
1855+
self.__dict__[var_name] = var_value
1856+
self.__dict__["_data_store"][var_name] = var_value

setup.cfg

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ exclude = tests
6767
where=src
6868

6969
[tool:pytest]
70-
addopts = --cov=datadog_api_client --cov-config .coveragerc
7170
# addopts = --black --cov=datadog_api_client --cov-config .coveragerc --cov-report=term-missing
7271

7372
[flake8]

src/datadog_api_client/v1/model_utils.py

Lines changed: 53 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/datadog_api_client/v2/model_utils.py

Lines changed: 53 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/conftest.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ def pytest_bdd_apply_tag(tag, function):
9191
if not _disable_recording():
9292
# ignore integration-only scenarios if the recording is enabled
9393
skip_tags.add("integration-only")
94+
if os.getenv("RECORD", "false").lower() != "false":
95+
skip_tags.add("replay-only")
9496
if tag in skip_tags:
9597
marker = pytest.mark.skip(reason=f"skipped because '{tag}' in {skip_tags}")
9698
marker(function)

0 commit comments

Comments
 (0)