Skip to content

Commit 5fdcab6

Browse files
HantingZhang2ci.datadog-api-specapi-clients-generation-pipeline[bot]
authored
Add UUID format support (#1743)
* change formatter * Adds UUID type * change uuid order * pre-commit fixes * Update api template * Update openapi.yaml remove added format * pre-commit fixes * add de/serialization tests * pre-commit fixes * test if adding format * pre-commit fixes * remove open api change * Raise the error instead of print * pre-commit fixes --------- Co-authored-by: ci.datadog-api-spec <[email protected]> Co-authored-by: api-clients-generation-pipeline[bot] <54105614+api-clients-generation-pipeline[bot]@users.noreply.github.com>
1 parent 45c4c4d commit 5fdcab6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+162
-56
lines changed

.generator/src/generator/formatter.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import keyword
77
import warnings
88
import re
9-
9+
from uuid import UUID
1010
import dateutil.parser
1111
import m2r2
1212

@@ -296,6 +296,11 @@ def format_datetime(x):
296296
if "tzoffset" in result:
297297
imports["dateutil.tz"].add("tzoffset")
298298
return result
299+
300+
def format_uuid(x):
301+
imports["uuid"].add("UUID")
302+
result = repr(UUID(x))
303+
return result
299304

300305
formatter = {
301306
"double": lambda s: repr(float(s)),
@@ -305,7 +310,8 @@ def format_datetime(x):
305310
"date-time": format_datetime,
306311
"binary": lambda s: f'open("{s}", "rb")',
307312
"email": repr,
308-
None: repr,
313+
"uuid": format_uuid,
314+
None: repr,
309315
}[schema.get("format")]
310316

311317
# TODO format date and datetime

.generator/src/generator/openapi.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def basic_type_to_python(type_, schema, typing=False):
2424
if type_ is None:
2525
if typing:
2626
return "Any"
27-
return "bool, date, datetime, dict, float, int, list, str, none_type"
27+
return "bool, date, datetime, dict, float, int, list, str, UUID, none_type"
2828
if type_ == "integer":
2929
return "int"
3030
elif type_ == "number":
@@ -35,6 +35,8 @@ def basic_type_to_python(type_, schema, typing=False):
3535
return "datetime"
3636
elif format_ == "binary":
3737
return "file_type"
38+
elif format_ == "uuid":
39+
return "UUID"
3840
return "str"
3941
elif type_ == "boolean":
4042
return "bool"

.generator/src/generator/templates/api.j2

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ from {{ package }}.model_utils import (
1616
none_type,
1717
UnsetType,
1818
unset,
19+
UUID,
1920
)
2021
{%- for model in get_api_models(operations) %}
2122
from {{ package }}.{{ version }}.model.{{ model|safe_snake_case }} import {{ model }}

.generator/src/generator/templates/api_client.j2

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import warnings
77
import multiprocessing
88
from multiprocessing.pool import ThreadPool
99
from datetime import date, datetime
10+
from uuid import UUID
1011
import io
1112
import os
1213
import re
@@ -177,6 +178,8 @@ class ApiClient:
177178
if getattr(obj, "tzinfo", None) is not None:
178179
return obj.isoformat()
179180
return "{}Z".format(obj.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3])
181+
elif isinstance(obj, UUID ):
182+
return str(obj)
180183
elif isinstance(obj, ModelSimple):
181184
return cls.sanitize_for_serialization(obj.value)
182185
elif isinstance(obj, (list, tuple)):

.generator/src/generator/templates/model.j2

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ from {{ package }}.model_utils import (
1515
none_type,
1616
unset,
1717
UnsetType,
18+
UUID,
1819
)
1920

2021
{% if "enum" in model -%}

.generator/src/generator/templates/model_utils.j2

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from contextlib import suppress
44
from datetime import date, datetime
5+
from uuid import UUID
56
import enum
67
import inspect
78
import io
@@ -52,7 +53,7 @@ class cached_property(object):
5253
return result
5354

5455

55-
PRIMITIVE_TYPES = (list, float, int, bool, datetime, date, str, file_type)
56+
PRIMITIVE_TYPES = (list, float, int, bool, datetime, date, str, UUID, file_type)
5657

5758

5859
def allows_single_value_input(cls):
@@ -567,7 +568,8 @@ COERCION_INDEX_BY_TYPE = {
567568
datetime: 9,
568569
date: 10,
569570
str: 11,
570-
file_type: 12, # 'file_type' is an alias for the built-in 'file' or 'io.IOBase' type.
571+
UUID: 12,
572+
file_type: 13, # 'file_type' is an alias for the built-in 'file' or 'io.IOBase' type.
571573
}
572574

