Skip to content

Commit 57446df

Browse files
committed
Added: yaml constructor factory (#150)
1 parent 145e23f commit 57446df

File tree

1 file changed

+44
-129
lines changed

1 file changed

+44
-129
lines changed

libreforms_fastapi/utils/pydantic_models.py

+44-129
Original file line numberDiff line numberDiff line change
@@ -93,107 +93,8 @@ class AdminUserModel(BaseModel):
9393
return UserModel
9494

9595

96-
# Example form configuration with default values set
97-
example_form_config = {
98-
"example_form": {
99-
"text_input": {
100-
"input_type": "text",
101-
"output_type": str,
102-
"field_name": "text_input",
103-
"default": "Default Text",
104-
"validators": {
105-
"min_length": 1, # These are drawn from:
106-
"max_length": 200, # https://docs.pydantic.dev/latest/api/fields/#pydantic.fields.Field
107-
"pattern": r'^[\s\S]*$',
108-
},
109-
"required": True,
110-
"options": None,
111-
"description": "This is a text field",
112-
},
113-
"number_input": {
114-
"input_type": "number",
115-
"output_type": int,
116-
"field_name": "number_input",
117-
"default": 42,
118-
"validators": {
119-
"ge": 0, # These are drawn from:
120-
"le": 10000, # https://docs.pydantic.dev/latest/api/fields/#pydantic.fields.Field
121-
},
122-
"required": False,
123-
"options": None,
124-
"description": "This is a number field",
125-
},
126-
"email_input": {
127-
"input_type": "email",
128-
"output_type": str,
129-
"field_name": "email_input",
130-
"default": "[email protected]",
131-
"required": False,
132-
"options": None,
133-
"description": "This is an email field",
134-
},
135-
"date_input": {
136-
"input_type": "date",
137-
"output_type": date,
138-
"field_name": "date_input",
139-
"default": "2024-01-01",
140-
"required": False,
141-
"options": None,
142-
"description": "This is a date field",
143-
},
144-
"checkbox_input": {
145-
"input_type": "checkbox",
146-
"output_type": List[str],
147-
"field_name": "checkbox_input",
148-
"options": ["Option1", "Option2", "Option3"],
149-
"required": True,
150-
"default": ["Option1", "Option3"],
151-
"description": "This is a checkbox field",
152-
},
153-
"radio_input": {
154-
"input_type": "radio",
155-
"output_type": str,
156-
"field_name": "radio_input",
157-
"options": ["Option1", "Option2"],
158-
"required": False,
159-
"default": "Option1",
160-
"description": "This is a radio field",
161-
},
162-
"select_input": {
163-
"input_type": "select",
164-
"output_type": str,
165-
"field_name": "select_input",
166-
"options": ["Option1", "Option2", "Option3"],
167-
"required": False,
168-
"default": "Option2",
169-
"description": "This is a select field",
170-
},
171-
"textarea_input": {
172-
"input_type": "textarea",
173-
"output_type": str,
174-
"field_name": "textarea_input",
175-
"default": "Default textarea content.",
176-
"validators": {
177-
"min_length": 0, # A note about min-length: https://stackoverflow.com/a/10294291/13301284. Better to set a pattern and set required.
178-
"max_length": 200, # These are drawn from: https://docs.pydantic.dev/latest/api/fields/#pydantic.fields.Field
179-
"pattern": r'^[\s\S]*$',
180-
},
181-
"required": False,
182-
"options": None,
183-
"description": "This is a textarea field",
184-
},
185-
"file_input": {
186-
"input_type": "file",
187-
"output_type": bytes,
188-
"field_name": "file_input",
189-
"options": None,
190-
"required": False,
191-
"default": None, # File inputs can't have default values
192-
"description": "This is a file field",
193-
},
194-
},
195-
}
196-
96+
# The options in the `validator` field are drawn from: https://docs.pydantic.dev/latest/api/fields/#pydantic.fields.Field
97+
# A note about min-length: https://stackoverflow.com/a/10294291/13301284. Better to set a pattern and set required.
19798
EXAMPLE_FORM_CONFIG_YAML = """
19899
example_form:
199100
text_input:
@@ -290,45 +191,59 @@ class AdminUserModel(BaseModel):
290191
description: This is a file field
291192
"""
292193

194+
def get_yaml_constructors(**kwargs):
195+
"""
196+
This factory is used to build a dictionary of built-in and custom constructors that
197+
will be used in building the internal, dictionary representation of the form config.
198+
"""
199+
200+
# Default constructors for returning Python types
201+
def type_constructor_int(loader, node):
202+
return int
293203

294-
# Constructors that return Python types themselves
295-
def type_constructor_int(loader, node):
296-
return int
204+
def type_constructor_str(loader, node):
205+
return str
297206

298-
def type_constructor_str(loader, node):
299-
return str
207+
def type_constructor_date(loader, node):
208+
return date
300209

301-
def type_constructor_date(loader, node):
302-
return date
210+
def type_constructor_datetime(loader, node):
211+
return datetime
303212

304-
def type_constructor_datetime(loader, node):
305-
return datetime
213+
def type_constructor_time(loader, node):
214+
return time
306215

307-
def type_constructor_time(loader, node):
308-
return time
216+
def type_constructor_timedelta(loader, node):
217+
return timedelta
309218

310-
def type_constructor_timedelta(loader, node):
311-
return timedelta
219+
def type_constructor_list(loader, node):
220+
return list
312221

313-
def type_constructor_list(loader, node):
314-
return list
222+
def type_constructor_tuple(loader, node):
223+
return tuple
315224

316-
def type_constructor_tuple(loader, node):
317-
return tuple
225+
def type_constructor_bytes(loader, node):
226+
return bytes
318227

319-
def type_constructor_bytes(loader, node):
320-
return bytes
228+
# We create a constructor mapping that we'll use later to
229+
# register the constructors.
230+
constructor_mapping = {
231+
'!int': type_constructor_int,
232+
'!str': type_constructor_str,
233+
'!date': type_constructor_date,
234+
'!type_datetime': type_constructor_datetime,
235+
'!type_time': type_constructor_time,
236+
'!type_timedelta': type_constructor_time,
237+
'!list': type_constructor_list,
238+
'!tuple': type_constructor_list,
239+
'!bytes': type_constructor_bytes,
240+
**kwargs,
241+
}
242+
return constructor_mapping
321243

322244
# Register the type constructors
323-
yaml.add_constructor('!int', type_constructor_int)
324-
yaml.add_constructor('!str', type_constructor_str)
325-
yaml.add_constructor('!date', type_constructor_date)
326-
yaml.add_constructor('!type_datetime', type_constructor_datetime)
327-
yaml.add_constructor('!type_time', type_constructor_time)
328-
yaml.add_constructor('!type_timedelta', type_constructor_time)
329-
yaml.add_constructor('!list', type_constructor_list)
330-
yaml.add_constructor('!tuple', type_constructor_list)
331-
yaml.add_constructor('!bytes', type_constructor_bytes)
245+
for key, value in get_yaml_constructors().items():
246+
yaml.add_constructor(key, value)
332247

333248
def load_form_config(config_path=None):
334249
"""

0 commit comments

Comments
 (0)