@@ -109,7 +109,13 @@ def parse_all(options, input, silently_correct=True):
109109 # ignored
110110 continue
111111
112- elif settings .get ("type" ) == UserInput .OPTION_DATERANGE :
112+ if settings .get ("requires" ) and not UserInput .requirements_met (settings ["requires" ], parsed_input ):
113+ # the option's condition is not met, so the user never saw it:
114+ # leave it out instead of storing a default for it. This holds
115+ # whether or not the (hidden) form field was submitted.
116+ continue
117+
118+ if settings .get ("type" ) == UserInput .OPTION_DATERANGE :
113119 # special case, since it combines two inputs
114120 option_min = option + "-min"
115121 option_max = option + "-max"
@@ -234,6 +240,43 @@ def parse_all(options, input, silently_correct=True):
234240
235241 return parsed_input
236242
243+ @staticmethod
244+ def requirements_met (requires , other_input ):
245+ """
246+ Check whether an option's "requires" condition is satisfied
247+
248+ `requires` may be:
249+ - a single string: "field==value"
250+ - an &&-joined string: "field1==v1 && field2==v2" (all must be true)
251+ - a ||-joined string: "field1==v1 || field2==v2" (any must be true)
252+ - a list/tuple of strings: every requirement must be true
253+
254+ :param requires: The option's "requires" setting
255+ :param dict other_input: Values to check the condition against; a
256+ condition that refers to a field missing from this dictionary is
257+ not met
258+ :return bool: True if the condition is satisfied
259+ """
260+ if isinstance (requires , (list , tuple )):
261+ # a list always means: every requirement must be satisfied
262+ req_list = list (requires )
263+ combine_and = True
264+ elif "||" in requires :
265+ # pipe-separated alternatives: any one is sufficient
266+ req_list = [r .strip () for r in requires .split ("||" )]
267+ combine_and = False
268+ elif "&&" in requires :
269+ # ampersand-separated conditions: all must hold
270+ req_list = [r .strip () for r in requires .split ("&&" )]
271+ combine_and = True
272+ else :
273+ # single requirement string
274+ req_list = [requires ]
275+ combine_and = True
276+
277+ results = [UserInput ._requirement_met (r , other_input ) for r in req_list ]
278+ return all (results ) if combine_and else any (results )
279+
237280 @staticmethod
238281 def _requirement_met (req , other_input ):
239282 """
@@ -337,42 +380,9 @@ def parse_value(settings, choice, other_input=None, silently_correct=True):
337380 :return: Validated and parsed input
338381 """
339382 # short-circuit if there is a requirement for the field to be parsed
340- # and the requirement isn't met.
341- # 'requires' may be:
342- # - a single string: "field==value"
343- # - an &&-joined string: "field1==v1 && field2==v2" (all must be true)
344- # - a ||-joined string: "field1==v1 || field2==v2" (any must be true)
345- # - a list/tuple of strings: AND semantics (all must be true)
346- if settings .get ("requires" ):
347- reqs = settings ["requires" ]
348-
349- # normalise to a list of individual requirement strings plus a flag
350- # indicating whether they combine with AND (True) or OR (False)
351- if isinstance (reqs , (list , tuple )):
352- # a list always uses AND semantics: every requirement must be satisfied
353- req_list = list (reqs )
354- combine_and = True
355- elif "||" in reqs :
356- # pipe-separated alternatives: any one is sufficient (OR)
357- req_list = [r .strip () for r in reqs .split ("||" )]
358- combine_and = False
359- elif "&&" in reqs :
360- # ampersand-separated conditions: all must hold (AND)
361- req_list = [r .strip () for r in reqs .split ("&&" )]
362- combine_and = True
363- else :
364- # single requirement string — original behaviour
365- req_list = [reqs ]
366- combine_and = True
367-
368- results = [UserInput ._requirement_met (r , other_input ) for r in req_list ]
369-
370- if combine_and and not all (results ):
371- # AND mode: every requirement must be satisfied
372- raise RequirementsNotMetException ()
373- elif not combine_and and not any (results ):
374- # OR mode: at least one requirement must be satisfied
375- raise RequirementsNotMetException ()
383+ # and the requirement isn't met
384+ if settings .get ("requires" ) and not UserInput .requirements_met (settings ["requires" ], other_input ):
385+ raise RequirementsNotMetException ()
376386
377387 input_type = settings .get ("type" , "" )
378388 if input_type in UserInput .OPTIONS_COSMETIC :
0 commit comments