|
| 1 | +# Add support for Union |
| 2 | + |
| 3 | +current this case will raise exception becuase A, B inside C is not walked during analysis |
| 4 | + |
| 5 | +which means they are not stored at metadata. |
| 6 | + |
| 7 | +and then during resolving it will attempt to read A and B from metadata then exceptions are raised. |
| 8 | + |
| 9 | +this feature aims to fix this bug. |
| 10 | + |
| 11 | +```python |
| 12 | +class A(BaseModel): |
| 13 | + id: int |
| 14 | + name: str |
| 15 | + |
| 16 | +class B(BaseModel): |
| 17 | + id: int |
| 18 | + age: int |
| 19 | + |
| 20 | +class C(BaseModel): |
| 21 | + items: List[Union[A, B]] = [] |
| 22 | + def resolve(self): |
| 23 | + return [A(id=1, name='n'), B(id=1, age=21)] |
| 24 | +``` |
| 25 | + |
| 26 | +for Union[A, B] pydantic-resolve will dive into A, B and store them in metadata. |
| 27 | + |
| 28 | +## plan |
| 29 | + |
| 30 | +- add `get_core_types` in types.py, will replace `shelling_type` |
| 31 | +- check the code using `shelling_type` and their deps |
| 32 | + - class_utils.py |
| 33 | + - get_pydantic_fields: change the return type from type -> tuple of type |
| 34 | + - get_dataclass_fields |
| 35 | + - update_forward_refs |
| 36 | + - update_pydantic_forward_refs |
| 37 | + - update_dataclass_forward_refs |
| 38 | + - analysis.py |
| 39 | + - scan_and_store_metadata |
| 40 | + - \_get_all_fields_and_object_fields |
| 41 | + - object_field_pairs from \_get_all_fields_and_object_fields |
| 42 | + - \_get_request_type_for_loader: calculate receiver types for dataloader |
| 43 | + |
| 44 | +## details |
| 45 | + |
| 46 | +```python |
| 47 | +def get_pydantic_fields(kls) -> Tuple[str, List[Type[BaseModel]]]: |
| 48 | + items = class_util.get_pydantic_field_items(kls) |
| 49 | + |
| 50 | + for name, v in items: |
| 51 | + t = get_type(v) |
| 52 | + |
| 53 | + shelled_types = get_core_types(t) |
| 54 | + expected_types = [t for t in shelled_types if is_acceptable_kls(t)] |
| 55 | + if expected_types: |
| 56 | + yield (name, expected_types) # type_ is the most inner type |
| 57 | +``` |
| 58 | + |
| 59 | +object_fields and object_field_pairs will be affected |
| 60 | + |
| 61 | +```python |
| 62 | +all_fields, object_fields, object_field_pairs = _get_all_fields_and_object_fields(kls) |
| 63 | +``` |
| 64 | + |
| 65 | +object_fields: |
| 66 | + |
| 67 | +```python |
| 68 | + |
| 69 | +object_fields_without_resolver = [a[0] for a in object_fields if a[0] not in fields_with_resolver] |
| 70 | + |
| 71 | +info: KlsMetaType = { |
| 72 | + 'resolve': resolve_fields, |
| 73 | + 'resolve_params': resolve_params, |
| 74 | + 'post': post_fields, |
| 75 | + 'post_params': post_params, |
| 76 | + 'post_default_handler_params': post_default_handler_params, |
| 77 | + 'raw_object_fields': object_fields_without_resolver, # <----- here |
| 78 | + 'object_fields': [], |
| 79 | + 'expose_dict': expose_dict, |
| 80 | + 'collect_dict': collect_dict, |
| 81 | + 'kls': kls, |
| 82 | + 'has_context': has_context, |
| 83 | + 'should_traverse': False |
| 84 | +} |
| 85 | + |
| 86 | +for field, shelled_type in (obj for obj in object_fields if obj[0] in object_fields_without_resolver): |
| 87 | + walker(shelled_type, ancestors + [(field, kls_name)]) |
| 88 | +``` |
0 commit comments