3
3
from typing import Dict , Optional , Tuple , Type , Union , List , Callable
4
4
5
5
from ..converters import Converter
6
+ from ..gen import AttributeOverride , make_dict_structure_fn , make_dict_unstructure_fn
6
7
7
8
8
9
def _make_subclasses_tree (cl : Type ) -> List [Type ]:
@@ -18,7 +19,10 @@ def _has_subclasses(cl: Type, given_subclasses: Tuple[Type]):
18
19
19
20
20
21
def include_subclasses (
21
- cl : Type , converter : Converter , subclasses : Optional [Tuple [Type ]] = None
22
+ cl : Type ,
23
+ converter : Converter ,
24
+ subclasses : Optional [Tuple [Type ]] = None ,
25
+ overrides : Optional [Dict [str , AttributeOverride ]] = None ,
22
26
) -> None :
23
27
"""
24
28
Modify the given converter so that the attrs/dataclass `cl` is un/structured as if
@@ -27,6 +31,9 @@ def include_subclasses(
27
31
28
32
Subclasses are detected using the `__subclasses__` method, or they can be explicitly
29
33
provided.
34
+
35
+ overrides is a mapping of some or all the parent class field names to attribute
36
+ overrides instantiated with :func:`cattrs.gen.override`
30
37
"""
31
38
# Due to https://github.com/python-attrs/attrs/issues/1047
32
39
collect ()
@@ -36,28 +43,35 @@ def include_subclasses(
36
43
else :
37
44
parent_subclass_tree = tuple (_make_subclasses_tree (cl ))
38
45
46
+ if overrides is None :
47
+ overrides = {}
48
+
39
49
for cl in parent_subclass_tree :
40
50
if not _has_subclasses (cl , parent_subclass_tree ):
41
51
continue
42
52
43
53
# Unstructuring ...
44
54
can_handle_unstruct , unstructure_a = gen_unstructure_handling_pair (
45
- converter , cl
55
+ converter , cl , overrides
46
56
)
47
57
# This needs to use function dispatch, using singledispatch will again
48
58
# match A and all subclasses, which is not what we want.
49
59
converter .register_unstructure_hook_func (can_handle_unstruct , unstructure_a )
50
60
51
61
# Structuring...
52
62
can_handle_struct , structure_a = gen_structure_handling_pair (
53
- converter , cl , parent_subclass_tree
63
+ converter , cl , parent_subclass_tree , overrides
54
64
)
55
65
converter .register_structure_hook_func (can_handle_struct , structure_a )
56
66
57
67
58
- def gen_unstructure_handling_pair (converter : Converter , cl : Type ):
68
+ def gen_unstructure_handling_pair (
69
+ converter : Converter ,
70
+ cl : Type ,
71
+ overrides : Optional [Dict [str , AttributeOverride ]] = None ,
72
+ ):
59
73
# This hook is for instances of A, but not instances of subclasses.
60
- base_hook = converter . gen_unstructure_attrs_fromdict (cl )
74
+ base_hook = make_dict_unstructure_fn (cl , converter , ** overrides )
61
75
62
76
def unstructure_a (val : cl , c = converter ) -> Dict :
63
77
"""
@@ -74,13 +88,16 @@ def unstructure_a(val: cl, c=converter) -> Dict:
74
88
75
89
76
90
def gen_structure_handling_pair (
77
- converter : Converter , cl : Type , given_subclasses_tree : Tuple [Type ]
91
+ converter : Converter ,
92
+ cl : Type ,
93
+ given_subclasses_tree : Tuple [Type ],
94
+ overrides : Optional [Dict [str , AttributeOverride ]] = None ,
78
95
) -> Tuple [Callable ]:
79
96
actual_subclass_tree = tuple (_make_subclasses_tree (cl ))
80
97
class_tree = tuple (set (actual_subclass_tree ) & set (given_subclasses_tree ))
81
98
subclass_union = Union [class_tree ]
82
99
dis_fn = converter ._get_dis_func (subclass_union )
83
- base_struct_hook = converter . gen_structure_attrs_fromdict (cl )
100
+ base_struct_hook = make_dict_structure_fn (cl , converter , ** overrides )
84
101
85
102
def structure_a (val : dict , _ , c = converter , cl = cl ) -> cl :
86
103
dis_cl = dis_fn (val )
0 commit comments