codeforms 0.1.0__tar.gz

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.
@@ -0,0 +1,39 @@
1
+ # This workflow will upload a Python Package using Twine when a release is created
2
+ # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries
3
+
4
+ # This workflow uses actions that are not certified by GitHub.
5
+ # They are provided by a third-party and are governed by
6
+ # separate terms of service, privacy policy, and support
7
+ # documentation.
8
+
9
+ name: Upload Python Package
10
+
11
+ on:
12
+ release:
13
+ types: [published]
14
+
15
+ permissions:
16
+ contents: read
17
+
18
+ jobs:
19
+ deploy:
20
+
21
+ runs-on: ubuntu-latest
22
+
23
+ steps:
24
+ - uses: actions/checkout@v3
25
+ - name: Set up Python
26
+ uses: actions/setup-python@v3
27
+ with:
28
+ python-version: '3.x'
29
+ - name: Install dependencies
30
+ run: |
31
+ python -m pip install --upgrade pip
32
+ pip install build
33
+ - name: Build package
34
+ run: python -m build
35
+ - name: Publish package
36
+ uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
37
+ with:
38
+ user: __token__
39
+ password: ${{ secrets.PYPI_API_TOKEN }}
@@ -0,0 +1,28 @@
1
+ name: Tests
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+
13
+ steps:
14
+ - name: Checkout
15
+ uses: actions/checkout@v4
16
+
17
+ - name: Set up Python
18
+ uses: actions/setup-python@v5
19
+ with:
20
+ python-version: "3.12"
21
+
22
+ - name: Install dependencies
23
+ run: |
24
+ python -m pip install --upgrade pip
25
+ pip install -e ".[dev]"
26
+
27
+ - name: Run test suite
28
+ run: pytest -q
@@ -0,0 +1,20 @@
1
+ # Python-generated files
2
+ *.py[oc]
3
+ build/
4
+ dist/
5
+ wheels/
6
+ *.egg-info
7
+
8
+ # Virtual environments
9
+ .venv
10
+
11
+ todo
12
+
13
+ # Agents
14
+ CLAUDE.md
15
+ .claude
16
+
17
+ # Caches
18
+ .uv-cache
19
+ .pytest_cache
20
+ __pycache__/
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Juan Pablo Manson
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,263 @@
1
+ Metadata-Version: 2.4
2
+ Name: codeforms
3
+ Version: 0.1.0
4
+ Summary: Python library for creating, validating, and rendering web forms using Pydantic
5
+ License-Expression: MIT
6
+ License-File: LICENSE
7
+ Requires-Python: >=3.12
8
+ Requires-Dist: pydantic[email]>=2.0
9
+ Provides-Extra: dev
10
+ Requires-Dist: pytest>=8.0; extra == 'dev'
11
+ Description-Content-Type: text/markdown
12
+
13
+ # codeforms
14
+
15
+ A Python library for dynamically creating, validating, and rendering web forms using [Pydantic](https://docs.pydantic.dev/).
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ pip install codeforms
21
+ ```
22
+
23
+ Or with [uv](https://docs.astral.sh/uv/):
24
+
25
+ ```bash
26
+ uv add codeforms
27
+ ```
28
+
29
+ Requires Python 3.12+.
30
+
31
+ ## Quick Start
32
+
33
+ ### Creating a Form
34
+
35
+ Everything starts with the `Form` class. A form is defined with a name and a list of fields.
36
+
37
+ ```python
38
+ from codeforms import Form, TextField, EmailField, NumberField
39
+
40
+ form = Form(
41
+ name="UserRegistration",
42
+ fields=[
43
+ TextField(name="full_name", label="Full Name", required=True),
44
+ EmailField(name="email", label="Email", required=True),
45
+ NumberField(name="age", label="Age"),
46
+ ]
47
+ )
48
+ ```
49
+
50
+ ### The `Form` Class
51
+
52
+ The `Form` class is the main container for your form structure.
53
+
54
+ - `id` — Auto-generated UUID.
55
+ - `name` — Form name (used in HTML export and validation).
56
+ - `fields` — A list of field objects (e.g. `TextField`, `EmailField`).
57
+ - `css_classes` — Optional CSS classes for the `<form>` tag.
58
+ - `version` — Form version number.
59
+ - `attributes` — Dictionary of additional HTML attributes for the `<form>` tag.
60
+
61
+ ## Field Types
62
+
63
+ All fields inherit from `FormFieldBase` and share these common attributes:
64
+
65
+ - `name` — Field name (maps to `name` in HTML).
66
+ - `label` — User-visible label.
67
+ - `field_type` — Field type (`FieldType` enum).
68
+ - `required` — Whether the field is mandatory.
69
+ - `placeholder` — Placeholder text inside the field.
70
+ - `default_value` — Default value.
71
+ - `help_text` — Help text displayed below the field.
72
+ - `css_classes` — CSS classes for the field element.
73
+ - `readonly` — Whether the field is read-only.
74
+ - `attributes` — Additional HTML attributes for the `<input>` tag.
75
+
76
+ ### Available Fields
77
+
78
+ - **`TextField`** — Generic text input (`<input type="text">`).
79
+ - `minlength`, `maxlength`: Min/max text length.
80
+ - `pattern`: Regex pattern for validation.
81
+ - **`EmailField`** — Email address (`<input type="email">`).
82
+ - **`NumberField`** — Numeric value (`<input type="number">`).
83
+ - `min_value`, `max_value`: Allowed value range.
84
+ - `step`: Increment step.
85
+ - **`DateField`** — Date picker (`<input type="date">`).
86
+ - `min_date`, `max_date`: Allowed date range.
87
+ - **`SelectField`** — Dropdown select (`<select>`).
88
+ - `options`: List of `SelectOption(value="...", label="...")`.
89
+ - `multiple`: Enables multi-select.
90
+ - `min_selected`, `max_selected`: Selection count limits (multi-select only).
91
+ - **`RadioField`** — Radio buttons (`<input type="radio">`).
92
+ - `options`: List of `SelectOption`.
93
+ - `inline`: Display options inline.
94
+ - **`CheckboxField`** — Single checkbox (`<input type="checkbox">`).
95
+ - **`CheckboxGroupField`** — Group of checkboxes.
96
+ - `options`: List of `SelectOption`.
97
+ - `inline`: Display options inline.
98
+ - **`FileField`** — File upload (`<input type="file">`).
99
+ - `accept`: Accepted file types (e.g. `"image/*,.pdf"`).
100
+ - `multiple`: Allow multiple file uploads.
101
+ - **`HiddenField`** — Hidden field (`<input type="hidden">`).
102
+
103
+ ## Data Validation
104
+
105
+ codeforms offers multiple ways to validate user-submitted data, leveraging Pydantic's validation engine.
106
+
107
+ ### Recommended: `FormDataValidator`
108
+
109
+ The most robust approach is `FormDataValidator.create_model`, which dynamically generates a Pydantic model from your form definition. This gives you powerful validations and detailed error messages automatically.
110
+
111
+ ```python
112
+ from codeforms import Form, FormDataValidator, TextField, SelectField, SelectOption
113
+ from pydantic import ValidationError
114
+
115
+ # 1. Define your form
116
+ form = Form(
117
+ name="MyForm",
118
+ fields=[
119
+ TextField(name="name", label="Name", required=True),
120
+ SelectField(
121
+ name="country",
122
+ label="Country",
123
+ options=[
124
+ SelectOption(value="us", label="United States"),
125
+ SelectOption(value="uk", label="United Kingdom"),
126
+ ]
127
+ )
128
+ ]
129
+ )
130
+
131
+ # 2. Create the validation model
132
+ ValidationModel = FormDataValidator.create_model(form)
133
+
134
+ # 3. Validate incoming data
135
+ user_data = {"name": "John", "country": "us"}
136
+
137
+ try:
138
+ validated = ValidationModel.model_validate(user_data)
139
+ print("Valid!", validated)
140
+ except ValidationError as e:
141
+ print("Validation errors:", e.errors())
142
+ ```
143
+
144
+ This approach integrates seamlessly with API backends like FastAPI or Flask, since it produces standard Pydantic models.
145
+
146
+ ### Other Validation Methods
147
+
148
+ Two simpler alternatives exist, though `FormDataValidator` is preferred:
149
+
150
+ 1. `form.validate_data(data)` — Built-in method on the `Form` class. Less flexible; doesn't produce Pydantic models.
151
+ 2. `validate_form_data(form, data)` — Standalone function with basic validation logic.
152
+
153
+ ## Exporting Forms
154
+
155
+ Once your form is defined, you can export it to different formats.
156
+
157
+ ```python
158
+ # Export to plain HTML
159
+ html_output = form.export('html', submit=True)
160
+ print(html_output['output'])
161
+
162
+ # Export to HTML with Bootstrap 5 classes
163
+ bootstrap_output = form.export('html_bootstrap5', submit=True)
164
+ print(bootstrap_output['output'])
165
+
166
+ # Export to JSON
167
+ json_output = form.to_json()
168
+ print(json_output)
169
+
170
+ # Export to a Python dictionary
171
+ dict_output = form.to_dict()
172
+ print(dict_output)
173
+ ```
174
+
175
+ ### Supported Formats
176
+
177
+ | Format | Description |
178
+ |---|---|
179
+ | `html` | Semantic HTML |
180
+ | `html_bootstrap4` | HTML with Bootstrap 4 classes |
181
+ | `html_bootstrap5` | HTML with Bootstrap 5 classes |
182
+ | `json` | JSON representation of the form |
183
+ | `dict` | Python dictionary representation |
184
+
185
+ HTML export can also generate a `<script>` block for basic client-side validation.
186
+
187
+ ## Internationalization (i18n)
188
+
189
+ All validation and export messages are locale-aware. **English** (`en`) and **Spanish** (`es`) are included out of the box, and you can register any additional language at runtime via `register_locale()`.
190
+
191
+ ### Switching Locales
192
+
193
+ ```python
194
+ from codeforms import set_locale, get_locale, get_available_locales
195
+
196
+ print(get_locale()) # "en"
197
+ print(get_available_locales()) # ["en", "es"]
198
+
199
+ set_locale("es")
200
+ # All validation messages will now be in Spanish
201
+ ```
202
+
203
+ ### Registering a Custom Locale
204
+
205
+ You can add any locale at runtime. Missing keys automatically fall back to English.
206
+
207
+ ```python
208
+ from codeforms import register_locale, set_locale
209
+
210
+ register_locale("pt", {
211
+ "field.required": "Este campo é obrigatório",
212
+ "field.required_named": "O campo {name} é obrigatório",
213
+ "email.invalid": "E-mail inválido",
214
+ "number.min_value": "O valor deve ser maior ou igual a {min}",
215
+ "form.validation_success": "Dados validados com sucesso",
216
+ "form.data_validation_error": "Erro na validação dos dados",
217
+ })
218
+
219
+ set_locale("pt")
220
+ ```
221
+
222
+ ### Using the Translation Function
223
+
224
+ The `t()` function translates a message key, with optional interpolation:
225
+
226
+ ```python
227
+ from codeforms import t, set_locale
228
+
229
+ set_locale("en")
230
+ print(t("field.required")) # "This field is required"
231
+ print(t("field.required_named", name="email")) # "The field email is required"
232
+
233
+ set_locale("es")
234
+ print(t("field.required")) # "Este campo es requerido"
235
+ print(t("text.minlength", min=3)) # "La longitud mínima es 3"
236
+ ```
237
+
238
+ ### Locale-Aware Validation
239
+
240
+ All validation functions respect the active locale:
241
+
242
+ ```python
243
+ from codeforms import Form, TextField, validate_form_data, set_locale
244
+
245
+ form = Form(
246
+ name="example",
247
+ fields=[TextField(name="name", label="Name", required=True)]
248
+ )
249
+
250
+ set_locale("en")
251
+ result = validate_form_data(form, {})
252
+ print(result["errors"][0]["message"]) # "The field name is required"
253
+
254
+ set_locale("es")
255
+ result = validate_form_data(form, {})
256
+ print(result["errors"][0]["message"]) # "El campo name es requerido"
257
+ ```
258
+
259
+ See [`examples/i18n_usage.py`](examples/i18n_usage.py) for a full working example.
260
+
261
+ ## License
262
+
263
+ MIT
@@ -0,0 +1,251 @@
1
+ # codeforms
2
+
3
+ A Python library for dynamically creating, validating, and rendering web forms using [Pydantic](https://docs.pydantic.dev/).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install codeforms
9
+ ```
10
+
11
+ Or with [uv](https://docs.astral.sh/uv/):
12
+
13
+ ```bash
14
+ uv add codeforms
15
+ ```
16
+
17
+ Requires Python 3.12+.
18
+
19
+ ## Quick Start
20
+
21
+ ### Creating a Form
22
+
23
+ Everything starts with the `Form` class. A form is defined with a name and a list of fields.
24
+
25
+ ```python
26
+ from codeforms import Form, TextField, EmailField, NumberField
27
+
28
+ form = Form(
29
+ name="UserRegistration",
30
+ fields=[
31
+ TextField(name="full_name", label="Full Name", required=True),
32
+ EmailField(name="email", label="Email", required=True),
33
+ NumberField(name="age", label="Age"),
34
+ ]
35
+ )
36
+ ```
37
+
38
+ ### The `Form` Class
39
+
40
+ The `Form` class is the main container for your form structure.
41
+
42
+ - `id` — Auto-generated UUID.
43
+ - `name` — Form name (used in HTML export and validation).
44
+ - `fields` — A list of field objects (e.g. `TextField`, `EmailField`).
45
+ - `css_classes` — Optional CSS classes for the `<form>` tag.
46
+ - `version` — Form version number.
47
+ - `attributes` — Dictionary of additional HTML attributes for the `<form>` tag.
48
+
49
+ ## Field Types
50
+
51
+ All fields inherit from `FormFieldBase` and share these common attributes:
52
+
53
+ - `name` — Field name (maps to `name` in HTML).
54
+ - `label` — User-visible label.
55
+ - `field_type` — Field type (`FieldType` enum).
56
+ - `required` — Whether the field is mandatory.
57
+ - `placeholder` — Placeholder text inside the field.
58
+ - `default_value` — Default value.
59
+ - `help_text` — Help text displayed below the field.
60
+ - `css_classes` — CSS classes for the field element.
61
+ - `readonly` — Whether the field is read-only.
62
+ - `attributes` — Additional HTML attributes for the `<input>` tag.
63
+
64
+ ### Available Fields
65
+
66
+ - **`TextField`** — Generic text input (`<input type="text">`).
67
+ - `minlength`, `maxlength`: Min/max text length.
68
+ - `pattern`: Regex pattern for validation.
69
+ - **`EmailField`** — Email address (`<input type="email">`).
70
+ - **`NumberField`** — Numeric value (`<input type="number">`).
71
+ - `min_value`, `max_value`: Allowed value range.
72
+ - `step`: Increment step.
73
+ - **`DateField`** — Date picker (`<input type="date">`).
74
+ - `min_date`, `max_date`: Allowed date range.
75
+ - **`SelectField`** — Dropdown select (`<select>`).
76
+ - `options`: List of `SelectOption(value="...", label="...")`.
77
+ - `multiple`: Enables multi-select.
78
+ - `min_selected`, `max_selected`: Selection count limits (multi-select only).
79
+ - **`RadioField`** — Radio buttons (`<input type="radio">`).
80
+ - `options`: List of `SelectOption`.
81
+ - `inline`: Display options inline.
82
+ - **`CheckboxField`** — Single checkbox (`<input type="checkbox">`).
83
+ - **`CheckboxGroupField`** — Group of checkboxes.
84
+ - `options`: List of `SelectOption`.
85
+ - `inline`: Display options inline.
86
+ - **`FileField`** — File upload (`<input type="file">`).
87
+ - `accept`: Accepted file types (e.g. `"image/*,.pdf"`).
88
+ - `multiple`: Allow multiple file uploads.
89
+ - **`HiddenField`** — Hidden field (`<input type="hidden">`).
90
+
91
+ ## Data Validation
92
+
93
+ codeforms offers multiple ways to validate user-submitted data, leveraging Pydantic's validation engine.
94
+
95
+ ### Recommended: `FormDataValidator`
96
+
97
+ The most robust approach is `FormDataValidator.create_model`, which dynamically generates a Pydantic model from your form definition. This gives you powerful validations and detailed error messages automatically.
98
+
99
+ ```python
100
+ from codeforms import Form, FormDataValidator, TextField, SelectField, SelectOption
101
+ from pydantic import ValidationError
102
+
103
+ # 1. Define your form
104
+ form = Form(
105
+ name="MyForm",
106
+ fields=[
107
+ TextField(name="name", label="Name", required=True),
108
+ SelectField(
109
+ name="country",
110
+ label="Country",
111
+ options=[
112
+ SelectOption(value="us", label="United States"),
113
+ SelectOption(value="uk", label="United Kingdom"),
114
+ ]
115
+ )
116
+ ]
117
+ )
118
+
119
+ # 2. Create the validation model
120
+ ValidationModel = FormDataValidator.create_model(form)
121
+
122
+ # 3. Validate incoming data
123
+ user_data = {"name": "John", "country": "us"}
124
+
125
+ try:
126
+ validated = ValidationModel.model_validate(user_data)
127
+ print("Valid!", validated)
128
+ except ValidationError as e:
129
+ print("Validation errors:", e.errors())
130
+ ```
131
+
132
+ This approach integrates seamlessly with API backends like FastAPI or Flask, since it produces standard Pydantic models.
133
+
134
+ ### Other Validation Methods
135
+
136
+ Two simpler alternatives exist, though `FormDataValidator` is preferred:
137
+
138
+ 1. `form.validate_data(data)` — Built-in method on the `Form` class. Less flexible; doesn't produce Pydantic models.
139
+ 2. `validate_form_data(form, data)` — Standalone function with basic validation logic.
140
+
141
+ ## Exporting Forms
142
+
143
+ Once your form is defined, you can export it to different formats.
144
+
145
+ ```python
146
+ # Export to plain HTML
147
+ html_output = form.export('html', submit=True)
148
+ print(html_output['output'])
149
+
150
+ # Export to HTML with Bootstrap 5 classes
151
+ bootstrap_output = form.export('html_bootstrap5', submit=True)
152
+ print(bootstrap_output['output'])
153
+
154
+ # Export to JSON
155
+ json_output = form.to_json()
156
+ print(json_output)
157
+
158
+ # Export to a Python dictionary
159
+ dict_output = form.to_dict()
160
+ print(dict_output)
161
+ ```
162
+
163
+ ### Supported Formats
164
+
165
+ | Format | Description |
166
+ |---|---|
167
+ | `html` | Semantic HTML |
168
+ | `html_bootstrap4` | HTML with Bootstrap 4 classes |
169
+ | `html_bootstrap5` | HTML with Bootstrap 5 classes |
170
+ | `json` | JSON representation of the form |
171
+ | `dict` | Python dictionary representation |
172
+
173
+ HTML export can also generate a `<script>` block for basic client-side validation.
174
+
175
+ ## Internationalization (i18n)
176
+
177
+ All validation and export messages are locale-aware. **English** (`en`) and **Spanish** (`es`) are included out of the box, and you can register any additional language at runtime via `register_locale()`.
178
+
179
+ ### Switching Locales
180
+
181
+ ```python
182
+ from codeforms import set_locale, get_locale, get_available_locales
183
+
184
+ print(get_locale()) # "en"
185
+ print(get_available_locales()) # ["en", "es"]
186
+
187
+ set_locale("es")
188
+ # All validation messages will now be in Spanish
189
+ ```
190
+
191
+ ### Registering a Custom Locale
192
+
193
+ You can add any locale at runtime. Missing keys automatically fall back to English.
194
+
195
+ ```python
196
+ from codeforms import register_locale, set_locale
197
+
198
+ register_locale("pt", {
199
+ "field.required": "Este campo é obrigatório",
200
+ "field.required_named": "O campo {name} é obrigatório",
201
+ "email.invalid": "E-mail inválido",
202
+ "number.min_value": "O valor deve ser maior ou igual a {min}",
203
+ "form.validation_success": "Dados validados com sucesso",
204
+ "form.data_validation_error": "Erro na validação dos dados",
205
+ })
206
+
207
+ set_locale("pt")
208
+ ```
209
+
210
+ ### Using the Translation Function
211
+
212
+ The `t()` function translates a message key, with optional interpolation:
213
+
214
+ ```python
215
+ from codeforms import t, set_locale
216
+
217
+ set_locale("en")
218
+ print(t("field.required")) # "This field is required"
219
+ print(t("field.required_named", name="email")) # "The field email is required"
220
+
221
+ set_locale("es")
222
+ print(t("field.required")) # "Este campo es requerido"
223
+ print(t("text.minlength", min=3)) # "La longitud mínima es 3"
224
+ ```
225
+
226
+ ### Locale-Aware Validation
227
+
228
+ All validation functions respect the active locale:
229
+
230
+ ```python
231
+ from codeforms import Form, TextField, validate_form_data, set_locale
232
+
233
+ form = Form(
234
+ name="example",
235
+ fields=[TextField(name="name", label="Name", required=True)]
236
+ )
237
+
238
+ set_locale("en")
239
+ result = validate_form_data(form, {})
240
+ print(result["errors"][0]["message"]) # "The field name is required"
241
+
242
+ set_locale("es")
243
+ result = validate_form_data(form, {})
244
+ print(result["errors"][0]["message"]) # "El campo name es requerido"
245
+ ```
246
+
247
+ See [`examples/i18n_usage.py`](examples/i18n_usage.py) for a full working example.
248
+
249
+ ## License
250
+
251
+ MIT