1
+ from enum import Enum
2
+
1
3
from pydantic import BaseModel
2
4
from pydantic .fields import ModelField
3
5
4
6
from easyconfig .__const__ import ARG_NAME_IN_FILE , MISSING
5
- from easyconfig .yaml import CommentedMap
7
+ from easyconfig .yaml import CommentedMap , CommentedSeq
8
+
9
+ NoneType = type (None )
10
+
11
+
12
+ def _get_yaml_value (obj , parent_model : BaseModel , skip_none = True ):
13
+ # Sometimes enum is used with int/str
14
+ if isinstance (obj , Enum ):
15
+ return _get_yaml_value (obj .value , parent_model = parent_model , skip_none = skip_none )
16
+
17
+ # yaml native datatypes
18
+ if isinstance (obj , (int , float , str , bool , bytes , NoneType )):
19
+ return obj
20
+
21
+ if isinstance (obj , BaseModel ):
22
+ return cmap_from_model (obj , skip_none = skip_none )
23
+
24
+ if isinstance (obj , (list , tuple , set , frozenset )):
25
+ seq = CommentedSeq ()
26
+ for value in obj :
27
+ seq .append (_get_yaml_value (value , parent_model = parent_model , skip_none = skip_none ))
28
+ return seq
29
+
30
+ if isinstance (obj , dict ):
31
+ ret = CommentedMap ()
32
+ for key , value in obj .items ():
33
+ yaml_key = _get_yaml_value (key , parent_model = parent_model , skip_none = skip_none )
34
+ ret [yaml_key ] = _get_yaml_value (value , parent_model = parent_model , skip_none = skip_none )
35
+ return ret
36
+
37
+ # YAML can't serialize all data pydantic types natively, so we use the json serializer of the model
38
+ # This works since a valid json is always a valid YAML. It's not nice but it's something!
39
+ model_cfg = parent_model .__config__
40
+ str_val = model_cfg .json_dumps (obj , default = parent_model .__json_encoder__ )
41
+ return model_cfg .json_loads (str_val )
6
42
7
43
8
44
def cmap_from_model (model : BaseModel , skip_none = True ) -> CommentedMap :
@@ -20,15 +56,8 @@ def cmap_from_model(model: BaseModel, skip_none=True) -> CommentedMap:
20
56
if not field_info .extra .get (ARG_NAME_IN_FILE , True ):
21
57
continue
22
58
23
- if isinstance (value , BaseModel ):
24
- cmap [yaml_key ] = cmap_from_model (value )
25
- else :
26
- # YAML can't serialize all data pydantic types natively, so we use the json serializer of the model
27
- # This works since a valid json is always a valid YAML. It's not nice but it's something!
28
- mode_cfg = model .__config__
29
- _json_value = mode_cfg .json_dumps (
30
- {'obj' : value }, default = model .__json_encoder__ )
31
- cmap [yaml_key ] = mode_cfg .json_loads (_json_value )['obj' ]
59
+ # get yaml representation
60
+ cmap [yaml_key ] = _get_yaml_value (value , parent_model = model )
32
61
33
62
if not description :
34
63
continue
0 commit comments