573575
# these are used to limit what type conversions we try to do
@@ -576,6 +578,7 @@ COERCION_INDEX_BY_TYPE = {
576578
UPCONVERSION_TYPE_PAIRS = (
577579
(str, datetime),
578580
(str, date),
581+
(str, UUID),
579582
(int, float), # A float may be serialized as an integer, e.g. '3' is a valid serialized float.
580583
(list, ModelComposed),
581584
(dict, ModelComposed),
@@ -624,6 +627,7 @@ COERCIBLE_TYPE_PAIRS = {
624627
# (str, float),
625628
(str, datetime),
626629
(str, date),
630+
(str, UUID),
627631
# (int, str),
628632
# (float, str),
629633
(str, file_type),
@@ -664,6 +668,8 @@ def get_simple_class(input_value):
664668
return date
665669
elif isinstance(input_value, str):
666670
return str
671+
elif isinstance(input_value, UUID):
672+
return UUID
667673
return type(input_value)
668674

669675

@@ -675,7 +681,7 @@ def check_allowed_values(allowed_values, input_variable, input_values):
675681
:type input_variable: str
676682
:param input_values: The values that we are checking to see if they are in
677683
allowed_values.
678-
:type input_values: list/str/int/float/date/datetime
684+
:type input_values: list/str/int/float/date/datetime/uuid
679685
"""
680686
if isinstance(input_values, list) and not set(input_values).issubset(allowed_values):
681687
invalid_values = (", ".join(map(str, set(input_values) - allowed_values)),)
@@ -721,7 +727,7 @@ def check_validations(validations, input_variable, input_values, configuration=N
721727
:param input_variable: The name of the input variable.
722728
:type input_variable: str
723729
:param input_values: The values that we are checking.
724-
:type input_values: list/str/int/float/date/datetime
730+
:type input_values: list/str/int/float/date/datetime/uuid
725731
:param configuration: The configuration instance.
726732
:type configuration: Configuration
727733
"""
@@ -1014,7 +1020,7 @@ def deserialize_primitive(data, klass, path_to_item):
10141020
:param klass: The class to convert to.
10151021
:type klass: str/class
10161022

1017-
:rtype: int, float, str, bool, date, datetime
1023+
:rtype: int, float, str, bool, date, datetime, UUID
10181024
"""
10191025
additional_message = ""
10201026
try:
@@ -1042,11 +1048,18 @@ def deserialize_primitive(data, klass, path_to_item):
10421048
raise ValueError("This is not a date")
10431049
return parse(data).date()
10441050
else:
1045-
converted_value = klass(data)
1051+
if isinstance(data, str) and klass == UUID:
1052+
try:
1053+
converted_value = UUID(data)
1054+
except ValueError:
1055+
raise ValueError("This is not an UUID")
10461056
if isinstance(data, str) and klass == float:
1057+
converted_value = float(data)
10471058
if str(converted_value) != data:
10481059
# '7' -> 7.0 -> '7.0' != '7'
10491060
raise ValueError("This is not a float")
1061+
else:
1062+
converted_value = klass(data)
10501063
return converted_value
10511064
except (OverflowError, ValueError) as ex:
10521065
# parse can raise OverflowError
@@ -1479,7 +1492,7 @@ def get_oneof_instance(cls, model_kwargs, constant_kwargs, model_arg=None):
14791492
Notes:
14801493
- this is only passed in when oneOf includes types which are not object
14811494
- None is used to suppress handling of model_arg, nullable models are handled in __new__
1482-
:type model_arg: int, float, bool, str, date, datetime, ModelSimple, None
1495+
:type model_arg: int, float, bool, str, date, datetime, ModelSimple, UUID, None
14831496
"""
14841497
if len(cls._composed_schemas["oneOf"]) == 0:
14851498
return None

src/datadog_api_client/api_client.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import multiprocessing
1010
from multiprocessing.pool import ThreadPool
1111
from datetime import date, datetime
12+
from uuid import UUID
1213
import io
1314
import os
1415
import re
@@ -179,6 +180,8 @@ def sanitize_for_serialization(cls, obj):
179180
if getattr(obj, "tzinfo", None) is not None:
180181
return obj.isoformat()
181182
return "{}Z".format(obj.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3])
183+
elif isinstance(obj, UUID):
184+
return str(obj)
182185
elif isinstance(obj, ModelSimple):
183186
return cls.sanitize_for_serialization(obj.value)
184187
elif isinstance(obj, (list, tuple)):

src/datadog_api_client/model_utils.py

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from contextlib import suppress
66
from datetime import date, datetime
7+
from uuid import UUID
78
import enum
89
import inspect
910
import io
@@ -54,7 +55,7 @@ def __get__(self, instance, cls=None):
5455
return result
5556

5657

57-
PRIMITIVE_TYPES = (list, float, int, bool, datetime, date, str, file_type)
58+
PRIMITIVE_TYPES = (list, float, int, bool, datetime, date, str, UUID, file_type)
5859

5960

6061
def allows_single_value_input(cls):
@@ -570,7 +571,8 @@ def __eq__(self, other):
570571
datetime: 9,
571572
date: 10,
572573
str: 11,
573-
file_type: 12, # 'file_type' is an alias for the built-in 'file' or 'io.IOBase' type.
574+
UUID: 12,
575+
file_type: 13, # 'file_type' is an alias for the built-in 'file' or 'io.IOBase' type.
574576
}
575577

576578
# these are used to limit what type conversions we try to do
@@ -579,6 +581,7 @@ def __eq__(self, other):
579581
UPCONVERSION_TYPE_PAIRS = (
580582
(str, datetime),
581583
(str, date),
584+
(str, UUID),
582585
(int, float), # A float may be serialized as an integer, e.g. '3' is a valid serialized float.
583586
(list, ModelComposed),
584587
(dict, ModelComposed),
@@ -627,6 +630,7 @@ def __eq__(self, other):
627630
# (str, float),
628631
(str, datetime),
629632
(str, date),
633+
(str, UUID),
630634
# (int, str),
631635
# (float, str),
632636
(str, file_type),
@@ -667,6 +671,8 @@ def get_simple_class(input_value):
667671
return date
668672
elif isinstance(input_value, str):
669673
return str
674+
elif isinstance(input_value, UUID):
675+
return UUID
670676
return type(input_value)
671677

672678

@@ -678,7 +684,7 @@ def check_allowed_values(allowed_values, input_variable, input_values):
678684
:type input_variable: str
679685
:param input_values: The values that we are checking to see if they are in
680686
allowed_values.
681-
:type input_values: list/str/int/float/date/datetime
687+
:type input_values: list/str/int/float/date/datetime/uuid
682688
"""
683689
if isinstance(input_values, list) and not set(input_values).issubset(allowed_values):
684690
invalid_values = (", ".join(map(str, set(input_values) - allowed_values)),)
@@ -724,7 +730,7 @@ def check_validations(validations, input_variable, input_values, configuration=N
724730
:param input_variable: The name of the input variable.
725731
:type input_variable: str
726732
:param input_values: The values that we are checking.
727-
:type input_values: list/str/int/float/date/datetime
733+
:type input_values: list/str/int/float/date/datetime/uuid
728734
:param configuration: The configuration instance.
729735
:type configuration: Configuration
730736
"""
@@ -1017,7 +1023,7 @@ def deserialize_primitive(data, klass, path_to_item):
10171023
:param klass: The class to convert to.
10181024
:type klass: str/class
10191025
1020-
:rtype: int, float, str, bool, date, datetime
1026+
:rtype: int, float, str, bool, date, datetime, UUID
10211027
"""
10221028
additional_message = ""
10231029
try:
@@ -1045,11 +1051,18 @@ def deserialize_primitive(data, klass, path_to_item):
10451051
raise ValueError("This is not a date")
10461052
return parse(data).date()
10471053
else:
1048-
converted_value = klass(data)
1054+
if isinstance(data, str) and klass == UUID:
1055+
try:
1056+
converted_value = UUID(data)
1057+
except ValueError:
1058+
raise ValueError("This is not an UUID")
10491059
if isinstance(data, str) and klass == float:
1060+
converted_value = float(data)
10501061
if str(converted_value) != data:
10511062
# '7' -> 7.0 -> '7.0' != '7'
10521063
raise ValueError("This is not a float")
1064+
else:
1065+
converted_value = klass(data)
10531066
return converted_value
10541067
except (OverflowError, ValueError) as ex:
10551068
# parse can raise OverflowError
@@ -1482,7 +1495,7 @@ def get_oneof_instance(cls, model_kwargs, constant_kwargs, model_arg=None):
14821495
Notes:
14831496
- this is only passed in when oneOf includes types which are not object
14841497
- None is used to suppress handling of model_arg, nullable models are handled in __new__
1485-
:type model_arg: int, float, bool, str, date, datetime, ModelSimple, None
1498+
:type model_arg: int, float, bool, str, date, datetime, ModelSimple, UUID, None
14861499
"""
14871500
if len(cls._composed_schemas["oneOf"]) == 0:
14881501
return None

src/datadog_api_client/v1/model/agent_check.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
date,
1111
datetime,
1212
none_type,
13+
UUID,
1314
)
1415

1516

@@ -18,11 +19,11 @@ class AgentCheck(ModelSimple):
1819
Array of strings.
1920
2021
21-
:type value: [bool, date, datetime, dict, float, int, list, str, none_type]
22+
:type value: [bool, date, datetime, dict, float, int, list, str, UUID, none_type]
2223
"""
2324

2425
@cached_property
2526
def openapi_types(_):
2627
return {
27-
"value": ([bool, date, datetime, dict, float, int, list, str, none_type],),
28+
"value": ([bool, date, datetime, dict, float, int, list, str, UUID, none_type],),
2829
}

0 commit comments

Comments
 (0)