dearpygui-forms 0.1.3__tar.gz → 0.2.1__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.
- {dearpygui_forms-0.1.3 → dearpygui_forms-0.2.1}/.gitignore +1 -0
- dearpygui_forms-0.2.1/.python-version +1 -0
- dearpygui_forms-0.2.1/PKG-INFO +64 -0
- dearpygui_forms-0.2.1/README.md +52 -0
- {dearpygui_forms-0.1.3 → dearpygui_forms-0.2.1}/pyproject.toml +4 -7
- dearpygui_forms-0.2.1/src/dearpygui_forms/__init__.py +4 -0
- dearpygui_forms-0.2.1/src/dearpygui_forms/dpg_form.py +57 -0
- dearpygui_forms-0.2.1/src/dearpygui_forms/exceptions.py +2 -0
- dearpygui_forms-0.2.1/src/dearpygui_forms/models.py +14 -0
- dearpygui_forms-0.2.1/src/dearpygui_forms/widgets.py +256 -0
- {dearpygui_forms-0.1.3 → dearpygui_forms-0.2.1}/tests/demo.py +16 -9
- dearpygui_forms-0.2.1/tests/micro_demo.py +30 -0
- dearpygui_forms-0.2.1/tests/test_models.py +37 -0
- dearpygui_forms-0.2.1/uv.lock +334 -0
- dearpygui_forms-0.1.3/.env +0 -1
- dearpygui_forms-0.1.3/.python-version +0 -1
- dearpygui_forms-0.1.3/PKG-INFO +0 -34
- dearpygui_forms-0.1.3/README.md +0 -23
- dearpygui_forms-0.1.3/src/dearpygui_forms/__init__.py +0 -124
- dearpygui_forms-0.1.3/tests/micro_demo.py +0 -20
- dearpygui_forms-0.1.3/uv.lock +0 -215
@@ -0,0 +1 @@
|
|
1
|
+
3.10
|
@@ -0,0 +1,64 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: dearpygui-forms
|
3
|
+
Version: 0.2.1
|
4
|
+
Summary: Dearpygui extention for autogeneration forms powered by pydantic.
|
5
|
+
Project-URL: homepage, https://github.com/vlewicki/dearpygui-forms
|
6
|
+
Author-email: Valentin Lewicki <vlewicki@vlewicki.ru>
|
7
|
+
Requires-Python: >=3.10
|
8
|
+
Requires-Dist: dearpygui>=2.0.0
|
9
|
+
Requires-Dist: loguru>=0.7.3
|
10
|
+
Requires-Dist: pydantic>=2.11.7
|
11
|
+
Description-Content-Type: text/markdown
|
12
|
+
|
13
|
+
# DearPyGui Forms
|
14
|
+
Generate GUI forms for your Pydantic models.
|
15
|
+
|
16
|
+
## Features
|
17
|
+
- Fill form fields with Pydantic model data
|
18
|
+
- Fill from fields with default values
|
19
|
+
- Validation on form submission
|
20
|
+
- Callbacks for form submission
|
21
|
+
|
22
|
+
|
23
|
+
Currently supported Pydantic fields:
|
24
|
+
- str
|
25
|
+
- int
|
26
|
+
- float
|
27
|
+
- bool
|
28
|
+
- datetime
|
29
|
+
- date
|
30
|
+
- time
|
31
|
+
|
32
|
+
## Example:
|
33
|
+
```python
|
34
|
+
from pprint import pprint
|
35
|
+
import dearpygui.dearpygui as dpg
|
36
|
+
from pydantic import BaseModel, Field
|
37
|
+
from dearpygui_forms import DPGForm
|
38
|
+
|
39
|
+
class User(BaseModel):
|
40
|
+
name: str = Field(default="John Doe", min_length=3)
|
41
|
+
age: int = Field(ge=18)
|
42
|
+
|
43
|
+
|
44
|
+
class Storage(BaseModel):
|
45
|
+
users: list[User] = []
|
46
|
+
|
47
|
+
class UserForm(DPGForm, model=User):
|
48
|
+
pass
|
49
|
+
|
50
|
+
|
51
|
+
dpg.create_context()
|
52
|
+
dpg.create_viewport()
|
53
|
+
|
54
|
+
store = Storage()
|
55
|
+
|
56
|
+
with dpg.window(label="User Form"):
|
57
|
+
user_form = UserForm(callback=lambda x: store.users.append(x))
|
58
|
+
user_form.add()
|
59
|
+
dpg.add_button(label="Print Users", callback=lambda: pprint(store.model_dump()))
|
60
|
+
dpg.setup_dearpygui()
|
61
|
+
dpg.show_viewport()
|
62
|
+
dpg.start_dearpygui()
|
63
|
+
dpg.destroy_context()
|
64
|
+
```
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# DearPyGui Forms
|
2
|
+
Generate GUI forms for your Pydantic models.
|
3
|
+
|
4
|
+
## Features
|
5
|
+
- Fill form fields with Pydantic model data
|
6
|
+
- Fill from fields with default values
|
7
|
+
- Validation on form submission
|
8
|
+
- Callbacks for form submission
|
9
|
+
|
10
|
+
|
11
|
+
Currently supported Pydantic fields:
|
12
|
+
- str
|
13
|
+
- int
|
14
|
+
- float
|
15
|
+
- bool
|
16
|
+
- datetime
|
17
|
+
- date
|
18
|
+
- time
|
19
|
+
|
20
|
+
## Example:
|
21
|
+
```python
|
22
|
+
from pprint import pprint
|
23
|
+
import dearpygui.dearpygui as dpg
|
24
|
+
from pydantic import BaseModel, Field
|
25
|
+
from dearpygui_forms import DPGForm
|
26
|
+
|
27
|
+
class User(BaseModel):
|
28
|
+
name: str = Field(default="John Doe", min_length=3)
|
29
|
+
age: int = Field(ge=18)
|
30
|
+
|
31
|
+
|
32
|
+
class Storage(BaseModel):
|
33
|
+
users: list[User] = []
|
34
|
+
|
35
|
+
class UserForm(DPGForm, model=User):
|
36
|
+
pass
|
37
|
+
|
38
|
+
|
39
|
+
dpg.create_context()
|
40
|
+
dpg.create_viewport()
|
41
|
+
|
42
|
+
store = Storage()
|
43
|
+
|
44
|
+
with dpg.window(label="User Form"):
|
45
|
+
user_form = UserForm(callback=lambda x: store.users.append(x))
|
46
|
+
user_form.add()
|
47
|
+
dpg.add_button(label="Print Users", callback=lambda: pprint(store.model_dump()))
|
48
|
+
dpg.setup_dearpygui()
|
49
|
+
dpg.show_viewport()
|
50
|
+
dpg.start_dearpygui()
|
51
|
+
dpg.destroy_context()
|
52
|
+
```
|
@@ -1,20 +1,20 @@
|
|
1
1
|
[project]
|
2
2
|
name = "dearpygui-forms"
|
3
|
-
version = "0.1
|
3
|
+
version = "0.2.1"
|
4
4
|
description = "Dearpygui extention for autogeneration forms powered by pydantic."
|
5
5
|
readme = "README.md"
|
6
6
|
authors = [
|
7
7
|
{ name = "Valentin Lewicki", email = "vlewicki@vlewicki.ru" }
|
8
8
|
]
|
9
|
-
requires-python = ">=3.
|
9
|
+
requires-python = ">=3.10"
|
10
10
|
dependencies = [
|
11
11
|
"dearpygui>=2.0.0",
|
12
12
|
"loguru>=0.7.3",
|
13
13
|
"pydantic>=2.11.7",
|
14
14
|
]
|
15
15
|
|
16
|
-
[project.
|
17
|
-
|
16
|
+
[project.urls]
|
17
|
+
homepage = "https://github.com/vlewicki/dearpygui-forms"
|
18
18
|
|
19
19
|
|
20
20
|
[build-system]
|
@@ -25,6 +25,3 @@ build-backend = "hatchling.build"
|
|
25
25
|
dev = [
|
26
26
|
"pylint>=3.3.7",
|
27
27
|
]
|
28
|
-
|
29
|
-
[tools.hatch.build]
|
30
|
-
include = ["src", "README.md"]
|
@@ -0,0 +1,57 @@
|
|
1
|
+
from pprint import pformat
|
2
|
+
from typing import Any, Type
|
3
|
+
import copy
|
4
|
+
|
5
|
+
import pydantic
|
6
|
+
import dearpygui.dearpygui as dpg
|
7
|
+
from loguru import logger
|
8
|
+
|
9
|
+
|
10
|
+
from .models import PropertySchema
|
11
|
+
from .widgets import *
|
12
|
+
from . import exceptions
|
13
|
+
|
14
|
+
|
15
|
+
def extract_defs(schema: dict[str, Any]) -> tuple[dict[str, Any], dict[str, Any]]:
|
16
|
+
"""split schema on root models schema and $defs"""
|
17
|
+
schema = copy.deepcopy(schema)
|
18
|
+
if "$defs" in schema:
|
19
|
+
defs = schema["$defs"]
|
20
|
+
del schema["$defs"]
|
21
|
+
root_model_schema = schema
|
22
|
+
else:
|
23
|
+
defs = {}
|
24
|
+
root_model_schema = schema
|
25
|
+
return root_model_schema, defs
|
26
|
+
|
27
|
+
|
28
|
+
class DPGForm:
|
29
|
+
def __init_subclass__(cls, *, model: Type[pydantic.BaseModel]) -> None:
|
30
|
+
cls._Model = model
|
31
|
+
|
32
|
+
def __init__(self, callback):
|
33
|
+
model_schema, models_defs = extract_defs(self._Model.model_json_schema())
|
34
|
+
self._model_widget = generate_widget(model_schema, models_defs)
|
35
|
+
self._callback = callback
|
36
|
+
|
37
|
+
def add(self):
|
38
|
+
self._model_widget.add()
|
39
|
+
dpg.add_button(label="Submit", callback=self._on_submit)
|
40
|
+
|
41
|
+
def fill_form(self, data_model: pydantic.BaseModel):
|
42
|
+
self._model_widget.set_value(data_model.model_dump())
|
43
|
+
|
44
|
+
def _on_submit(self):
|
45
|
+
try:
|
46
|
+
data = self._Model(**self._model_widget.get_value())
|
47
|
+
except pydantic.ValidationError as e:
|
48
|
+
with dpg.window(modal=True, label="Validation Error"):
|
49
|
+
dpg.add_text(f"Validation error: {e}")
|
50
|
+
except exceptions.DearpyguiFormsError as e:
|
51
|
+
with dpg.window(modal=True, label="Form Error"):
|
52
|
+
dpg.add_text(f"Form error: {e}")
|
53
|
+
else:
|
54
|
+
self._callback(data)
|
55
|
+
|
56
|
+
def get_form_data(self):
|
57
|
+
return self._Model(**self._model_widget.get_value())
|
@@ -0,0 +1,14 @@
|
|
1
|
+
from typing import Any, Literal
|
2
|
+
from pydantic import BaseModel
|
3
|
+
|
4
|
+
|
5
|
+
class PropertySchema:
|
6
|
+
def __init__(self, schema: dict[str, Any]) -> None:
|
7
|
+
self.title: str | None = schema.get("title", None)
|
8
|
+
self.type: str | None = schema.get("type", None)
|
9
|
+
self.anyOf: list[dict[str, Any]] = schema.get("anyOf", [])
|
10
|
+
self.properties: dict[str, dict[str, Any]] = schema.get("properties", {})
|
11
|
+
self.default = schema.get("default", None)
|
12
|
+
|
13
|
+
def __repr__(self) -> str:
|
14
|
+
return f"PropertySchema(title={self.title}, type={self.type}, anyOf={self.anyOf}, properties={self.properties}, default={self.default})"
|
@@ -0,0 +1,256 @@
|
|
1
|
+
import copy
|
2
|
+
from typing import Any
|
3
|
+
|
4
|
+
import dearpygui.dearpygui as dpg
|
5
|
+
from loguru import logger
|
6
|
+
|
7
|
+
|
8
|
+
from .models import PropertySchema
|
9
|
+
from .exceptions import DearpyguiFormsError
|
10
|
+
|
11
|
+
|
12
|
+
@logger.catch
|
13
|
+
def dereference_property(schema: dict[str, Any], defs: dict[str, Any]):
|
14
|
+
if "$ref" in schema:
|
15
|
+
path = schema["$ref"].split("/")[-1]
|
16
|
+
new_schema = copy.deepcopy(defs[path])
|
17
|
+
new_schema.update(copy.deepcopy(schema))
|
18
|
+
del new_schema["$ref"]
|
19
|
+
else:
|
20
|
+
new_schema = copy.deepcopy(schema)
|
21
|
+
return new_schema
|
22
|
+
|
23
|
+
|
24
|
+
class Widget:
|
25
|
+
def __init__(self, schema: PropertySchema, defs: dict, **kwargs):
|
26
|
+
self.schema = schema
|
27
|
+
self._defs = defs
|
28
|
+
self._kwargs = kwargs
|
29
|
+
with dpg.stage() as self._staging_container_id:
|
30
|
+
with dpg.group() as self._root_item:
|
31
|
+
self._ui()
|
32
|
+
|
33
|
+
if schema.default:
|
34
|
+
self.set_value(schema.default)
|
35
|
+
|
36
|
+
def _ui(self):
|
37
|
+
dpg.add_text(f"Property {self.schema.title}, type: {self.schema.type}")
|
38
|
+
|
39
|
+
def add(self, parent=None, hidden=False):
|
40
|
+
"""
|
41
|
+
Add widget as dpg ui item.
|
42
|
+
"""
|
43
|
+
if parent is not None:
|
44
|
+
dpg.push_container_stack(parent)
|
45
|
+
dpg.unstage(self._staging_container_id)
|
46
|
+
dpg.pop_container_stack()
|
47
|
+
else:
|
48
|
+
dpg.unstage(self._staging_container_id)
|
49
|
+
|
50
|
+
if hidden:
|
51
|
+
self.hide()
|
52
|
+
|
53
|
+
def hide(self):
|
54
|
+
dpg.hide_item(self._root_item)
|
55
|
+
|
56
|
+
def show(self):
|
57
|
+
dpg.show_item(self._root_item)
|
58
|
+
|
59
|
+
def set_value(self, value: Any):
|
60
|
+
pass
|
61
|
+
|
62
|
+
def get_value(self) -> Any:
|
63
|
+
pass
|
64
|
+
|
65
|
+
|
66
|
+
class ObjectWidget(Widget):
|
67
|
+
def __init__(self, schema, defs, **kwargs):
|
68
|
+
self._properties: dict[str, Widget] = {}
|
69
|
+
super().__init__(schema, defs, **kwargs)
|
70
|
+
|
71
|
+
def _ui(self):
|
72
|
+
for property_name, property in self.schema.properties.items():
|
73
|
+
property_widget = generate_widget(property, self._defs, generate_object=False)
|
74
|
+
property_widget.add()
|
75
|
+
self._properties[property_name] = property_widget
|
76
|
+
|
77
|
+
def get_value(self) -> dict[str, Any]:
|
78
|
+
return {property_name: property_widget.get_value() for property_name, property_widget in self._properties.items()}
|
79
|
+
|
80
|
+
def set_value(self, value: dict[str, Any]):
|
81
|
+
for property_name, property_widget in self._properties.items():
|
82
|
+
property_widget.set_value(value.get(property_name))
|
83
|
+
|
84
|
+
|
85
|
+
class ArrayWidget(Widget):
|
86
|
+
def __init__(self, schema, defs, **kwargs):
|
87
|
+
super().__init__(schema, defs, **kwargs)
|
88
|
+
|
89
|
+
|
90
|
+
class MultiTypeWidget(Widget):
|
91
|
+
def __init__(self, schema, defs, **kwargs):
|
92
|
+
self._type_switcher_id = dpg.generate_uuid()
|
93
|
+
self._widget: Widget | None = None
|
94
|
+
self._widgets: dict[str, Widget] = {}
|
95
|
+
for type_schema in schema.anyOf:
|
96
|
+
widget = generate_widget(type_schema, defs, generate_object=False)
|
97
|
+
self._widgets[widget.schema.type] = widget
|
98
|
+
|
99
|
+
super().__init__(schema, defs, **kwargs)
|
100
|
+
|
101
|
+
def _ui(self):
|
102
|
+
with dpg.group(horizontal=True):
|
103
|
+
dpg.add_text(self.schema.title)
|
104
|
+
dpg.add_combo(label="Type",
|
105
|
+
tag=self._type_switcher_id,
|
106
|
+
items=list(self._widgets.keys()),
|
107
|
+
callback=self.switch_value_type,
|
108
|
+
no_preview=True
|
109
|
+
)
|
110
|
+
with dpg.group(indent=25) as self._form:
|
111
|
+
for widget in self._widgets.values():
|
112
|
+
widget.add(hidden=True)
|
113
|
+
|
114
|
+
def switch_value_type(self):
|
115
|
+
new_type = dpg.get_value(self._type_switcher_id)
|
116
|
+
if self._widget is not None:
|
117
|
+
self._widget.hide()
|
118
|
+
self._widget = self._widgets[new_type]
|
119
|
+
self._widget.show()
|
120
|
+
|
121
|
+
def get_value(self):
|
122
|
+
if self._widget:
|
123
|
+
return self._widget.get_value()
|
124
|
+
else:
|
125
|
+
raise DearpyguiFormsError(f"{self.schema.title}: choose value type")
|
126
|
+
|
127
|
+
def set_value(self, value):
|
128
|
+
pass
|
129
|
+
# dpg.set_value(self._type_switcher_id, value)
|
130
|
+
|
131
|
+
|
132
|
+
class StringWidget(Widget):
|
133
|
+
def __init__(self, schema, defs, **kwargs):
|
134
|
+
self._input_id = dpg.generate_uuid()
|
135
|
+
super().__init__(schema, defs, **kwargs)
|
136
|
+
|
137
|
+
def _ui(self):
|
138
|
+
dpg.add_input_text(label=self.schema.title, tag=self._input_id)
|
139
|
+
|
140
|
+
def get_value(self):
|
141
|
+
return dpg.get_value(self._input_id)
|
142
|
+
|
143
|
+
def set_value(self, value):
|
144
|
+
dpg.set_value(self._input_id, value)
|
145
|
+
|
146
|
+
|
147
|
+
class IntegerWidget(Widget):
|
148
|
+
def __init__(self, schema, defs, **kwargs):
|
149
|
+
self._input_id = dpg.generate_uuid()
|
150
|
+
super().__init__(schema, defs, **kwargs)
|
151
|
+
|
152
|
+
def _ui(self):
|
153
|
+
dpg.add_input_int(label=self.schema.title, tag=self._input_id)
|
154
|
+
|
155
|
+
def get_value(self):
|
156
|
+
return dpg.get_value(self._input_id)
|
157
|
+
|
158
|
+
def set_value(self, value):
|
159
|
+
dpg.set_value(self._input_id, value)
|
160
|
+
|
161
|
+
|
162
|
+
class NumberWidget(Widget):
|
163
|
+
def __init__(self, schema, defs, **kwargs):
|
164
|
+
self._input_id = dpg.generate_uuid()
|
165
|
+
super().__init__(schema, defs, **kwargs)
|
166
|
+
|
167
|
+
def _ui(self):
|
168
|
+
dpg.add_input_float(label=self.schema.title, tag=self._input_id)
|
169
|
+
|
170
|
+
def get_value(self):
|
171
|
+
return dpg.get_value(self._input_id)
|
172
|
+
|
173
|
+
def set_value(self, value):
|
174
|
+
dpg.set_value(self._input_id, value)
|
175
|
+
|
176
|
+
|
177
|
+
class BooleanWidget(Widget):
|
178
|
+
def __init__(self, schema, defs, **kwargs):
|
179
|
+
self._checkbox_id = dpg.generate_uuid()
|
180
|
+
super().__init__(schema, defs, **kwargs)
|
181
|
+
|
182
|
+
def _ui(self):
|
183
|
+
dpg.add_checkbox(label=self.schema.title, tag=self._checkbox_id)
|
184
|
+
|
185
|
+
def get_value(self):
|
186
|
+
return dpg.get_value(self._checkbox_id)
|
187
|
+
|
188
|
+
def set_value(self, value: bool):
|
189
|
+
dpg.set_value(self._checkbox_id, value)
|
190
|
+
|
191
|
+
class NoneWidget(Widget):
|
192
|
+
def __init__(self, schema, defs, **kwargs):
|
193
|
+
self._none_id = dpg.generate_uuid()
|
194
|
+
super().__init__(schema, defs, **kwargs)
|
195
|
+
|
196
|
+
def _ui(self):
|
197
|
+
dpg.add_input_text(default_value='<None>', label=self.schema.title, tag=self._none_id, enabled=False)
|
198
|
+
|
199
|
+
def get_value(self):
|
200
|
+
return None
|
201
|
+
|
202
|
+
def set_value(self, value):
|
203
|
+
pass
|
204
|
+
|
205
|
+
|
206
|
+
class ExternalWidget(Widget):
|
207
|
+
def __init__(self, schema, defs, **kwargs):
|
208
|
+
self._external_id = dpg.generate_uuid()
|
209
|
+
self._widget: Widget | None = None
|
210
|
+
super().__init__(schema, defs, **kwargs)
|
211
|
+
|
212
|
+
def _ui(self):
|
213
|
+
with dpg.tree_node(label=self.schema.title) as self._form:
|
214
|
+
self._edit_button = dpg.add_button(label=f"Edit", callback=self.show_object_form)
|
215
|
+
|
216
|
+
def show_object_form(self):
|
217
|
+
if self._widget is None:
|
218
|
+
dpg.delete_item(self._edit_button)
|
219
|
+
self._widget = ObjectWidget(self.schema, self._defs)
|
220
|
+
self._widget.add(parent=self._form)
|
221
|
+
|
222
|
+
def get_value(self):
|
223
|
+
if self._widget is None:
|
224
|
+
raise DearpyguiFormsError(f"{self.schema.title}: set up object.")
|
225
|
+
return self._widget.get_value()
|
226
|
+
|
227
|
+
def set_value(self, value):
|
228
|
+
self.show_object_form()
|
229
|
+
self._widget.set_value(value)
|
230
|
+
|
231
|
+
|
232
|
+
def generate_widget(json_schema: dict[str, Any], defs: dict[str, Any], generate_object: bool = True, **kwargs) -> Widget:
|
233
|
+
schema = PropertySchema(dereference_property(json_schema, defs))
|
234
|
+
match schema:
|
235
|
+
case PropertySchema(type='object'):
|
236
|
+
if generate_object:
|
237
|
+
return ObjectWidget(schema, defs, **kwargs)
|
238
|
+
else:
|
239
|
+
return ExternalWidget(schema, defs, **kwargs)
|
240
|
+
case PropertySchema(type='array'):
|
241
|
+
raise NotImplementedError("ArrayWidget is not implemented yet")
|
242
|
+
return ArrayWidget(schema, defs, **kwargs)
|
243
|
+
case PropertySchema(type='string'):
|
244
|
+
return StringWidget(schema, defs, **kwargs)
|
245
|
+
case PropertySchema(type='integer'):
|
246
|
+
return IntegerWidget(schema, defs, **kwargs)
|
247
|
+
case PropertySchema(type='number'):
|
248
|
+
return NumberWidget(schema, defs, **kwargs)
|
249
|
+
case PropertySchema(type='boolean'):
|
250
|
+
return BooleanWidget(schema, defs, **kwargs)
|
251
|
+
case PropertySchema(type='null'):
|
252
|
+
return NoneWidget(schema, defs, **kwargs)
|
253
|
+
case PropertySchema(anyOf=types) if len(types) > 0:
|
254
|
+
return MultiTypeWidget(schema, defs, **kwargs)
|
255
|
+
case _:
|
256
|
+
raise ValueError(f"Unsupported schema: {schema}")
|
@@ -1,8 +1,10 @@
|
|
1
1
|
import datetime
|
2
2
|
import decimal
|
3
|
+
from pprint import pprint
|
3
4
|
import dearpygui.dearpygui as dpg
|
4
5
|
|
5
6
|
import dearpygui.dearpygui as dpg
|
7
|
+
from loguru import logger
|
6
8
|
from pydantic import BaseModel, Field
|
7
9
|
|
8
10
|
from dearpygui import demo
|
@@ -10,6 +12,11 @@ import pydantic
|
|
10
12
|
from dearpygui_forms import DPGForm
|
11
13
|
|
12
14
|
|
15
|
+
class Tool(BaseModel):
|
16
|
+
name: str = Field(title="Tool name", min_length=1)
|
17
|
+
price: float = Field(title="Price", ge=0)
|
18
|
+
quantity: int = Field(title="Quantity", ge=0)
|
19
|
+
|
13
20
|
class User(BaseModel):
|
14
21
|
name: str = Field(title="User name", min_length=1)
|
15
22
|
birthday: datetime.date = datetime.date(2000, 1, 1)
|
@@ -18,14 +25,18 @@ class User(BaseModel):
|
|
18
25
|
fingers_on_the_hand: int = 5
|
19
26
|
weight: float = 60.0
|
20
27
|
pi: decimal.Decimal = decimal.Decimal('3.1415')
|
21
|
-
male: bool = True
|
28
|
+
male: bool|None = True
|
29
|
+
tool: Tool = Field(title="Gun", default=Tool(name="Gun00", price=100.0, quantity=1))
|
30
|
+
best_friend: 'User | None' = Field(title='Best friend')
|
31
|
+
zero: None
|
22
32
|
# friends: list['User']
|
23
33
|
|
24
34
|
|
35
|
+
class UserForm(DPGForm, model=User):
|
36
|
+
pass
|
25
37
|
|
26
|
-
class
|
27
|
-
|
28
|
-
|
38
|
+
class ToolForm(DPGForm, model=Tool):
|
39
|
+
pass
|
29
40
|
|
30
41
|
|
31
42
|
def main():
|
@@ -52,11 +63,7 @@ def main():
|
|
52
63
|
dpg.add_menu_item(label='About', callback=dpg.show_about)
|
53
64
|
|
54
65
|
with dpg.window(label="Template", width=641, height=480):
|
55
|
-
|
56
|
-
|
57
|
-
with dpg.window(label="Main"):
|
58
|
-
dpg.add_text("Hello")
|
59
|
-
UserForm(print).add()
|
66
|
+
UserForm(lambda x: logger.success(x)).add()
|
60
67
|
|
61
68
|
|
62
69
|
|
@@ -0,0 +1,30 @@
|
|
1
|
+
from pprint import pprint
|
2
|
+
import dearpygui.dearpygui as dpg
|
3
|
+
from pydantic import BaseModel, Field
|
4
|
+
from dearpygui_forms import DPGForm
|
5
|
+
|
6
|
+
class User(BaseModel):
|
7
|
+
name: str = Field(default="John Doe", min_length=3)
|
8
|
+
age: int = Field(ge=18)
|
9
|
+
|
10
|
+
|
11
|
+
class Storage(BaseModel):
|
12
|
+
users: list[User] = []
|
13
|
+
|
14
|
+
class UserForm(DPGForm, model=User):
|
15
|
+
pass
|
16
|
+
|
17
|
+
|
18
|
+
dpg.create_context()
|
19
|
+
dpg.create_viewport()
|
20
|
+
|
21
|
+
store = Storage()
|
22
|
+
|
23
|
+
with dpg.window(label="User Form"):
|
24
|
+
user_form = UserForm(callback=lambda x: store.users.append(x))
|
25
|
+
user_form.add()
|
26
|
+
dpg.add_button(label="Print Users", callback=lambda: pprint(store.model_dump()))
|
27
|
+
dpg.setup_dearpygui()
|
28
|
+
dpg.show_viewport()
|
29
|
+
dpg.start_dearpygui()
|
30
|
+
dpg.destroy_context()
|
@@ -0,0 +1,37 @@
|
|
1
|
+
import enum
|
2
|
+
from pprint import pprint
|
3
|
+
from pydantic import BaseModel
|
4
|
+
|
5
|
+
|
6
|
+
models: list[type[BaseModel]] = []
|
7
|
+
|
8
|
+
|
9
|
+
class Category(enum.Enum):
|
10
|
+
FOOD = "food"
|
11
|
+
ENTERTAINMENT = "entertainment"
|
12
|
+
TRANSPORTATION = "transportation"
|
13
|
+
HOUSING = "housing"
|
14
|
+
UTILITIES = "utilities"
|
15
|
+
OTHER = 0
|
16
|
+
|
17
|
+
class Transaction(BaseModel):
|
18
|
+
category: Category
|
19
|
+
|
20
|
+
|
21
|
+
models.append(Transaction)
|
22
|
+
|
23
|
+
class Test1(BaseModel):
|
24
|
+
val: int | None = None
|
25
|
+
|
26
|
+
models.append(Test1)
|
27
|
+
|
28
|
+
|
29
|
+
class Test2(BaseModel):
|
30
|
+
val: Transaction | Test1
|
31
|
+
|
32
|
+
models.append(Test2)
|
33
|
+
|
34
|
+
|
35
|
+
for model in models:
|
36
|
+
pprint(model.model_json_schema())
|
37
|
+
print(Test1().model_dump_json())
|