|
1 | 1 | from typing import Optional
|
2 | 2 |
|
3 | 3 | import pytest
|
4 |
| -from dirty_equals import IsPartialDict |
| 4 | +from dirty_equals import IsList, IsPartialDict |
5 | 5 |
|
6 | 6 | from pydantic_core import SchemaError, SchemaValidator, ValidationError
|
7 | 7 |
|
| 8 | +from ..conftest import Err |
| 9 | + |
8 | 10 |
|
9 | 11 | def test_branch_nullable():
|
10 | 12 | v = SchemaValidator(
|
@@ -234,7 +236,7 @@ def test_outside_parent():
|
234 | 236 | }
|
235 | 237 |
|
236 | 238 |
|
237 |
| -def test_recursion(): |
| 239 | +def test_recursion_branch(): |
238 | 240 | v = SchemaValidator(
|
239 | 241 | {
|
240 | 242 | 'type': 'typed-dict',
|
@@ -266,3 +268,96 @@ def test_recursion():
|
266 | 268 | 'input_value': {'name': 'recursive', 'branch': IsPartialDict(name='recursive')},
|
267 | 269 | }
|
268 | 270 | ]
|
| 271 | + |
| 272 | + |
| 273 | +def test_recursive_list(): |
| 274 | + v = SchemaValidator( |
| 275 | + {'type': 'list', 'ref': 'the-list', 'items_schema': {'type': 'recursive-ref', 'schema_ref': 'the-list'}} |
| 276 | + ) |
| 277 | + assert v.validate_python([]) == [] |
| 278 | + assert v.validate_python([[]]) == [[]] |
| 279 | + |
| 280 | + data = list() |
| 281 | + data.append(data) |
| 282 | + with pytest.raises(ValidationError, match='Recursion error - cyclic reference detected'): |
| 283 | + assert v.validate_python(data) |
| 284 | + |
| 285 | + |
| 286 | +@pytest.fixture(scope='module') |
| 287 | +def multiple_tuple_schema(): |
| 288 | + return SchemaValidator( |
| 289 | + { |
| 290 | + 'type': 'typed-dict', |
| 291 | + 'fields': { |
| 292 | + 'f1': { |
| 293 | + 'schema': { |
| 294 | + 'type': 'tuple-fix-len', |
| 295 | + 'ref': 't', |
| 296 | + 'items_schema': [ |
| 297 | + {'type': 'int'}, |
| 298 | + {'type': 'nullable', 'schema': {'type': 'recursive-ref', 'schema_ref': 't'}}, |
| 299 | + ], |
| 300 | + } |
| 301 | + }, |
| 302 | + 'f2': { |
| 303 | + 'schema': {'type': 'nullable', 'schema': {'type': 'recursive-ref', 'schema_ref': 't'}}, |
| 304 | + 'default': None, |
| 305 | + }, |
| 306 | + }, |
| 307 | + } |
| 308 | + ) |
| 309 | + |
| 310 | + |
| 311 | +@pytest.mark.parametrize( |
| 312 | + 'input_value,expected', |
| 313 | + [ |
| 314 | + ({'f1': [1, None]}, {'f1': (1, None), 'f2': None}), |
| 315 | + ({'f1': [1, None], 'f2': [2, None]}, {'f1': (1, None), 'f2': (2, None)}), |
| 316 | + ( |
| 317 | + {'f1': [1, (3, None)], 'f2': [2, (4, (4, (5, None)))]}, |
| 318 | + {'f1': (1, (3, None)), 'f2': (2, (4, (4, (5, None))))}, |
| 319 | + ), |
| 320 | + ({'f1': [1, 2]}, Err(r'f1 -> 1\s+Value must be a valid tuple')), |
| 321 | + ( |
| 322 | + {'f1': [1, (3, None)], 'f2': [2, (4, (4, (5, 6)))]}, |
| 323 | + Err(r'f2 -> 1 -> 1 -> 1 -> 1\s+Value must be a valid tuple'), |
| 324 | + ), |
| 325 | + ], |
| 326 | +) |
| 327 | +def test_multiple_tuple_param(multiple_tuple_schema, input_value, expected): |
| 328 | + if isinstance(expected, Err): |
| 329 | + with pytest.raises(ValidationError, match=expected.message): |
| 330 | + multiple_tuple_schema.validate_python(input_value) |
| 331 | + # debug(repr(exc_info.value)) |
| 332 | + else: |
| 333 | + assert multiple_tuple_schema.validate_python(input_value) == expected |
| 334 | + |
| 335 | + |
| 336 | +def test_multiple_tuple_repeat(multiple_tuple_schema): |
| 337 | + t = (42, None) |
| 338 | + assert multiple_tuple_schema.validate_python({'f1': (1, t), 'f2': (2, t)}) == { |
| 339 | + 'f1': (1, (42, None)), |
| 340 | + 'f2': (2, (42, None)), |
| 341 | + } |
| 342 | + |
| 343 | + |
| 344 | +def test_multiple_tuple_recursion(multiple_tuple_schema): |
| 345 | + data = [1] |
| 346 | + data.append(data) |
| 347 | + with pytest.raises(ValidationError) as exc_info: |
| 348 | + multiple_tuple_schema.validate_python({'f1': data, 'f2': data}) |
| 349 | + |
| 350 | + assert exc_info.value.errors() == [ |
| 351 | + { |
| 352 | + 'kind': 'recursion_loop', |
| 353 | + 'loc': ['f1', 1], |
| 354 | + 'message': 'Recursion error - cyclic reference detected', |
| 355 | + 'input_value': [1, IsList(length=2)], |
| 356 | + }, |
| 357 | + { |
| 358 | + 'kind': 'recursion_loop', |
| 359 | + 'loc': ['f2', 1], |
| 360 | + 'message': 'Recursion error - cyclic reference detected', |
| 361 | + 'input_value': [1, IsList(length=2)], |
| 362 | + }, |
| 363 | + ] |
0 commit comments