dash-app-gallery
dash-app-gallery copied to clipboard
Adding Pattern Matching app
@IcToxi proposed the following community app that has pattern matching:
from dash import Dash, html, dcc, Input, Output, State, MATCH, ALL
app = Dash(__name__)
questionnaire = {
1: {
"type": "choice",
"question": "Does your agency use an electronic accounting software system (as opposed to manual)?",
"options": ["Yes", "No", "Skip"],
},
2: {
"type": "choice+blank",
"question": "Has your agency recently implemented any new or substantially changed systems, for example, financial management or accounting systems? (If yes, please explain.)",
"options": ["Yes", "No", "Skip"],
},
3: {
"type": "choice",
"question": "Does your agency have a written Accounting and Financial Reporting policy?",
"options": ["Yes", "No", "Skip"],
},
4: {
"type": "choice",
"question": "Does your agency have a written Personnel policy (to include travel reimbursement, fringe benefits, etc.)?",
"options": ["Yes", "No", "Skip"],
},
5: {
"type": "multi-choice",
"question": "Which of the following aspects of the OJT training program were explained to you?",
"options": [
"Training Hours",
"Type of Training",
"Training Wages",
"Job Choices",
"Entry Wages",
],
},
6: {
"type": "multi-choice",
"question": "How did you learn about this OJT program?",
"options": [
"Contractor",
"Community Based Organization",
"Union Apprenticeship Program",
"Other",
],
},
7: {
"type": "blank",
"question": "What are your performance based strengths (speed, strength, power, agility, balance, conditioning, etc.)?",
},
8: {
"type": "essay",
"question": "Do you have any questions, comments or concerns?",
},
}
def generate(k, v):
match v["type"]:
case "choice":
return html.Div(
[
html.P(str(k) + ". " + v["question"]),
dcc.RadioItems(
id={
"index": k,
"type": v["type"],
"category": "questionnaire",
"additional": False,
},
options={i: i for i in v["options"]},
),
]
)
case "multi-choice":
return html.Div(
[
html.P(str(k) + ". " + v["question"]),
dcc.Checklist(
id={
"index": k,
"type": v["type"],
"category": "questionnaire",
"additional": False,
},
options={i: i for i in v["options"]},
),
]
)
case "choice+blank":
return html.Div(
[
html.P(str(k) + ". " + v["question"]),
dcc.RadioItems(
id={
"index": k,
"type": v["type"],
"category": "questionnaire",
"additional": False,
},
options={i: i for i in v["options"]},
),
dcc.Input(
id={
"index": k,
"type": v["type"],
"category": "questionnaire",
"additional": True,
},
disabled=True,
),
]
)
case "blank":
return html.Div(
[
html.P(str(k) + ". " + v["question"]),
dcc.Input(
id={
"index": k,
"type": v["type"],
"category": "questionnaire",
"additional": False,
}
),
]
)
case "essay":
return html.Div(
[
html.P(str(k) + ". " + v["question"]),
dcc.Textarea(
id={
"index": k,
"type": v["type"],
"category": "questionnaire",
"additional": False,
}
),
]
)
case _:
return html.Div("Something is wrong...")
app.layout = html.Div(
[generate(k, v) for k, v in questionnaire.items()]
+ [html.Br(), btn := html.Button("Submit"), answers := html.Div()]
)
app.callback(
Output(
{
"category": "questionnaire",
"type": "choice+blank",
"additional": True,
"index": MATCH,
},
"disabled",
),
Input(
{
"category": "questionnaire",
"type": "choice+blank",
"additional": False,
"index": MATCH,
},
"value",
),
)(lambda v: False if v == "Yes" else True)
app.callback(
Output(btn, "disabled"),
Input(
{"category": "questionnaire", "type": ALL, "additional": False, "index": ALL},
"value",
),
)(lambda answer: False if all(answer) else True)
@app.callback(
Output(answers, "children"),
Input(btn, "n_clicks"),
[
State(
{"category": "questionnaire", "type": ALL, "additional": ALL, "index": ALL},
"id",
),
State(
{"category": "questionnaire", "type": ALL, "additional": ALL, "index": ALL},
"value",
),
],
prevent_initial_call=True,
)
def collect(n_clicks, index, answer):
return str([v | {"answer": answer[i]} for i, v in enumerate(index)])
if __name__ == "__main__":
app.run_server(debug=True)
Hi @IcToxi
It would be great to have a pattern matching example. Thank you. This code is a lot longer than any other app in the gallery. Could we make it more beginner-friendly by shortening it; maybe 100-130 lines of code?
Also, I'm not sure why but I get an error when I try to run the code above:
match v["type"]:
^
SyntaxError: invalid syntax
Hi @Coding-with-Adam, I thought of a way to shorten it by taking out the questionnaire. That's not a bug, it's a switch-case statement that is new in 3.10.
Closing this since it's related to the PR that was closed.