With PyWebIO I have created a user form that takes up to six dates, each pair composing a date range from start date sdt
to end date edt
. The first two dates are required, the remaining four are optional. This form can be validated via a function; check_form
in my example.
I would like to use this function to allow the user only the input of consecutive, chronological pairs.
Example form:
from pywebio import *
form = input.input_group("form", [
input.input("Period 1 - Start",
name="sdt_1",
type=input.DATE,
required=True),
input.input("Period 1 - End",
name="edt_1",
type=input.DATE,
required=True),
input.input("Period 2 - Start (optional)",
name="sdt_2",
type=input.DATE),
input.input("Period 2 - End (optional)",
name="edt_2",
type=input.DATE),
input.input("Period 3 - Start (optional)",
name="sdt_3",
type=input.DATE),
input.input("Period 3 - End (optional)",
name="edt_3",
type=input.DATE),
], validate = check_form)
PyWebIO sorts the input into a dict, using the name as key and the input as value.
Output of print(form)
:
form = {
'sdt_1': '2020-01-01',
'edt_1': '2020-08-08',
'sdt_2': '2021-01-01',
'edt_2': '2021-08-08',
'sdt_3': '2023-01-01',
'edt_3': '2023-08-08'
}
I have come up with a solution that checks for chronological order and for an equal amount of entries. However, this solution still allows the user to make nonsensical input, such as only entering a date for sdt_1, edt_1, sdt_3, sdt_3
or sdt_1, edt_1, sdt_2, edt_3
def check_form(data):
data_lst = []
for key in data.keys():
if data[key] != "":
data_lst.append(data[key])
if sorted(data_lst) != data_lst:
return ("sdt_1", "ERROR: Entries not in chronological order.")
if len(data_lst) % 2:
return ("sdt_1", "ERROR: Uneven amount of entries.")
Any help is much appreciated!
CodePudding user response:
Since the first pair is required and the remaining two pairs are optional, you should enforce that logic.
def check_form(data):
required_pairs = {1} # Specify all the required pairs in this set
max_pairs = 3 # Max numbber of pairs
data_lst = []
for i in range(1, max_pairs 1):
s_key = f"sdt_{i}"
e_key = f"edt_{i}"
# Get the data from the dict. If the key doesn't exist, treat it as an empty string
s_val = data.get(s_key, "")
e_val = data.get(e_key, "")
if i in required_pairs or s_val or e_val:
if i in required_pairs:
# This is a required pair and input is missing
if not s_val: return (s_key, "ERROR: Missing required input")
elif not e_val: return (e_key, "ERROR: Missing required input")
elif e_val and not s_val:
# e_key is specified but not s_key
return (s_key, "ERROR: Uneven pair of inputs")
elif s_val and not e_val:
# s_key is specified but not e_key
return (e_key, "ERROR: Uneven pair of inputs")
# We didn't return an error, so this data must be valid
data_lst.append(data[s_key])
data_lst.append(data[e_key])
if sorted(data_lst) != data_lst:
return ("sdt_1", "ERROR: Entries not in chronological order")
Note that you can check if a string s
is empty by simply if s
(empty strings are falsy)
Let's test this:
##### VALID INPUTS:
# Case 1: Specify all inputs
assert check_form({
'sdt_1': '2020-01-01',
'edt_1': '2020-08-08',
'sdt_2': '2021-01-01',
'edt_2': '2021-08-08',
'sdt_3': '2023-01-01',
'edt_3': '2023-08-08'
}) == None
# Case 2: Specify only required inputs
assert check_form({
'sdt_1': '2020-01-01',
'edt_1': '2020-08-08',
'sdt_2': '',
'edt_2': '',
'sdt_3': '',
'edt_3': ''
}) == None
# Case 3.1: Specify required inputs and one optional input
assert check_form({
'sdt_1': '2020-01-01',
'edt_1': '2020-08-08',
'sdt_2': '2021-01-01',
'edt_2': '2021-01-08',
'sdt_3': '',
'edt_3': ''
}) == None
# Case 3.2: Specify required inputs and one optional input
assert check_form({
'sdt_1': '2020-01-01',
'edt_1': '2020-08-08',
'sdt_2': '',
'edt_2': '',
'sdt_3': '2021-01-01',
'edt_3': '2021-01-08',
}) == None
#### INVALID INPUTS
# Case 4.1: Skip required inputs
assert check_form({
'sdt_1': '',
'edt_1': '2020-08-08',
'sdt_2': '2021-01-01',
'edt_2': '2021-08-08',
'sdt_3': '2022-01-01',
'edt_3': '2022-01-08',
}) == ('sdt_1', "ERROR: Missing required input")
# Case 4.2: Skip required inputs
assert check_form({
'sdt_1': '2020-01-01',
'edt_1': '',
'sdt_2': '2021-01-01',
'edt_2': '2021-08-08',
'sdt_3': '2022-01-01',
'edt_3': '2022-01-08',
}) == ('edt_1', "ERROR: Missing required input")
# Case 4.3: Skip required inputs
assert check_form({
'sdt_1': '',
'edt_1': '',
'sdt_2': '2021-01-01',
'edt_2': '2021-08-08',
'sdt_3': '2022-01-01',
'edt_3': '2022-01-08',
}) == ('sdt_1', "ERROR: Missing required input")
# Case 5.1: Incomplete pair of optional inputs
assert check_form({
'sdt_1': '2020-01-01',
'edt_1': '2020-08-08',
'sdt_2': '',
'edt_2': '2021-08-08',
'sdt_3': '2022-01-01',
'edt_3': '2022-01-08',
}) == ('sdt_2', "ERROR: Uneven pair of inputs")
# Case 5.2: Incomplete pair of optional inputs
assert check_form({
'sdt_1': '2020-01-01',
'edt_1': '2020-08-08',
'sdt_2': '2021-01-01',
'edt_2': '',
'sdt_3': '2022-01-01',
'edt_3': '2022-01-08',
}) == ('edt_2', "ERROR: Uneven pair of inputs")
# Case 5.3: Incomplete pair of optional inputs
assert check_form({
'sdt_1': '2020-01-01',
'edt_1': '2020-08-08',
'sdt_2': '2021-01-01',
'edt_2': '2021-08-08',
'sdt_3': '',
'edt_3': '2022-01-08',
}) == ('sdt_3', "ERROR: Uneven pair of inputs")
# Case 5.4: Incomplete pair of optional inputs
assert check_form({
'sdt_1': '2020-01-01',
'edt_1': '2020-08-08',
'sdt_2': '2021-01-01',
'edt_2': '2021-08-08',
'sdt_3': '2022-01-01',
'edt_3': '',
}) == ('edt_3', "ERROR: Uneven pair of inputs")
# Case 5.5: Incomplete pair of optional inputs
assert check_form({
'sdt_1': '2020-01-01',
'edt_1': '2020-08-08',
'sdt_2': '2021-01-01',
'edt_2': '',
'sdt_3': '2022-01-01',
'edt_3': '',
}) == ('edt_2', "ERROR: Uneven pair of inputs")
# Case 5.6: Incomplete pair of optional inputs
assert check_form({
'sdt_1': '2020-01-01',
'edt_1': '2020-08-08',
'sdt_2': '',
'edt_2': '2021-08-08',
'sdt_3': '',
'edt_3': '2022-08-08',
}) == ('sdt_2', "ERROR: Uneven pair of inputs")
# Case 6.1: Non-chronological inputs
assert check_form({
'sdt_1': '2020-01-01',
'edt_1': '2019-08-08',
'sdt_2': '2021-01-01',
'edt_2': '2021-08-08',
'sdt_3': '2022-01-01',
'edt_3': '2022-08-08',
}) == ('sdt_1', "ERROR: Entries not in chronological order")
# Case 6.2: Non-chronological inputs
assert check_form({
'sdt_1': '2020-01-01',
'edt_1': '2020-08-08',
'sdt_2': '2021-01-01',
'edt_2': '2022-08-08',
'sdt_3': '2022-01-01',
'edt_3': '2022-08-08',
}) == ('sdt_1', "ERROR: Entries not in chronological order")
CodePudding user response:
I have come up with a solution. Put the dict into a list and check from the second index on if the previous index was empty. Like so:
def check_form(data):
data_lst = []
data_lst_2 = list(form.values())
for key in data.keys():
if data[key] != "":
data_lst.append(data[key])
if sorted(data_lst) != data_lst:
return ("sdt_1", "ERROR: Entries not in chronological order.")
if len(data_lst) % 2:
return ("sdt_1", "ERROR: Uneven amount of entries.")
for item in data_lst_2[1:]:
if data_lst_2[data_lst_2.index(item) - 1] == "":
return ("sdt_1", "ERROR: Entries not consecutive.")