codeforms 0.2.0__py3-none-any.whl → 0.2.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
codeforms/i18n.py CHANGED
@@ -28,33 +28,27 @@ from __future__ import annotations
28
28
  import copy
29
29
  from typing import Any, Dict, Optional
30
30
 
31
-
32
31
  # --- Message catalogs per locale ---
33
32
 
34
33
  _MESSAGES_EN: Dict[str, str] = {
35
34
  # Field-level validation
36
35
  "field.required": "This field is required",
37
36
  "field.required_named": "The field {name} is required",
38
-
39
37
  # TextField
40
38
  "text.minlength": "Minimum length is {min}",
41
39
  "text.maxlength": "Maximum length is {max}",
42
40
  "text.pattern_mismatch": "Value does not match the required pattern",
43
41
  "text.invalid_regex": "Invalid regex pattern",
44
-
45
42
  # EmailField
46
43
  "email.invalid": "Invalid email",
47
-
48
44
  # NumberField
49
45
  "number.min_value": "Value must be greater than or equal to {min}",
50
46
  "number.max_value": "Value must be less than or equal to {max}",
51
47
  "number.invalid": "Must be a valid number",
52
-
53
48
  # DateField
54
49
  "date.min_date": "Date must be after {min}",
55
50
  "date.max_date": "Date must be before {max}",
56
51
  "date.invalid_format": "Must be a valid date in YYYY-MM-DD format",
57
-
58
52
  # SelectField
59
53
  "select.invalid_option": "Invalid option selected",
60
54
  "select.invalid_options": "Invalid options selected",
@@ -69,40 +63,32 @@ _MESSAGES_EN: Dict[str, str] = {
69
63
  "select.max_selected_requires_multiple": "max_selected can only be used with multiple=True",
70
64
  "select.max_less_than_min": "max_selected must be greater than or equal to min_selected",
71
65
  "select.invalid_value_must_be_one_of": "Invalid value. Must be one of: {valid}",
72
-
73
66
  # RadioField
74
67
  "radio.invalid_option": "Invalid option selected",
75
68
  "radio.default_must_be_string": "Default value must be a string",
76
-
77
69
  # CheckboxField
78
70
  "checkbox.must_be_boolean": "Must be a boolean value",
79
71
  "checkbox.default_must_be_boolean": "Default value must be a boolean",
80
-
81
72
  # CheckboxGroupField
82
73
  "checkbox_group.default_must_be_list": "Default value must be a list of values",
83
74
  "checkbox_group.invalid_options": "Invalid options selected",
84
-
85
75
  # UrlField
86
76
  "url.invalid_scheme": "URL must start with http:// or https://",
87
-
88
77
  # Form-level
89
78
  "form.unique_field_names": "Field names must be unique in the form",
90
79
  "form.unique_field_names_in_group": "Field names must be unique within group '{title}'",
91
80
  "form.validation_success": "Data validated successfully",
92
81
  "form.validation_error": "Validation error",
93
82
  "form.data_validation_error": "Data validation error",
94
-
95
83
  # Export / HTML
96
84
  "export.fix_errors": "Please fix the following errors:",
97
85
  "export.submit": "Submit",
98
86
  "export.field_required": "The field {label} is required",
99
-
100
87
  # Wizard / Multi-step
101
88
  "wizard.not_a_wizard_form": "This form is not configured as a wizard (no steps found)",
102
89
  "wizard.invalid_step_index": "Invalid step index {index}, must be between 0 and {max}",
103
90
  "wizard.step_validation_failed": "Validation failed for step {step}",
104
91
  "wizard.validation_failed": "Wizard validation failed",
105
-
106
92
  # Visibility
107
93
  "visibility.unknown_operator": "Unknown visibility operator: {operator}",
108
94
  }
@@ -111,26 +97,21 @@ _MESSAGES_ES: Dict[str, str] = {
111
97
  # Validación a nivel de campo
112
98
  "field.required": "Este campo es requerido",
113
99
  "field.required_named": "El campo {name} es requerido",
114
-
115
100
  # TextField
116
101
  "text.minlength": "La longitud mínima es {min}",
117
102
  "text.maxlength": "La longitud máxima es {max}",
118
103
  "text.pattern_mismatch": "El valor no coincide con el patrón requerido",
119
104
  "text.invalid_regex": "Patrón regex inválido",
120
-
121
105
  # EmailField
122
106
  "email.invalid": "Email inválido",
123
-
124
107
  # NumberField
125
108
  "number.min_value": "El valor debe ser mayor o igual a {min}",
126
109
  "number.max_value": "El valor debe ser menor o igual a {max}",
127
110
  "number.invalid": "Debe ser un número válido",
128
-
129
111
  # DateField
130
112
  "date.min_date": "La fecha debe ser posterior a {min}",
131
113
  "date.max_date": "La fecha debe ser anterior a {max}",
132
114
  "date.invalid_format": "Debe ser una fecha válida en formato YYYY-MM-DD",
133
-
134
115
  # SelectField
135
116
  "select.invalid_option": "Opción inválida seleccionada",
136
117
  "select.invalid_options": "Opciones inválidas seleccionadas",
@@ -145,40 +126,32 @@ _MESSAGES_ES: Dict[str, str] = {
145
126
  "select.max_selected_requires_multiple": "max_selected solo puede usarse con multiple=True",
146
127
  "select.max_less_than_min": "max_selected debe ser mayor o igual que min_selected",
147
128
  "select.invalid_value_must_be_one_of": "Valor inválido. Debe ser uno de: {valid}",
148
-
149
129
  # RadioField
150
130
  "radio.invalid_option": "Opción inválida seleccionada",
151
131
  "radio.default_must_be_string": "El valor por defecto debe ser una cadena",
152
-
153
132
  # CheckboxField
154
133
  "checkbox.must_be_boolean": "Debe ser un valor booleano",
155
134
  "checkbox.default_must_be_boolean": "El valor por defecto debe ser un booleano",
156
-
157
135
  # CheckboxGroupField
158
136
  "checkbox_group.default_must_be_list": "El valor por defecto debe ser una lista de valores",
159
137
  "checkbox_group.invalid_options": "Opciones inválidas seleccionadas",
160
-
161
138
  # UrlField
162
139
  "url.invalid_scheme": "La URL debe comenzar con http:// o https://",
163
-
164
140
  # Formulario
165
141
  "form.unique_field_names": "Los nombres de los campos deben ser únicos en el formulario",
166
142
  "form.unique_field_names_in_group": "Los nombres de los campos deben ser únicos dentro del grupo '{title}'",
167
143
  "form.validation_success": "Datos validados correctamente",
168
144
  "form.validation_error": "Error en la validación",
169
145
  "form.data_validation_error": "Error en la validación de datos",
170
-
171
146
  # Exportación / HTML
172
147
  "export.fix_errors": "Por favor corrija los siguientes errores:",
173
148
  "export.submit": "Enviar",
174
149
  "export.field_required": "El campo {label} es requerido",
175
-
176
150
  # Wizard / Multi-paso
177
151
  "wizard.not_a_wizard_form": "Este formulario no está configurado como wizard (no se encontraron pasos)",
178
152
  "wizard.invalid_step_index": "Índice de paso inválido {index}, debe estar entre 0 y {max}",
179
153
  "wizard.step_validation_failed": "La validación falló para el paso {step}",
180
154
  "wizard.validation_failed": "La validación del wizard falló",
181
-
182
155
  # Visibilidad
183
156
  "visibility.unknown_operator": "Operador de visibilidad desconocido: {operator}",
184
157
  }
@@ -215,9 +188,7 @@ def set_locale(locale: str) -> None:
215
188
  global _current_locale
216
189
  if locale not in _locales:
217
190
  available = ", ".join(sorted(_locales.keys()))
218
- raise ValueError(
219
- f"Unknown locale '{locale}'. Available locales: {available}"
220
- )
191
+ raise ValueError(f"Unknown locale '{locale}'. Available locales: {available}")
221
192
  _current_locale = locale
222
193
 
223
194
 
codeforms/registry.py CHANGED
@@ -17,7 +17,7 @@ Usage:
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
- from typing import Any, Dict, List, Type, TYPE_CHECKING
20
+ from typing import TYPE_CHECKING, Any, Dict, List, Type
21
21
 
22
22
  if TYPE_CHECKING:
23
23
  from codeforms.fields import FormFieldBase
@@ -33,15 +33,16 @@ _registry_initialized: bool = False
33
33
  # Internal helpers
34
34
  # ---------------------------------------------------------------------------
35
35
 
36
+
36
37
  def _get_field_type_key(cls: Type[FormFieldBase]) -> str:
37
38
  """Extract the field_type default value as a plain string."""
38
- field_info = cls.model_fields.get('field_type')
39
+ field_info = cls.model_fields.get("field_type")
39
40
  if field_info is None:
40
41
  raise ValueError(f"{cls.__name__} has no 'field_type' field")
41
42
  default = field_info.default
42
43
  if default is None:
43
44
  raise ValueError(f"{cls.__name__} must define a default field_type value")
44
- return default.value if hasattr(default, 'value') else str(default)
45
+ return default.value if hasattr(default, "value") else str(default)
45
46
 
46
47
 
47
48
  def _register_class(cls: Type[FormFieldBase]) -> None:
@@ -61,15 +62,37 @@ def _init_builtin_types() -> None:
61
62
  _registry_initialized = True
62
63
 
63
64
  from codeforms.fields import (
64
- TextField, EmailField, NumberField, DateField,
65
- SelectField, RadioField, CheckboxField, CheckboxGroupField,
66
- FileField, HiddenField, UrlField, TextareaField, ListField,
65
+ CheckboxField,
66
+ CheckboxGroupField,
67
+ DateField,
68
+ EmailField,
69
+ FileField,
70
+ HiddenField,
71
+ ListField,
72
+ ObjectListField,
73
+ NumberField,
74
+ RadioField,
75
+ SelectField,
76
+ TextareaField,
77
+ TextField,
78
+ UrlField,
67
79
  )
68
80
 
69
81
  for cls in [
70
- TextField, EmailField, NumberField, DateField,
71
- SelectField, RadioField, CheckboxField, CheckboxGroupField,
72
- FileField, HiddenField, UrlField, TextareaField, ListField,
82
+ TextField,
83
+ EmailField,
84
+ NumberField,
85
+ DateField,
86
+ SelectField,
87
+ RadioField,
88
+ CheckboxField,
89
+ CheckboxGroupField,
90
+ FileField,
91
+ HiddenField,
92
+ UrlField,
93
+ TextareaField,
94
+ ListField,
95
+ ObjectListField,
73
96
  ]:
74
97
  _register_class(cls)
75
98
 
@@ -78,6 +101,7 @@ def _init_builtin_types() -> None:
78
101
  # Public API
79
102
  # ---------------------------------------------------------------------------
80
103
 
104
+
81
105
  def register_field_type(field_class: Type[FormFieldBase]) -> None:
82
106
  """
83
107
  Register a custom field type so it can be used in Form and FieldGroup.
@@ -104,10 +128,9 @@ def register_field_type(field_class: Type[FormFieldBase]) -> None:
104
128
  """
105
129
  _init_builtin_types()
106
130
  from codeforms.fields import FormFieldBase as _Base
131
+
107
132
  if not issubclass(field_class, _Base):
108
- raise TypeError(
109
- f"{field_class.__name__} must be a subclass of FormFieldBase"
110
- )
133
+ raise TypeError(f"{field_class.__name__} must be a subclass of FormFieldBase")
111
134
  _register_class(field_class)
112
135
 
113
136
 
@@ -153,25 +176,27 @@ def resolve_content_item(item: Any) -> Any:
153
176
  return item # already an instance
154
177
 
155
178
  # (1) Explicit container type discriminator
156
- if 'type' in item:
157
- container_type = item['type']
158
- if container_type == 'step':
179
+ if "type" in item:
180
+ container_type = item["type"]
181
+ if container_type == "step":
159
182
  from codeforms.fields import FormStep
183
+
160
184
  return FormStep.model_validate(item)
161
185
  # Unknown type values fall through to existing heuristics
162
186
 
163
187
  # (2) Legacy FieldGroup heuristic (has 'title', no 'field_type')
164
- if 'title' in item and 'field_type' not in item:
188
+ if "title" in item and "field_type" not in item:
165
189
  from codeforms.fields import FieldGroup
190
+
166
191
  return FieldGroup.model_validate(item)
167
192
 
168
193
  # (3) Field type registry lookup
169
- field_type = item.get('field_type')
194
+ field_type = item.get("field_type")
170
195
  if field_type is None:
171
196
  return item
172
197
 
173
198
  # Normalise enum → string
174
- if hasattr(field_type, 'value'):
199
+ if hasattr(field_type, "value"):
175
200
  field_type = field_type.value
176
201
 
177
202
  candidates = _field_type_registry.get(field_type)