@@ -200,12 +200,16 @@ def work(self):
200200
201201 # build the single runtime view of this dataset's parameters: every
202202 # stored parameter, plus the declared default for any option that was
203- # not stored. Worker code should read options from self.parameters
204- # only, and not re-read them from the dataset mid-run — stored
205- # parameters may change during a run, but this dictionary stays
206- # complete and stable.
203+ # not stored, so worker code can read any declared option without
204+ # checking whether it exists. The stored parameters themselves are
205+ # kept as self.given_parameters: they hold only the options that were
206+ # actually part of the submission (see option_given()). Worker code
207+ # should read options from self.parameters, and not re-read them from
208+ # the dataset mid-run — stored parameters may change during a run,
209+ # but these dictionaries stay stable.
207210 given_parameters = self .dataset .parameters .copy ()
208211 all_parameters = self .get_options (self .source_dataset , config = self .config )
212+ self .given_parameters = given_parameters
209213 self .parameters = {
210214 param : given_parameters .get (param , all_parameters .get (param , {}).get ("default" ))
211215 for param in [* all_parameters .keys (), * given_parameters .keys ()]
@@ -438,6 +442,29 @@ def after_process(self):
438442 except (SMTPException , ConnectionRefusedError , socket .timeout ):
439443 self .log .error ("Error sending email to %s" % owner )
440444
445+ def option_given (self , option ):
446+ """
447+ Check whether an option was actually part of this dataset's submission
448+
449+ `self.parameters` always contains every option this worker declares,
450+ with defaults filled in for anything that was not stored. That is
451+ convenient for reading values, but it cannot tell you whether the
452+ option was really part of the submission. This method can: it checks
453+ the parameters as they were stored when the dataset was created. For
454+ datasets queued via the web interface, an option is only stored if
455+ the user could see it when submitting (i.e. its `requires` condition
456+ was met); for datasets queued by other code (e.g. presets), an option
457+ is only stored if the calling code explicitly set it.
458+
459+ Note that a stored option may still hold its default value: a user
460+ who saw an option and left it untouched still counts as having been
461+ given it.
462+
463+ :param str option: Option name, as used in `get_options()`
464+ :return bool: Whether the option was part of the stored parameters
465+ """
466+ return option in self .given_parameters
467+
441468 def clean_up_on_error (self ):
442469 try :
443470 # ensure proxied requests are stopped
@@ -1087,7 +1114,8 @@ def validate_query(query, request, config):
10871114 marked `sensitive` are removed from the stored record when the dataset
10881115 starts running. At run time, the worker reads all of this back through
10891116 `self.parameters`, with declared option defaults filled in for any
1090- missing keys.
1117+ missing keys; `option_given()` tells a worker whether an option was
1118+ really part of the stored submission.
10911119
10921120 By default nothing is checked and the input is stored as-is. Search
10931121 workers must define their own version: doing so is what makes a
0 commit comments