@@ -66,8 +66,8 @@ def extract_config_metadata(node: ast.ClassDef) -> Optional[Dict]:
66
66
67
67
This function parses the AST (abstract syntax tree) of a Config class to retrieve:
68
68
- The class-level docstring.
69
- - A dictionary mapping each field name to its associated type, default value (if any) ,
70
- and metadata (such as help text and numeric constraints).
69
+ - A dictionary mapping each field name to a dictionary with field information ,
70
+ including its type, default value (if any), and metadata (such as help text and constraints).
71
71
72
72
Parameters
73
73
----------
@@ -79,8 +79,7 @@ def extract_config_metadata(node: ast.ClassDef) -> Optional[Dict]:
79
79
Optional[Dict]
80
80
A dictionary with keys:
81
81
- 'docstring': The docstring of the class.
82
- - 'fields': A mapping from field names to a dictionary with field information,
83
- including 'type' (str), and optionally 'default' and 'metadata'.
82
+ - 'fields': A mapping from field names to field information (type, default, metadata).
84
83
Returns None if no fields are found.
85
84
"""
86
85
# Retrieve the class-level docstring.
@@ -99,18 +98,31 @@ def extract_config_metadata(node: ast.ClassDef) -> Optional[Dict]:
99
98
if field_type :
100
99
field_data ['type' ] = field_type
101
100
102
- # Initialize the default value as None.
103
101
default_value = None
104
102
105
103
# Check if the field value is defined using a call to the 'field' function.
106
104
if isinstance (item .value , ast .Call ) and getattr (item .value .func , 'id' , None ) == 'field' :
107
- # Iterate over keyword arguments to extract 'default' value.
105
+ # Iterate over keyword arguments to extract 'default' or 'default_factory' value.
108
106
for kw in item .value .keywords :
109
107
if kw .arg == 'default' :
110
108
try :
111
109
default_value = ast .literal_eval (kw .value )
112
110
except Exception as e :
113
111
logger .error (f"Failed to eval default for field { field_name } : { e } " )
112
+ elif kw .arg == 'default_factory' :
113
+ if isinstance (kw .value , ast .Name ):
114
+ # Handle common default factories.
115
+ if kw .value .id == 'dict' :
116
+ default_value = {}
117
+ elif kw .value .id == 'list' :
118
+ default_value = []
119
+ else :
120
+ logger .warning (f"Unknown default_factory { kw .value .id } for field { field_name } , skipping evaluation." )
121
+ else :
122
+ try :
123
+ default_value = ast .literal_eval (kw .value )
124
+ except Exception as e :
125
+ logger .error (f"Failed to eval default_factory for field { field_name } : { e } " )
114
126
# Iterate again to extract 'metadata' if available.
115
127
for kw in item .value .keywords :
116
128
if kw .arg == 'metadata' and isinstance (kw .value , ast .Dict ):
@@ -131,7 +143,6 @@ def extract_config_metadata(node: ast.ClassDef) -> Optional[Dict]:
131
143
if default_value is not None :
132
144
field_data ['default' ] = default_value
133
145
134
- # Save the processed field data under its name.
135
146
fields [field_name ] = field_data
136
147
137
148
# Return the gathered metadata if any fields were identified; otherwise, return None.
0 commit comments