pydantic-ui 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.
- pydantic_ui-0.1.0/.gitignore +54 -0
- pydantic_ui-0.1.0/PKG-INFO +291 -0
- pydantic_ui-0.1.0/README.md +252 -0
- pydantic_ui-0.1.0/pydantic_ui/__init__.py +20 -0
- pydantic_ui-0.1.0/pydantic_ui/app.py +468 -0
- pydantic_ui-0.1.0/pydantic_ui/config.py +176 -0
- pydantic_ui-0.1.0/pydantic_ui/controller.py +235 -0
- pydantic_ui-0.1.0/pydantic_ui/events.py +87 -0
- pydantic_ui-0.1.0/pydantic_ui/handlers.py +240 -0
- pydantic_ui-0.1.0/pydantic_ui/models.py +100 -0
- pydantic_ui-0.1.0/pydantic_ui/schema.py +414 -0
- pydantic_ui-0.1.0/pydantic_ui/sessions.py +197 -0
- pydantic_ui-0.1.0/pydantic_ui/utils.py +194 -0
- pydantic_ui-0.1.0/pyproject.toml +122 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
frontend/coverage/*
|
|
2
|
+
examples/basic/user_input/*
|
|
3
|
+
# Python
|
|
4
|
+
__pycache__/
|
|
5
|
+
*.py[cod]
|
|
6
|
+
*$py.class
|
|
7
|
+
*.so
|
|
8
|
+
.Python
|
|
9
|
+
build/
|
|
10
|
+
develop-eggs/
|
|
11
|
+
dist/
|
|
12
|
+
downloads/
|
|
13
|
+
eggs/
|
|
14
|
+
.eggs/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
*.egg-info/
|
|
20
|
+
.installed.cfg
|
|
21
|
+
*.egg
|
|
22
|
+
|
|
23
|
+
# Virtual environments
|
|
24
|
+
venv/
|
|
25
|
+
ENV/
|
|
26
|
+
env/
|
|
27
|
+
|
|
28
|
+
# IDE
|
|
29
|
+
.vscode/
|
|
30
|
+
.idea/
|
|
31
|
+
*.swp
|
|
32
|
+
*.swo
|
|
33
|
+
|
|
34
|
+
# Node
|
|
35
|
+
node_modules/
|
|
36
|
+
frontend/dist/
|
|
37
|
+
|
|
38
|
+
# Build artifacts (but keep the static folder structure)
|
|
39
|
+
pydantic_ui/static/*
|
|
40
|
+
!pydantic_ui/static/.gitkeep
|
|
41
|
+
|
|
42
|
+
# OS
|
|
43
|
+
.DS_Store
|
|
44
|
+
Thumbs.db
|
|
45
|
+
|
|
46
|
+
# Test
|
|
47
|
+
.pytest_cache/
|
|
48
|
+
.coverage
|
|
49
|
+
htmlcov/
|
|
50
|
+
|
|
51
|
+
# Misc
|
|
52
|
+
*.log
|
|
53
|
+
.env
|
|
54
|
+
.env.local
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pydantic-ui
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Dynamic UI for editing deeply nested Pydantic models
|
|
5
|
+
Project-URL: Homepage, https://github.com/idling-mind/pydantic-ui
|
|
6
|
+
Project-URL: Documentation, https://github.com/idling-mind/pydantic-ui#readme
|
|
7
|
+
Project-URL: Repository, https://github.com/idling-mind/pydantic-ui
|
|
8
|
+
Project-URL: Issues, https://github.com/idling-mind/pydantic-ui/issues
|
|
9
|
+
Author-email: Najeem Muhammed <najeem@gmail.com>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
Keywords: editor,fastapi,form,pydantic,react,ui
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Framework :: FastAPI
|
|
14
|
+
Classifier: Framework :: Pydantic :: 2
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Requires-Dist: fastapi>=0.100.0
|
|
26
|
+
Requires-Dist: pydantic>=2.0.0
|
|
27
|
+
Requires-Dist: uvicorn>=0.23.0
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: coverage>=7.4.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: faker>=22.0.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: httpx>=0.27.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: mypy>=1.8.0; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
|
|
34
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
|
|
35
|
+
Requires-Dist: pytest-mock>=3.12.0; extra == 'dev'
|
|
36
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
37
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
38
|
+
Description-Content-Type: text/markdown
|
|
39
|
+
|
|
40
|
+
# Pydantic UI
|
|
41
|
+
|
|
42
|
+
A dynamic, modern UI for editing deeply nested Pydantic models with FastAPI integration.
|
|
43
|
+
|
|
44
|
+

|
|
45
|
+

|
|
46
|
+

|
|
47
|
+

|
|
48
|
+
|
|
49
|
+
## Features
|
|
50
|
+
|
|
51
|
+
- 🌳 **Tree Navigation**: Sidebar showing hierarchical structure of nested models
|
|
52
|
+
- 🎨 **Dynamic Renderers**: Auto-detect appropriate input components based on field types
|
|
53
|
+
- ⚙️ **Customizable**: Override default renderers with sliders, dropdowns, date pickers, etc.
|
|
54
|
+
- 🌓 **Theme Support**: Light and dark mode with system preference detection
|
|
55
|
+
- ✅ **Validation**: Real-time validation using Pydantic validators
|
|
56
|
+
- 📦 **Easy Integration**: Mount as a FastAPI router in your existing application
|
|
57
|
+
|
|
58
|
+
## Installation
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
pip install pydantic-ui
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Quick Start
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
from fastapi import FastAPI
|
|
68
|
+
from pydantic import BaseModel, Field
|
|
69
|
+
from typing import Annotated
|
|
70
|
+
from pydantic_ui import create_pydantic_ui, FieldConfig, Renderer
|
|
71
|
+
|
|
72
|
+
# Define your Pydantic model
|
|
73
|
+
class Address(BaseModel):
|
|
74
|
+
street: str
|
|
75
|
+
city: str
|
|
76
|
+
zipcode: str
|
|
77
|
+
|
|
78
|
+
class Person(BaseModel):
|
|
79
|
+
name: str = Field(min_length=1, max_length=100)
|
|
80
|
+
age: Annotated[int, FieldConfig(
|
|
81
|
+
renderer=Renderer.SLIDER,
|
|
82
|
+
props={"min": 0, "max": 120}
|
|
83
|
+
)]
|
|
84
|
+
email: str
|
|
85
|
+
address: Address
|
|
86
|
+
tags: list[str] = []
|
|
87
|
+
|
|
88
|
+
# Create FastAPI app and mount pydantic-ui
|
|
89
|
+
app = FastAPI()
|
|
90
|
+
|
|
91
|
+
app.include_router(
|
|
92
|
+
create_pydantic_ui(Person, prefix="/editor"),
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
if __name__ == "__main__":
|
|
96
|
+
import uvicorn
|
|
97
|
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Then visit `http://localhost:8000/editor` to see the UI.
|
|
101
|
+
|
|
102
|
+
## UI Configuration
|
|
103
|
+
|
|
104
|
+
### Global Configuration
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
from pydantic_ui import create_pydantic_ui, UIConfig
|
|
108
|
+
|
|
109
|
+
app.include_router(
|
|
110
|
+
create_pydantic_ui(
|
|
111
|
+
Person,
|
|
112
|
+
ui_config=UIConfig(
|
|
113
|
+
title="Person Editor",
|
|
114
|
+
description="Edit person details",
|
|
115
|
+
theme="system", # "light", "dark", or "system"
|
|
116
|
+
read_only=False,
|
|
117
|
+
show_validation=True,
|
|
118
|
+
),
|
|
119
|
+
prefix="/editor"
|
|
120
|
+
),
|
|
121
|
+
)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Per-Field Configuration
|
|
125
|
+
|
|
126
|
+
Use `Annotated` with `FieldConfig` to customize individual fields:
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
from typing import Annotated
|
|
130
|
+
from pydantic_ui import FieldConfig, Renderer
|
|
131
|
+
|
|
132
|
+
class Settings(BaseModel):
|
|
133
|
+
# Slider for numeric values
|
|
134
|
+
volume: Annotated[int, FieldConfig(
|
|
135
|
+
renderer=Renderer.SLIDER,
|
|
136
|
+
label="Volume Level",
|
|
137
|
+
help_text="Adjust the volume",
|
|
138
|
+
props={"min": 0, "max": 100, "step": 5}
|
|
139
|
+
)] = 50
|
|
140
|
+
|
|
141
|
+
# Dropdown for enum-like fields
|
|
142
|
+
theme: Annotated[str, FieldConfig(
|
|
143
|
+
renderer=Renderer.SELECT,
|
|
144
|
+
props={"options": ["light", "dark", "auto"]}
|
|
145
|
+
)] = "auto"
|
|
146
|
+
|
|
147
|
+
# Toggle instead of checkbox
|
|
148
|
+
notifications: Annotated[bool, FieldConfig(
|
|
149
|
+
renderer=Renderer.TOGGLE
|
|
150
|
+
)] = True
|
|
151
|
+
|
|
152
|
+
# Text area for long text
|
|
153
|
+
bio: Annotated[str, FieldConfig(
|
|
154
|
+
renderer=Renderer.TEXT_AREA,
|
|
155
|
+
props={"rows": 5, "placeholder": "Tell us about yourself..."}
|
|
156
|
+
)] = ""
|
|
157
|
+
|
|
158
|
+
# Hidden fields
|
|
159
|
+
internal_id: Annotated[str, FieldConfig(hidden=True)]
|
|
160
|
+
|
|
161
|
+
# Read-only fields
|
|
162
|
+
created_at: Annotated[str, FieldConfig(read_only=True)]
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Available Renderers
|
|
166
|
+
|
|
167
|
+
| Renderer | Description | Props |
|
|
168
|
+
|----------|-------------|-------|
|
|
169
|
+
| `auto` | Auto-detect based on type | - |
|
|
170
|
+
| `text_input` | Standard text input | `placeholder`, `maxLength` |
|
|
171
|
+
| `text_area` | Multi-line text | `rows`, `placeholder` |
|
|
172
|
+
| `number_input` | Numeric input | `min`, `max`, `step` |
|
|
173
|
+
| `slider` | Slider control | `min`, `max`, `step`, `marks` |
|
|
174
|
+
| `checkbox` | Checkbox | - |
|
|
175
|
+
| `toggle` | Toggle switch | - |
|
|
176
|
+
| `select` | Dropdown select | `options` |
|
|
177
|
+
| `multi_select` | Multi-select | `options` |
|
|
178
|
+
| `date_picker` | Date picker | `format` |
|
|
179
|
+
| `color_picker` | Color picker | - |
|
|
180
|
+
| `password` | Password input | - |
|
|
181
|
+
| `email` | Email input | - |
|
|
182
|
+
| `url` | URL input | - |
|
|
183
|
+
|
|
184
|
+
## Data Handlers
|
|
185
|
+
|
|
186
|
+
### Custom Data Loading and Saving
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
from pydantic_ui import create_pydantic_ui
|
|
190
|
+
|
|
191
|
+
pydantic_ui = create_pydantic_ui(Person, prefix="/editor")
|
|
192
|
+
app.include_router(pydantic_ui)
|
|
193
|
+
|
|
194
|
+
@pydantic_ui.data_loader
|
|
195
|
+
async def load_person() -> Person:
|
|
196
|
+
"""Load data from your database or file."""
|
|
197
|
+
return await database.get_person(id=1)
|
|
198
|
+
|
|
199
|
+
@pydantic_ui.data_saver
|
|
200
|
+
async def save_person(data: Person) -> None:
|
|
201
|
+
"""Save data to your database or file."""
|
|
202
|
+
await database.update_person(id=1, data=data)
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Initial Data
|
|
206
|
+
|
|
207
|
+
```python
|
|
208
|
+
initial_person = Person(
|
|
209
|
+
name="John Doe",
|
|
210
|
+
age=30,
|
|
211
|
+
email="john@example.com",
|
|
212
|
+
address=Address(street="123 Main St", city="NYC", zipcode="10001"),
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
app.include_router(
|
|
216
|
+
create_pydantic_ui(
|
|
217
|
+
Person,
|
|
218
|
+
initial_data=initial_person,
|
|
219
|
+
prefix="/editor"
|
|
220
|
+
),
|
|
221
|
+
)
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## API Endpoints
|
|
225
|
+
|
|
226
|
+
When mounted at `/editor`, the following endpoints are available:
|
|
227
|
+
|
|
228
|
+
| Method | Endpoint | Description |
|
|
229
|
+
|--------|----------|-------------|
|
|
230
|
+
| GET | `/editor/` | Serve the React UI |
|
|
231
|
+
| GET | `/editor/api/schema` | Get the model schema |
|
|
232
|
+
| GET | `/editor/api/data` | Get current data |
|
|
233
|
+
| POST | `/editor/api/data` | Update data |
|
|
234
|
+
| PATCH | `/editor/api/data` | Partial update |
|
|
235
|
+
| POST | `/editor/api/validate` | Validate without saving |
|
|
236
|
+
| GET | `/editor/api/config` | Get UI configuration |
|
|
237
|
+
|
|
238
|
+
## Examples
|
|
239
|
+
|
|
240
|
+
See the [examples](./examples/) directory for more complete examples:
|
|
241
|
+
|
|
242
|
+
- [Basic Usage](./examples/basic/)
|
|
243
|
+
- [Custom Renderers](./examples/custom_renderers/)
|
|
244
|
+
- [Complex Nested Models](./examples/complex_models/)
|
|
245
|
+
|
|
246
|
+
## Development
|
|
247
|
+
|
|
248
|
+
### Setup
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
# Clone the repository
|
|
252
|
+
git clone https://github.com/yourusername/pydantic-ui.git
|
|
253
|
+
cd pydantic-ui
|
|
254
|
+
|
|
255
|
+
# Install dependencies
|
|
256
|
+
pip install -e ".[dev]"
|
|
257
|
+
|
|
258
|
+
# Install frontend dependencies
|
|
259
|
+
cd frontend
|
|
260
|
+
npm install
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Running Tests
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
# Backend tests
|
|
267
|
+
pytest
|
|
268
|
+
|
|
269
|
+
# Frontend tests
|
|
270
|
+
cd frontend
|
|
271
|
+
npm test
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Building
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
# Build frontend
|
|
278
|
+
cd frontend
|
|
279
|
+
npm run build:package
|
|
280
|
+
|
|
281
|
+
# Build Python package
|
|
282
|
+
python -m build
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## Contributing
|
|
286
|
+
|
|
287
|
+
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
288
|
+
|
|
289
|
+
## License
|
|
290
|
+
|
|
291
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# Pydantic UI
|
|
2
|
+
|
|
3
|
+
A dynamic, modern UI for editing deeply nested Pydantic models with FastAPI integration.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+

|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- 🌳 **Tree Navigation**: Sidebar showing hierarchical structure of nested models
|
|
13
|
+
- 🎨 **Dynamic Renderers**: Auto-detect appropriate input components based on field types
|
|
14
|
+
- ⚙️ **Customizable**: Override default renderers with sliders, dropdowns, date pickers, etc.
|
|
15
|
+
- 🌓 **Theme Support**: Light and dark mode with system preference detection
|
|
16
|
+
- ✅ **Validation**: Real-time validation using Pydantic validators
|
|
17
|
+
- 📦 **Easy Integration**: Mount as a FastAPI router in your existing application
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install pydantic-ui
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
from fastapi import FastAPI
|
|
29
|
+
from pydantic import BaseModel, Field
|
|
30
|
+
from typing import Annotated
|
|
31
|
+
from pydantic_ui import create_pydantic_ui, FieldConfig, Renderer
|
|
32
|
+
|
|
33
|
+
# Define your Pydantic model
|
|
34
|
+
class Address(BaseModel):
|
|
35
|
+
street: str
|
|
36
|
+
city: str
|
|
37
|
+
zipcode: str
|
|
38
|
+
|
|
39
|
+
class Person(BaseModel):
|
|
40
|
+
name: str = Field(min_length=1, max_length=100)
|
|
41
|
+
age: Annotated[int, FieldConfig(
|
|
42
|
+
renderer=Renderer.SLIDER,
|
|
43
|
+
props={"min": 0, "max": 120}
|
|
44
|
+
)]
|
|
45
|
+
email: str
|
|
46
|
+
address: Address
|
|
47
|
+
tags: list[str] = []
|
|
48
|
+
|
|
49
|
+
# Create FastAPI app and mount pydantic-ui
|
|
50
|
+
app = FastAPI()
|
|
51
|
+
|
|
52
|
+
app.include_router(
|
|
53
|
+
create_pydantic_ui(Person, prefix="/editor"),
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
if __name__ == "__main__":
|
|
57
|
+
import uvicorn
|
|
58
|
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Then visit `http://localhost:8000/editor` to see the UI.
|
|
62
|
+
|
|
63
|
+
## UI Configuration
|
|
64
|
+
|
|
65
|
+
### Global Configuration
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from pydantic_ui import create_pydantic_ui, UIConfig
|
|
69
|
+
|
|
70
|
+
app.include_router(
|
|
71
|
+
create_pydantic_ui(
|
|
72
|
+
Person,
|
|
73
|
+
ui_config=UIConfig(
|
|
74
|
+
title="Person Editor",
|
|
75
|
+
description="Edit person details",
|
|
76
|
+
theme="system", # "light", "dark", or "system"
|
|
77
|
+
read_only=False,
|
|
78
|
+
show_validation=True,
|
|
79
|
+
),
|
|
80
|
+
prefix="/editor"
|
|
81
|
+
),
|
|
82
|
+
)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Per-Field Configuration
|
|
86
|
+
|
|
87
|
+
Use `Annotated` with `FieldConfig` to customize individual fields:
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from typing import Annotated
|
|
91
|
+
from pydantic_ui import FieldConfig, Renderer
|
|
92
|
+
|
|
93
|
+
class Settings(BaseModel):
|
|
94
|
+
# Slider for numeric values
|
|
95
|
+
volume: Annotated[int, FieldConfig(
|
|
96
|
+
renderer=Renderer.SLIDER,
|
|
97
|
+
label="Volume Level",
|
|
98
|
+
help_text="Adjust the volume",
|
|
99
|
+
props={"min": 0, "max": 100, "step": 5}
|
|
100
|
+
)] = 50
|
|
101
|
+
|
|
102
|
+
# Dropdown for enum-like fields
|
|
103
|
+
theme: Annotated[str, FieldConfig(
|
|
104
|
+
renderer=Renderer.SELECT,
|
|
105
|
+
props={"options": ["light", "dark", "auto"]}
|
|
106
|
+
)] = "auto"
|
|
107
|
+
|
|
108
|
+
# Toggle instead of checkbox
|
|
109
|
+
notifications: Annotated[bool, FieldConfig(
|
|
110
|
+
renderer=Renderer.TOGGLE
|
|
111
|
+
)] = True
|
|
112
|
+
|
|
113
|
+
# Text area for long text
|
|
114
|
+
bio: Annotated[str, FieldConfig(
|
|
115
|
+
renderer=Renderer.TEXT_AREA,
|
|
116
|
+
props={"rows": 5, "placeholder": "Tell us about yourself..."}
|
|
117
|
+
)] = ""
|
|
118
|
+
|
|
119
|
+
# Hidden fields
|
|
120
|
+
internal_id: Annotated[str, FieldConfig(hidden=True)]
|
|
121
|
+
|
|
122
|
+
# Read-only fields
|
|
123
|
+
created_at: Annotated[str, FieldConfig(read_only=True)]
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Available Renderers
|
|
127
|
+
|
|
128
|
+
| Renderer | Description | Props |
|
|
129
|
+
|----------|-------------|-------|
|
|
130
|
+
| `auto` | Auto-detect based on type | - |
|
|
131
|
+
| `text_input` | Standard text input | `placeholder`, `maxLength` |
|
|
132
|
+
| `text_area` | Multi-line text | `rows`, `placeholder` |
|
|
133
|
+
| `number_input` | Numeric input | `min`, `max`, `step` |
|
|
134
|
+
| `slider` | Slider control | `min`, `max`, `step`, `marks` |
|
|
135
|
+
| `checkbox` | Checkbox | - |
|
|
136
|
+
| `toggle` | Toggle switch | - |
|
|
137
|
+
| `select` | Dropdown select | `options` |
|
|
138
|
+
| `multi_select` | Multi-select | `options` |
|
|
139
|
+
| `date_picker` | Date picker | `format` |
|
|
140
|
+
| `color_picker` | Color picker | - |
|
|
141
|
+
| `password` | Password input | - |
|
|
142
|
+
| `email` | Email input | - |
|
|
143
|
+
| `url` | URL input | - |
|
|
144
|
+
|
|
145
|
+
## Data Handlers
|
|
146
|
+
|
|
147
|
+
### Custom Data Loading and Saving
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
from pydantic_ui import create_pydantic_ui
|
|
151
|
+
|
|
152
|
+
pydantic_ui = create_pydantic_ui(Person, prefix="/editor")
|
|
153
|
+
app.include_router(pydantic_ui)
|
|
154
|
+
|
|
155
|
+
@pydantic_ui.data_loader
|
|
156
|
+
async def load_person() -> Person:
|
|
157
|
+
"""Load data from your database or file."""
|
|
158
|
+
return await database.get_person(id=1)
|
|
159
|
+
|
|
160
|
+
@pydantic_ui.data_saver
|
|
161
|
+
async def save_person(data: Person) -> None:
|
|
162
|
+
"""Save data to your database or file."""
|
|
163
|
+
await database.update_person(id=1, data=data)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Initial Data
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
initial_person = Person(
|
|
170
|
+
name="John Doe",
|
|
171
|
+
age=30,
|
|
172
|
+
email="john@example.com",
|
|
173
|
+
address=Address(street="123 Main St", city="NYC", zipcode="10001"),
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
app.include_router(
|
|
177
|
+
create_pydantic_ui(
|
|
178
|
+
Person,
|
|
179
|
+
initial_data=initial_person,
|
|
180
|
+
prefix="/editor"
|
|
181
|
+
),
|
|
182
|
+
)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## API Endpoints
|
|
186
|
+
|
|
187
|
+
When mounted at `/editor`, the following endpoints are available:
|
|
188
|
+
|
|
189
|
+
| Method | Endpoint | Description |
|
|
190
|
+
|--------|----------|-------------|
|
|
191
|
+
| GET | `/editor/` | Serve the React UI |
|
|
192
|
+
| GET | `/editor/api/schema` | Get the model schema |
|
|
193
|
+
| GET | `/editor/api/data` | Get current data |
|
|
194
|
+
| POST | `/editor/api/data` | Update data |
|
|
195
|
+
| PATCH | `/editor/api/data` | Partial update |
|
|
196
|
+
| POST | `/editor/api/validate` | Validate without saving |
|
|
197
|
+
| GET | `/editor/api/config` | Get UI configuration |
|
|
198
|
+
|
|
199
|
+
## Examples
|
|
200
|
+
|
|
201
|
+
See the [examples](./examples/) directory for more complete examples:
|
|
202
|
+
|
|
203
|
+
- [Basic Usage](./examples/basic/)
|
|
204
|
+
- [Custom Renderers](./examples/custom_renderers/)
|
|
205
|
+
- [Complex Nested Models](./examples/complex_models/)
|
|
206
|
+
|
|
207
|
+
## Development
|
|
208
|
+
|
|
209
|
+
### Setup
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
# Clone the repository
|
|
213
|
+
git clone https://github.com/yourusername/pydantic-ui.git
|
|
214
|
+
cd pydantic-ui
|
|
215
|
+
|
|
216
|
+
# Install dependencies
|
|
217
|
+
pip install -e ".[dev]"
|
|
218
|
+
|
|
219
|
+
# Install frontend dependencies
|
|
220
|
+
cd frontend
|
|
221
|
+
npm install
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Running Tests
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
# Backend tests
|
|
228
|
+
pytest
|
|
229
|
+
|
|
230
|
+
# Frontend tests
|
|
231
|
+
cd frontend
|
|
232
|
+
npm test
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Building
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
# Build frontend
|
|
239
|
+
cd frontend
|
|
240
|
+
npm run build:package
|
|
241
|
+
|
|
242
|
+
# Build Python package
|
|
243
|
+
python -m build
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Contributing
|
|
247
|
+
|
|
248
|
+
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
249
|
+
|
|
250
|
+
## License
|
|
251
|
+
|
|
252
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pydantic UI - Dynamic UI for editing deeply nested Pydantic models.
|
|
3
|
+
|
|
4
|
+
A FastAPI-based package that provides a modern React UI for editing
|
|
5
|
+
Pydantic models with tree navigation and customizable field renderers.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from pydantic_ui.app import create_pydantic_ui
|
|
9
|
+
from pydantic_ui.config import ActionButton, FieldConfig, Renderer, UIConfig
|
|
10
|
+
from pydantic_ui.controller import PydanticUIController
|
|
11
|
+
|
|
12
|
+
__version__ = "0.1.0"
|
|
13
|
+
__all__ = [
|
|
14
|
+
"create_pydantic_ui",
|
|
15
|
+
"UIConfig",
|
|
16
|
+
"FieldConfig",
|
|
17
|
+
"Renderer",
|
|
18
|
+
"ActionButton",
|
|
19
|
+
"PydanticUIController",
|
|
20
|
+
]
|