Skip to content

Commit 9336cb8

Browse files
author
Ruben van Leeuwen
committed
Adds demo form steps used in presentation at WFO dev days
1 parent 35a7467 commit 9336cb8

File tree

1 file changed

+136
-0
lines changed

1 file changed

+136
-0
lines changed

backend/demo.py

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
from dataclasses import dataclass
2+
from typing import Annotated, ClassVar, Iterator
3+
from annotated_types import (
4+
SLOTS,
5+
BaseMetadata,
6+
GroupedMetadata,
7+
Ge,
8+
Le,
9+
MultipleOf,
10+
Predicate,
11+
doc,
12+
)
13+
14+
from fastapi import FastAPI
15+
from fastapi.middleware.cors import CORSMiddleware
16+
17+
from pydantic import BaseModel, ConfigDict, Field
18+
from pydantic_forms.core import FormPage, post_form
19+
from pydantic_forms.types import State
20+
from pydantic_forms.exception_handlers.fastapi import form_error_handler
21+
from pydantic_forms.exceptions import FormException
22+
from pydantic_forms.core import FormPage as PydanticFormsFormPage
23+
from pydantic_forms.types import JSON
24+
25+
from pydantic_forms.validators import (
26+
unique_conlist,
27+
)
28+
29+
30+
class FormPage(PydanticFormsFormPage):
31+
meta__: ClassVar[JSON] = {"hasNext": True}
32+
33+
34+
class SubmitFormPage(FormPage):
35+
meta__: ClassVar[JSON] = {"hasNext": False}
36+
37+
38+
app = FastAPI()
39+
# Configure CORS
40+
app.add_middleware(
41+
CORSMiddleware,
42+
allow_origins=["*"], # Allows all origins
43+
allow_credentials=True,
44+
allow_methods=["*"], # Allows all methods
45+
allow_headers=["*"], # Allows all headers
46+
)
47+
app.add_exception_handler(FormException, form_error_handler) # type: ignore[arg-type]
48+
49+
50+
@app.get("/")
51+
def read_root():
52+
return {"Hello": "World"}
53+
54+
55+
@dataclass(frozen=True, **SLOTS)
56+
class ExtraData(GroupedMetadata):
57+
props: dict
58+
59+
def __iter__(self) -> Iterator[BaseMetadata]:
60+
yield Field(json_schema_extra=self.props)
61+
62+
63+
def example_backend_validation(val: int) -> bool:
64+
if val == "Karel":
65+
raise ValueError("No not Karel!")
66+
return True
67+
68+
69+
NumberExample = Annotated[
70+
int,
71+
Ge(18),
72+
Le(99),
73+
MultipleOf(multiple_of=3),
74+
Predicate(example_backend_validation),
75+
]
76+
77+
StringExample = Annotated[
78+
str,
79+
Field(min_length=2, max_length=10),
80+
Predicate(example_backend_validation),
81+
]
82+
83+
84+
@app.post("/form")
85+
async def form(form_data: list[dict] = []):
86+
def form_generator(state: State):
87+
88+
class NameForm(FormPage):
89+
model_config = ConfigDict(title="Demo form step 1")
90+
name: str
91+
92+
name_form_data = yield NameForm
93+
94+
class NameValidationForm(FormPage):
95+
model_config = ConfigDict(title="Demo form step 1")
96+
name_with_validation: StringExample
97+
98+
name_validation_form_data = yield NameValidationForm
99+
100+
class NameAgeForm(FormPage):
101+
model_config = ConfigDict(title="Demo form step 1")
102+
name: StringExample
103+
age: NumberExample
104+
105+
name_age_form_data = yield NameAgeForm
106+
107+
class PersonObjectForm(FormPage):
108+
class Person(BaseModel):
109+
name: StringExample
110+
age: NumberExample
111+
112+
model_config = ConfigDict(title="Demo form step 1")
113+
person: Person
114+
115+
person_object_form_data = yield PersonObjectForm
116+
117+
class PersonArrayForm(FormPage):
118+
class Person(BaseModel):
119+
name: StringExample
120+
age: NumberExample
121+
122+
model_config = ConfigDict(title="Demo form step 1")
123+
PersonList: unique_conlist(Person, min_items=1, max_items=3)
124+
125+
person_array_form_data = yield PersonArrayForm
126+
127+
return (
128+
name_form_data.model_dump()
129+
| name_validation_form_data.model_dump()
130+
| name_age_form_data.model_dump()
131+
| person_object_form_data.model_dump()
132+
| person_array_form_data.model_dump()
133+
)
134+
135+
post_form(form_generator, state={}, user_inputs=form_data)
136+
return "OK!"

0 commit comments

Comments
 (0)