ul-api-utils 8.1.20__py3-none-any.whl → 8.1.21__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ul-api-utils might be problematic. Click here for more details.
- ul_api_utils/utils/flask_swagger_generator/specifiers/swagger_three_specifier.py +3 -3
- ul_api_utils/utils/flask_swagger_generator/utils/replace_in_dict.py +1 -1
- ul_api_utils/validators/__tests__/test_custom_fields.py +32 -32
- ul_api_utils/validators/custom_fields.py +28 -52
- {ul_api_utils-8.1.20.dist-info → ul_api_utils-8.1.21.dist-info}/METADATA +1 -1
- {ul_api_utils-8.1.20.dist-info → ul_api_utils-8.1.21.dist-info}/RECORD +10 -10
- {ul_api_utils-8.1.20.dist-info → ul_api_utils-8.1.21.dist-info}/LICENSE +0 -0
- {ul_api_utils-8.1.20.dist-info → ul_api_utils-8.1.21.dist-info}/WHEEL +0 -0
- {ul_api_utils-8.1.20.dist-info → ul_api_utils-8.1.21.dist-info}/entry_points.txt +0 -0
- {ul_api_utils-8.1.20.dist-info → ul_api_utils-8.1.21.dist-info}/top_level.txt +0 -0
|
@@ -68,8 +68,8 @@ class SwaggerSchema(SwaggerModel):
|
|
|
68
68
|
if '$ref' in json.dumps(json_schema):
|
|
69
69
|
while '$ref' in json.dumps(json_schema):
|
|
70
70
|
json_schema = replace_value_in_dict(json_schema.copy(), json_schema.copy())
|
|
71
|
-
if '
|
|
72
|
-
del json_schema['
|
|
71
|
+
if '$defs' in json_schema:
|
|
72
|
+
del json_schema['$defs']
|
|
73
73
|
self.type = json_schema['type']
|
|
74
74
|
if json_schema['type'] == 'object':
|
|
75
75
|
self.properties = json_schema.get('properties', dict())
|
|
@@ -508,7 +508,7 @@ class SwaggerPath(SwaggerModel):
|
|
|
508
508
|
swagger_request_type.add_swagger_model(parameters)
|
|
509
509
|
query_schema = query_model.model_json_schema()
|
|
510
510
|
query_required_fields = set(query_schema.get('required')) if query_schema.get('required') is not None else set()
|
|
511
|
-
query_definitions = query_schema.get('
|
|
511
|
+
query_definitions = query_schema.get('$defs')
|
|
512
512
|
for parameter_name, parameter_spec in query_schema.get('properties').items():
|
|
513
513
|
if parameter_spec.get('type') is not None:
|
|
514
514
|
parameter_models.add(SwaggerQueryParameter(
|
|
@@ -5,7 +5,7 @@ def replace_value_in_dict(item: Union[List, Dict], original_schema): # type: ig
|
|
|
5
5
|
if isinstance(item, list):
|
|
6
6
|
return [replace_value_in_dict(i, original_schema) for i in item]
|
|
7
7
|
elif isinstance(item, dict):
|
|
8
|
-
if list(item.keys())
|
|
8
|
+
if '$ref' in list(item.keys()):
|
|
9
9
|
definitions = item['$ref'][2:].split('/')
|
|
10
10
|
res = original_schema.copy()
|
|
11
11
|
for definition in definitions:
|
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel
|
|
4
|
+
from typing import Union, List
|
|
5
|
+
from ul_api_utils.validators.custom_fields import QueryParamsSeparatedList
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ModelStr(BaseModel):
|
|
9
|
+
param: QueryParamsSeparatedList[str]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ModelInt(BaseModel):
|
|
13
|
+
param: QueryParamsSeparatedList[int]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@pytest.mark.parametrize(
|
|
17
|
+
"model, input_data, expected_output",
|
|
18
|
+
[
|
|
19
|
+
pytest.param(ModelStr, "first_array_element,second,third,this", ["first_array_element", "second", "third", "this"]),
|
|
20
|
+
pytest.param(ModelStr, ["first_array_element,second,third,this"], ["first_array_element", "second", "third", "this"]),
|
|
21
|
+
pytest.param(ModelInt, ["1,2,3,4,5"], [1, 2, 3, 4, 5]),
|
|
22
|
+
pytest.param(ModelStr, 'first_array_element,"second,third",this', ["first_array_element", "second,third", "this"]),
|
|
23
|
+
pytest.param(ModelStr, ['first_array_element,"second,third",this'], ["first_array_element", "second,third", "this"]),
|
|
24
|
+
pytest.param(ModelStr, '"first_array_element,second,third",this, "1,2"', ["first_array_element,second,third", "this", "1,2"]),
|
|
25
|
+
],
|
|
26
|
+
)
|
|
27
|
+
def test__query_params_separated_list(
|
|
28
|
+
model: Union[ModelStr, ModelInt], input_data: Union[List[str], str], expected_output: List[Union[str, int]],
|
|
29
|
+
) -> None:
|
|
30
|
+
instance = model(param=input_data) # type: ignore
|
|
31
|
+
assert isinstance(instance.param, list)
|
|
32
|
+
assert instance.param == expected_output
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import csv
|
|
2
|
-
from typing import TypeVar, Generic, List, Union,
|
|
2
|
+
from typing import TypeVar, Generic, List, Union, Annotated, Any, get_args
|
|
3
3
|
from uuid import UUID
|
|
4
4
|
|
|
5
|
-
from pydantic import Field, StringConstraints,
|
|
6
|
-
from pydantic_core import ValidationError, InitErrorDetails
|
|
7
|
-
from pydantic_core.core_schema import ValidationInfo
|
|
5
|
+
from pydantic import Field, StringConstraints, BeforeValidator
|
|
8
6
|
|
|
9
7
|
from ul_api_utils.const import CRON_EXPRESSION_VALIDATION_REGEX, MIN_UTC_OFFSET_SECONDS, MAX_UTC_OFFSET_SECONDS
|
|
10
8
|
|
|
@@ -29,56 +27,34 @@ PgTypePositiveInt64Annotation = Annotated[int, Field(ge=0, le=922337203685477580
|
|
|
29
27
|
QueryParamsSeparatedListValueType = TypeVar('QueryParamsSeparatedListValueType')
|
|
30
28
|
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
that it is a list.
|
|
36
|
-
|
|
37
|
-
F.E. Query string is ?foo=1,2
|
|
30
|
+
def validate_query_params(value: Union[str, List[str]], type_: type) -> List[QueryParamsSeparatedListValueType]:
|
|
31
|
+
def process_item(item: str) -> QueryParamsSeparatedListValueType:
|
|
32
|
+
return type_(item.strip())
|
|
38
33
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
34
|
+
if isinstance(value, list):
|
|
35
|
+
result: list[QueryParamsSeparatedListValueType] = []
|
|
36
|
+
for item in value:
|
|
37
|
+
if isinstance(item, str):
|
|
38
|
+
reader = csv.reader([item], skipinitialspace=True)
|
|
39
|
+
result.extend(process_item(sub_item) for row in reader for sub_item in row)
|
|
40
|
+
else:
|
|
41
|
+
raise ValueError("List items must be strings")
|
|
42
|
+
elif isinstance(value, str):
|
|
43
|
+
reader = csv.reader([value], skipinitialspace=True)
|
|
44
|
+
result = [process_item(item) for row in reader for item in row]
|
|
45
|
+
else:
|
|
46
|
+
raise ValueError("Value must be a string or a list of strings")
|
|
43
47
|
|
|
44
|
-
|
|
45
|
-
def __class_getitem__(cls, item: Any) -> QueryParamsSeparatedListValueType:
|
|
46
|
-
new_cls = super().__class_getitem__(item) # type: ignore
|
|
47
|
-
new_cls._contains_type = item
|
|
48
|
-
return new_cls
|
|
48
|
+
return result
|
|
49
49
|
|
|
50
|
-
@classmethod
|
|
51
|
-
def __get_validators__(cls) -> Generator[Callable[[Union[List[str], str], ValidationInfo], List[QueryParamsSeparatedListValueType]], None, None]:
|
|
52
|
-
yield cls.validate
|
|
53
50
|
|
|
51
|
+
class QueryParamsSeparatedList(Generic[QueryParamsSeparatedListValueType]):
|
|
54
52
|
@classmethod
|
|
55
|
-
def
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if not isinstance(query_param, list):
|
|
65
|
-
query_param = [query_param]
|
|
66
|
-
|
|
67
|
-
reader = csv.reader(query_param, skipinitialspace=True)
|
|
68
|
-
splitted = next(reader)
|
|
69
|
-
|
|
70
|
-
validated_items = []
|
|
71
|
-
errors: List[InitErrorDetails] = []
|
|
72
|
-
|
|
73
|
-
for idx, value in enumerate(splitted):
|
|
74
|
-
try:
|
|
75
|
-
validated_items.append(adapter.validate_python(value))
|
|
76
|
-
except ValidationError as e:
|
|
77
|
-
for error in e.errors(include_url=False):
|
|
78
|
-
error['loc'] = ('param', idx)
|
|
79
|
-
errors.append(error) # type: ignore
|
|
80
|
-
|
|
81
|
-
if errors:
|
|
82
|
-
raise ValidationError.from_exception_data("List validation error", errors)
|
|
83
|
-
|
|
84
|
-
return validated_items
|
|
53
|
+
def __get_pydantic_core_schema__(cls, source_type: type, handler: Any) -> Any:
|
|
54
|
+
inner_type = get_args(source_type)[0]
|
|
55
|
+
return handler(
|
|
56
|
+
Annotated[
|
|
57
|
+
List[inner_type], # type: ignore
|
|
58
|
+
BeforeValidator(lambda x: validate_query_params(x, inner_type))
|
|
59
|
+
]
|
|
60
|
+
)
|
|
@@ -126,12 +126,12 @@ ul_api_utils/utils/flask_swagger_generator/exceptions.py,sha256=yA4IsUyxh5puyoYz
|
|
|
126
126
|
ul_api_utils/utils/flask_swagger_generator/specifiers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
127
127
|
ul_api_utils/utils/flask_swagger_generator/specifiers/swagger_models.py,sha256=P52azB25Ncpp6I5j5bq4LLAJHDLSORFVJp9bHoXvpQk,1698
|
|
128
128
|
ul_api_utils/utils/flask_swagger_generator/specifiers/swagger_specifier.py,sha256=9Cf1ijk90IDYUDG8kTjK4cxjdxpYjWZz1tKJHPCeDAA,1513
|
|
129
|
-
ul_api_utils/utils/flask_swagger_generator/specifiers/swagger_three_specifier.py,sha256=
|
|
129
|
+
ul_api_utils/utils/flask_swagger_generator/specifiers/swagger_three_specifier.py,sha256=jPdy2zHAg9BjRzU0rrqiosfMir0pjdrPfrp1rEQHVj0,30819
|
|
130
130
|
ul_api_utils/utils/flask_swagger_generator/specifiers/swagger_version.py,sha256=A14IRG-e2KL2SlFbHep2FH0uMRIHPhfd7KLkYdtWrfA,1312
|
|
131
131
|
ul_api_utils/utils/flask_swagger_generator/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
132
132
|
ul_api_utils/utils/flask_swagger_generator/utils/input_type.py,sha256=Ynp3zI5q1F0Tl_eTdNbWoCxRKPwBCJkwJOoeHE2pTRE,2533
|
|
133
133
|
ul_api_utils/utils/flask_swagger_generator/utils/parameter_type.py,sha256=bTE_kDUPNYL7Qr1AV_h4pXEWiLeiVYVFBxAWMkLYzPU,1557
|
|
134
|
-
ul_api_utils/utils/flask_swagger_generator/utils/replace_in_dict.py,sha256=
|
|
134
|
+
ul_api_utils/utils/flask_swagger_generator/utils/replace_in_dict.py,sha256=xGF78881vi8xAWbJ9eaqBzsuMFHSJGZNYlm6bmC-5jk,742
|
|
135
135
|
ul_api_utils/utils/flask_swagger_generator/utils/request_type.py,sha256=fx4ltfODfYmXx3i31BTZGAtwzrMqYbk48VQavQirFa8,1504
|
|
136
136
|
ul_api_utils/utils/flask_swagger_generator/utils/schema_type.py,sha256=NqFRHjSWZgg6fNYE-CG7vwLa57ie9WjooB2YfVTs4UM,294
|
|
137
137
|
ul_api_utils/utils/flask_swagger_generator/utils/security_type.py,sha256=AcWOQZBbUPXZyyTbmGFRt5p4Jx1uwETuxNRtXXht16I,1148
|
|
@@ -143,14 +143,14 @@ ul_api_utils/utils/memory_db/errors.py,sha256=Bw1O1Y_WTCeCRNgb9iwrGT1fst6iHORhrN
|
|
|
143
143
|
ul_api_utils/utils/memory_db/repository.py,sha256=0AI0-VA4Md54BrAuZLX0Lg7rxyyGv54aWiiNUPycGSA,3760
|
|
144
144
|
ul_api_utils/utils/memory_db/__tests__/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
145
145
|
ul_api_utils/validators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
146
|
-
ul_api_utils/validators/custom_fields.py,sha256=
|
|
146
|
+
ul_api_utils/validators/custom_fields.py,sha256=6pNvwHMhup9pqGOvqp57UsPAfmgvVyLujBKooBY-C1I,2998
|
|
147
147
|
ul_api_utils/validators/validate_empty_object.py,sha256=3Ck_iwyJE_M5e7l6s1i88aqb73zIt06uaLrMG2PAb0A,299
|
|
148
148
|
ul_api_utils/validators/validate_uuid.py,sha256=EfvlRirv2EW0Z6w3s8E8rUa9GaI8qXZkBWhnPs8NFrA,257
|
|
149
149
|
ul_api_utils/validators/__tests__/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
150
|
-
ul_api_utils/validators/__tests__/test_custom_fields.py,sha256=
|
|
151
|
-
ul_api_utils-8.1.
|
|
152
|
-
ul_api_utils-8.1.
|
|
153
|
-
ul_api_utils-8.1.
|
|
154
|
-
ul_api_utils-8.1.
|
|
155
|
-
ul_api_utils-8.1.
|
|
156
|
-
ul_api_utils-8.1.
|
|
150
|
+
ul_api_utils/validators/__tests__/test_custom_fields.py,sha256=omXI_PPefDfCehEVJxEevep8phY6aySjLnpW_usT85U,1385
|
|
151
|
+
ul_api_utils-8.1.21.dist-info/LICENSE,sha256=6Qo8OdcqI8aGrswJKJYhST-bYqxVQBQ3ujKdTSdq-80,1062
|
|
152
|
+
ul_api_utils-8.1.21.dist-info/METADATA,sha256=dvWXhY1fsuIeO5nNOuMcjrsAx8g0ySsgNhnN-j-CJmk,14748
|
|
153
|
+
ul_api_utils-8.1.21.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
|
|
154
|
+
ul_api_utils-8.1.21.dist-info/entry_points.txt,sha256=8tL3ySHWTyJMuV1hx1fHfN8zumDVOCOm63w3StphkXg,53
|
|
155
|
+
ul_api_utils-8.1.21.dist-info/top_level.txt,sha256=1XsW8iOSFaH4LOzDcnNyxHpHrbKU3fSn-aIAxe04jmw,21
|
|
156
|
+
ul_api_utils-8.1.21.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|