Skip to content
This repository was archived by the owner on Dec 25, 2024. It is now read-only.

Commit 16a31d3

Browse files
authored
Improves contains validation (#267)
* Updates contains validators and the pre validator contains fn * Samples regen * Fixes validate_contains return type
1 parent 3940c87 commit 16a31d3

File tree

6 files changed

+162
-156
lines changed
  • samples/client
    • 3_0_3_unit_test/python/src/unit_test_api/schemas
    • 3_1_0_unit_test/python/src/unit_test_api/schemas
    • openapi_features
      • nonCompliantUseDiscriminatorIfCompositionFails/python/src/this_package/schemas
      • security/python/src/this_package/schemas
    • petstore/python/src/petstore_api/schemas
  • src/main/resources/python/schemas

6 files changed

+162
-156
lines changed

samples/client/3_0_3_unit_test/python/src/unit_test_api/schemas/validation.py

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,10 @@ def _validate(
9090
and k
9191
not in validation_metadata.configuration.disabled_json_schema_python_keywords
9292
}
93-
contains_qty = 0
93+
contains_path_to_schemas = []
9494
path_to_schemas: PathToSchemasType = {}
9595
if 'contains' in vars(cls_schema):
96-
contains_qty = _get_contains_qty(
96+
contains_path_to_schemas = _get_contains_path_to_schemas(
9797
arg,
9898
vars(cls_schema)['contains'],
9999
validation_metadata,
@@ -120,7 +120,7 @@ def _validate(
120120
for keyword, val in json_schema_data.items():
121121
used_val: typing.Any
122122
if keyword in {'contains', 'min_contains', 'max_contains'}:
123-
used_val = (val, contains_qty)
123+
used_val = (val, contains_path_to_schemas)
124124
elif keyword == 'items':
125125
used_val = (val, prefix_items_length)
126126
elif keyword in {'unevaluated_items', 'unevaluated_properties'}:
@@ -1116,66 +1116,67 @@ def validate_else(
11161116
raise ex
11171117

11181118

1119-
def _get_contains_qty(
1119+
def _get_contains_path_to_schemas(
11201120
arg: typing.Any,
11211121
contains_cls: typing.Type[SchemaValidator],
11221122
validation_metadata: ValidationMetadata,
11231123
path_to_schemas: PathToSchemasType
1124-
) -> int:
1124+
) -> typing.List[PathToSchemasType]:
11251125
if not isinstance(arg, tuple):
1126-
return 0
1126+
return []
11271127
contains_cls = _get_class(contains_cls)
1128-
these_path_to_schemas: PathToSchemasType = {}
1129-
contains_qty = 0
1128+
contains_path_to_schemas = []
11301129
for i, value in enumerate(arg):
1130+
these_path_to_schemas: PathToSchemasType = {}
11311131
item_validation_metadata = ValidationMetadata(
11321132
path_to_item=validation_metadata.path_to_item+(i,),
11331133
configuration=validation_metadata.configuration,
11341134
validated_path_to_schemas=validation_metadata.validated_path_to_schemas
11351135
)
11361136
if item_validation_metadata.validation_ran_earlier(contains_cls):
1137-
add_deeper_validated_schemas(item_validation_metadata, path_to_schemas)
1138-
contains_qty += 1
1137+
add_deeper_validated_schemas(item_validation_metadata, these_path_to_schemas)
1138+
contains_path_to_schemas.append(these_path_to_schemas)
11391139
continue
11401140
try:
11411141
other_path_to_schemas = contains_cls._validate(
11421142
value, validation_metadata=item_validation_metadata)
1143-
update(these_path_to_schemas, other_path_to_schemas)
1144-
contains_qty += 1
1143+
contains_path_to_schemas.append(other_path_to_schemas)
11451144
except exceptions.OpenApiException:
11461145
pass
1147-
if contains_qty:
1148-
update(path_to_schemas, these_path_to_schemas)
1149-
return contains_qty
1146+
return contains_path_to_schemas
11501147

11511148

11521149
def validate_contains(
11531150
arg: typing.Any,
1154-
contains_qty: typing.Tuple[typing.Type[SchemaValidator], int],
1151+
contains_cls_path_to_schemas: typing.Tuple[typing.Type[SchemaValidator], typing.List[PathToSchemasType]],
11551152
cls: typing.Type,
11561153
validation_metadata: ValidationMetadata,
11571154
) -> typing.Optional[PathToSchemasType]:
11581155
if not isinstance(arg, tuple):
11591156
return None
1160-
if not contains_qty[1]:
1157+
many_path_to_schemas = contains_cls_path_to_schemas[1]
1158+
if not many_path_to_schemas:
11611159
raise exceptions.ApiValueError(
11621160
"Validation failed for contains keyword in class={} at path_to_item={}. No "
11631161
"items validated to the contains schema.".format(cls, validation_metadata.path_to_item)
11641162
)
1165-
return None
1163+
these_path_to_schemas: PathToSchemasType = {}
1164+
for other_path_to_schema in many_path_to_schemas:
1165+
update(these_path_to_schemas, other_path_to_schema)
1166+
return these_path_to_schemas
11661167

11671168

11681169
def validate_min_contains(
11691170
arg: typing.Any,
1170-
min_contains_and_qty: typing.Tuple[int, int],
1171+
min_contains_and_contains_path_to_schemas: typing.Tuple[int, typing.List[PathToSchemasType]],
11711172
cls: typing.Type,
11721173
validation_metadata: ValidationMetadata,
11731174
) -> typing.Optional[PathToSchemasType]:
11741175
if not isinstance(arg, tuple):
11751176
return None
1176-
min_contains = min_contains_and_qty[0]
1177-
contains_qty = min_contains_and_qty[1]
1178-
if not contains_qty or contains_qty < min_contains:
1177+
min_contains = min_contains_and_contains_path_to_schemas[0]
1178+
contains_path_to_schemas = min_contains_and_contains_path_to_schemas[1]
1179+
if len(contains_path_to_schemas) < min_contains:
11791180
raise exceptions.ApiValueError(
11801181
"Validation failed for minContains keyword in class={} at path_to_item={}. No "
11811182
"items validated to the contains schema.".format(cls, validation_metadata.path_to_item)
@@ -1185,15 +1186,15 @@ def validate_min_contains(
11851186

11861187
def validate_max_contains(
11871188
arg: typing.Any,
1188-
max_contains_and_qty: typing.Tuple[int, int],
1189+
max_contains_and_contains_path_to_schemas: typing.Tuple[int, typing.List[PathToSchemasType]],
11891190
cls: typing.Type,
11901191
validation_metadata: ValidationMetadata,
11911192
) -> typing.Optional[PathToSchemasType]:
11921193
if not isinstance(arg, tuple):
11931194
return None
1194-
max_contains = max_contains_and_qty[0]
1195-
contains_qty = max_contains_and_qty[1]
1196-
if not contains_qty or contains_qty > max_contains:
1195+
max_contains = max_contains_and_contains_path_to_schemas[0]
1196+
contains_path_to_schemas = max_contains_and_contains_path_to_schemas[1]
1197+
if len(contains_path_to_schemas) > max_contains:
11971198
raise exceptions.ApiValueError(
11981199
"Validation failed for maxContains keyword in class={} at path_to_item={}. Too "
11991200
"many items validated to the contains schema.".format(cls, validation_metadata.path_to_item)

samples/client/3_1_0_unit_test/python/src/unit_test_api/schemas/validation.py

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,10 @@ def _validate(
9090
and k
9191
not in validation_metadata.configuration.disabled_json_schema_python_keywords
9292
}
93-
contains_qty = 0
93+
contains_path_to_schemas = []
9494
path_to_schemas: PathToSchemasType = {}
9595
if 'contains' in vars(cls_schema):
96-
contains_qty = _get_contains_qty(
96+
contains_path_to_schemas = _get_contains_path_to_schemas(
9797
arg,
9898
vars(cls_schema)['contains'],
9999
validation_metadata,
@@ -120,7 +120,7 @@ def _validate(
120120
for keyword, val in json_schema_data.items():
121121
used_val: typing.Any
122122
if keyword in {'contains', 'min_contains', 'max_contains'}:
123-
used_val = (val, contains_qty)
123+
used_val = (val, contains_path_to_schemas)
124124
elif keyword == 'items':
125125
used_val = (val, prefix_items_length)
126126
elif keyword in {'unevaluated_items', 'unevaluated_properties'}:
@@ -1116,66 +1116,67 @@ def validate_else(
11161116
raise ex
11171117

11181118

1119-
def _get_contains_qty(
1119+
def _get_contains_path_to_schemas(
11201120
arg: typing.Any,
11211121
contains_cls: typing.Type[SchemaValidator],
11221122
validation_metadata: ValidationMetadata,
11231123
path_to_schemas: PathToSchemasType
1124-
) -> int:
1124+
) -> typing.List[PathToSchemasType]:
11251125
if not isinstance(arg, tuple):
1126-
return 0
1126+
return []
11271127
contains_cls = _get_class(contains_cls)
1128-
these_path_to_schemas: PathToSchemasType = {}
1129-
contains_qty = 0
1128+
contains_path_to_schemas = []
11301129
for i, value in enumerate(arg):
1130+
these_path_to_schemas: PathToSchemasType = {}
11311131
item_validation_metadata = ValidationMetadata(
11321132
path_to_item=validation_metadata.path_to_item+(i,),
11331133
configuration=validation_metadata.configuration,
11341134
validated_path_to_schemas=validation_metadata.validated_path_to_schemas
11351135
)
11361136
if item_validation_metadata.validation_ran_earlier(contains_cls):
1137-
add_deeper_validated_schemas(item_validation_metadata, path_to_schemas)
1138-
contains_qty += 1
1137+
add_deeper_validated_schemas(item_validation_metadata, these_path_to_schemas)
1138+
contains_path_to_schemas.append(these_path_to_schemas)
11391139
continue
11401140
try:
11411141
other_path_to_schemas = contains_cls._validate(
11421142
value, validation_metadata=item_validation_metadata)
1143-
update(these_path_to_schemas, other_path_to_schemas)
1144-
contains_qty += 1
1143+
contains_path_to_schemas.append(other_path_to_schemas)
11451144
except exceptions.OpenApiException:
11461145
pass
1147-
if contains_qty:
1148-
update(path_to_schemas, these_path_to_schemas)
1149-
return contains_qty
1146+
return contains_path_to_schemas
11501147

11511148

11521149
def validate_contains(
11531150
arg: typing.Any,
1154-
contains_qty: typing.Tuple[typing.Type[SchemaValidator], int],
1151+
contains_cls_path_to_schemas: typing.Tuple[typing.Type[SchemaValidator], typing.List[PathToSchemasType]],
11551152
cls: typing.Type,
11561153
validation_metadata: ValidationMetadata,
11571154
) -> typing.Optional[PathToSchemasType]:
11581155
if not isinstance(arg, tuple):
11591156
return None
1160-
if not contains_qty[1]:
1157+
many_path_to_schemas = contains_cls_path_to_schemas[1]
1158+
if not many_path_to_schemas:
11611159
raise exceptions.ApiValueError(
11621160
"Validation failed for contains keyword in class={} at path_to_item={}. No "
11631161
"items validated to the contains schema.".format(cls, validation_metadata.path_to_item)
11641162
)
1165-
return None
1163+
these_path_to_schemas: PathToSchemasType = {}
1164+
for other_path_to_schema in many_path_to_schemas:
1165+
update(these_path_to_schemas, other_path_to_schema)
1166+
return these_path_to_schemas
11661167

11671168

11681169
def validate_min_contains(
11691170
arg: typing.Any,
1170-
min_contains_and_qty: typing.Tuple[int, int],
1171+
min_contains_and_contains_path_to_schemas: typing.Tuple[int, typing.List[PathToSchemasType]],
11711172
cls: typing.Type,
11721173
validation_metadata: ValidationMetadata,
11731174
) -> typing.Optional[PathToSchemasType]:
11741175
if not isinstance(arg, tuple):
11751176
return None
1176-
min_contains = min_contains_and_qty[0]
1177-
contains_qty = min_contains_and_qty[1]
1178-
if not contains_qty or contains_qty < min_contains:
1177+
min_contains = min_contains_and_contains_path_to_schemas[0]
1178+
contains_path_to_schemas = min_contains_and_contains_path_to_schemas[1]
1179+
if len(contains_path_to_schemas) < min_contains:
11791180
raise exceptions.ApiValueError(
11801181
"Validation failed for minContains keyword in class={} at path_to_item={}. No "
11811182
"items validated to the contains schema.".format(cls, validation_metadata.path_to_item)
@@ -1185,15 +1186,15 @@ def validate_min_contains(
11851186

11861187
def validate_max_contains(
11871188
arg: typing.Any,
1188-
max_contains_and_qty: typing.Tuple[int, int],
1189+
max_contains_and_contains_path_to_schemas: typing.Tuple[int, typing.List[PathToSchemasType]],
11891190
cls: typing.Type,
11901191
validation_metadata: ValidationMetadata,
11911192
) -> typing.Optional[PathToSchemasType]:
11921193
if not isinstance(arg, tuple):
11931194
return None
1194-
max_contains = max_contains_and_qty[0]
1195-
contains_qty = max_contains_and_qty[1]
1196-
if not contains_qty or contains_qty > max_contains:
1195+
max_contains = max_contains_and_contains_path_to_schemas[0]
1196+
contains_path_to_schemas = max_contains_and_contains_path_to_schemas[1]
1197+
if len(contains_path_to_schemas) > max_contains:
11971198
raise exceptions.ApiValueError(
11981199
"Validation failed for maxContains keyword in class={} at path_to_item={}. Too "
11991200
"many items validated to the contains schema.".format(cls, validation_metadata.path_to_item)

samples/client/openapi_features/nonCompliantUseDiscriminatorIfCompositionFails/python/src/this_package/schemas/validation.py

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,10 @@ def _validate(
101101
'discriminated_cls': discriminated_cls,
102102
'ensure_discriminator_value_present_exc': ensure_discriminator_value_present_exc
103103
}
104-
contains_qty = 0
104+
contains_path_to_schemas = []
105105
path_to_schemas: PathToSchemasType = {}
106106
if 'contains' in vars(cls_schema):
107-
contains_qty = _get_contains_qty(
107+
contains_path_to_schemas = _get_contains_path_to_schemas(
108108
arg,
109109
vars(cls_schema)['contains'],
110110
validation_metadata,
@@ -131,7 +131,7 @@ def _validate(
131131
for keyword, val in json_schema_data.items():
132132
used_val: typing.Any
133133
if keyword in {'contains', 'min_contains', 'max_contains'}:
134-
used_val = (val, contains_qty)
134+
used_val = (val, contains_path_to_schemas)
135135
elif keyword == 'items':
136136
used_val = (val, prefix_items_length)
137137
elif keyword in {'unevaluated_items', 'unevaluated_properties'}:
@@ -1196,68 +1196,69 @@ def validate_else(
11961196
raise ex
11971197

11981198

1199-
def _get_contains_qty(
1199+
def _get_contains_path_to_schemas(
12001200
arg: typing.Any,
12011201
contains_cls: typing.Type[SchemaValidator],
12021202
validation_metadata: ValidationMetadata,
12031203
path_to_schemas: PathToSchemasType
1204-
) -> int:
1204+
) -> typing.List[PathToSchemasType]:
12051205
if not isinstance(arg, tuple):
1206-
return 0
1206+
return []
12071207
contains_cls = _get_class(contains_cls)
1208-
these_path_to_schemas: PathToSchemasType = {}
1209-
contains_qty = 0
1208+
contains_path_to_schemas = []
12101209
for i, value in enumerate(arg):
1210+
these_path_to_schemas: PathToSchemasType = {}
12111211
item_validation_metadata = ValidationMetadata(
12121212
path_to_item=validation_metadata.path_to_item+(i,),
12131213
configuration=validation_metadata.configuration,
12141214
validated_path_to_schemas=validation_metadata.validated_path_to_schemas
12151215
)
12161216
if item_validation_metadata.validation_ran_earlier(contains_cls):
1217-
add_deeper_validated_schemas(item_validation_metadata, path_to_schemas)
1218-
contains_qty += 1
1217+
add_deeper_validated_schemas(item_validation_metadata, these_path_to_schemas)
1218+
contains_path_to_schemas.append(these_path_to_schemas)
12191219
continue
12201220
try:
12211221
other_path_to_schemas = contains_cls._validate(
12221222
value, validation_metadata=item_validation_metadata)
1223-
update(these_path_to_schemas, other_path_to_schemas)
1224-
contains_qty += 1
1223+
contains_path_to_schemas.append(other_path_to_schemas)
12251224
except exceptions.OpenApiException:
12261225
pass
1227-
if contains_qty:
1228-
update(path_to_schemas, these_path_to_schemas)
1229-
return contains_qty
1226+
return contains_path_to_schemas
12301227

12311228

12321229
def validate_contains(
12331230
arg: typing.Any,
1234-
contains_qty: typing.Tuple[typing.Type[SchemaValidator], int],
1231+
contains_cls_path_to_schemas: typing.Tuple[typing.Type[SchemaValidator], typing.List[PathToSchemasType]],
12351232
cls: typing.Type,
12361233
validation_metadata: ValidationMetadata,
12371234
**kwargs
12381235
) -> typing.Optional[PathToSchemasType]:
12391236
if not isinstance(arg, tuple):
12401237
return None
1241-
if not contains_qty[1]:
1238+
many_path_to_schemas = contains_cls_path_to_schemas[1]
1239+
if not many_path_to_schemas:
12421240
raise exceptions.ApiValueError(
12431241
"Validation failed for contains keyword in class={} at path_to_item={}. No "
12441242
"items validated to the contains schema.".format(cls, validation_metadata.path_to_item)
12451243
)
1246-
return None
1244+
these_path_to_schemas: PathToSchemasType = {}
1245+
for other_path_to_schema in many_path_to_schemas:
1246+
update(these_path_to_schemas, other_path_to_schema)
1247+
return these_path_to_schemas
12471248

12481249

12491250
def validate_min_contains(
12501251
arg: typing.Any,
1251-
min_contains_and_qty: typing.Tuple[int, int],
1252+
min_contains_and_contains_path_to_schemas: typing.Tuple[int, typing.List[PathToSchemasType]],
12521253
cls: typing.Type,
12531254
validation_metadata: ValidationMetadata,
12541255
**kwargs
12551256
) -> typing.Optional[PathToSchemasType]:
12561257
if not isinstance(arg, tuple):
12571258
return None
1258-
min_contains = min_contains_and_qty[0]
1259-
contains_qty = min_contains_and_qty[1]
1260-
if not contains_qty or contains_qty < min_contains:
1259+
min_contains = min_contains_and_contains_path_to_schemas[0]
1260+
contains_path_to_schemas = min_contains_and_contains_path_to_schemas[1]
1261+
if len(contains_path_to_schemas) < min_contains:
12611262
raise exceptions.ApiValueError(
12621263
"Validation failed for minContains keyword in class={} at path_to_item={}. No "
12631264
"items validated to the contains schema.".format(cls, validation_metadata.path_to_item)
@@ -1267,16 +1268,16 @@ def validate_min_contains(
12671268

12681269
def validate_max_contains(
12691270
arg: typing.Any,
1270-
max_contains_and_qty: typing.Tuple[int, int],
1271+
max_contains_and_contains_path_to_schemas: typing.Tuple[int, typing.List[PathToSchemasType]],
12711272
cls: typing.Type,
12721273
validation_metadata: ValidationMetadata,
12731274
**kwargs
12741275
) -> typing.Optional[PathToSchemasType]:
12751276
if not isinstance(arg, tuple):
12761277
return None
1277-
max_contains = max_contains_and_qty[0]
1278-
contains_qty = max_contains_and_qty[1]
1279-
if not contains_qty or contains_qty > max_contains:
1278+
max_contains = max_contains_and_contains_path_to_schemas[0]
1279+
contains_path_to_schemas = max_contains_and_contains_path_to_schemas[1]
1280+
if len(contains_path_to_schemas) > max_contains:
12801281
raise exceptions.ApiValueError(
12811282
"Validation failed for maxContains keyword in class={} at path_to_item={}. Too "
12821283
"many items validated to the contains schema.".format(cls, validation_metadata.path_to_item)

0 commit comments

Comments
 (0)