@@ -140,6 +140,9 @@ def __init__(self):
140140 self ._submit_timeout = self .get_option ('job_submit_timeout' )
141141 self ._use_nodes_opt = self .get_option ('use_nodes_option' )
142142 self ._resubmit_on_errors = self .get_option ('resubmit_on_errors' )
143+ self ._sched_access_in_submit = self .get_option (
144+ 'sched_access_in_submit'
145+ )
143146
144147 def make_job (self , * args , ** kwargs ):
145148 return _SlurmJob (* args , ** kwargs )
@@ -209,39 +212,33 @@ def emit_preamble(self, job):
209212 )
210213 )
211214
212- for opt in job .sched_access :
213- if not opt .strip ().startswith (('-C' , '--constraint' )):
214- preamble .append ('%s %s' % (self ._prefix , opt ))
215-
216- # To avoid overriding a constraint that's passed into `sched_access`,
217- # we AND it with the `--constraint` option passed either in `options`
218- # or in `cli_options`
219- constraints = []
220- constraint_parser = ArgumentParser ()
221- constraint_parser .add_argument ('-C' , '--constraint' )
222- parsed_options , _ = constraint_parser .parse_known_args (
223- job .sched_access
224- )
225- if parsed_options .constraint :
226- constraints .append (parsed_options .constraint .strip ())
227-
228- # NOTE: Here last of the passed --constraint job options is taken
229- # into account in order to respect the behavior of slurm.
230- parsed_options , _ = constraint_parser .parse_known_args (
231- job .options + job .cli_options
232- )
233- if parsed_options .constraint :
234- constraints .append (parsed_options .constraint .strip ())
235-
236- if constraints :
237- if len (constraints ) == 1 :
238- constr = constraints [0 ]
215+ # Combine constraints in `sched_access`
216+ #
217+ # We AND the constraints defined in `sched_access` with those in
218+ # either the `job.options` or `job.cli_options`. We essentially "move"
219+ # the option from the source option list to `sched_access` as if the
220+ # user has specified all the constraint in `sched_access`. We can then
221+ # move with the preamble generation or the submission normally.
222+ c_parser = ArgumentParser ()
223+ c_parser .add_argument ('-C' , '--constraint' )
224+ access , access_other = c_parser .parse_known_args (job .sched_access )
225+ job_opts , other_job_opts = c_parser .parse_known_args (job .options )
226+ cli_opts , other_cli_opts = c_parser .parse_known_args (job .cli_options )
227+ if access .constraint and (job_opts .constraint or cli_opts .constraint ):
228+ constraints = [access .constraint ]
229+ if job_opts .constraint :
230+ constraints .append (job_opts .constraint )
231+ job .options = other_job_opts
239232 else :
240- # Parenthesize the constraints prior to joining them with `&`
241- # to make sure that precedence is respected.
242- constr = '&' .join (f'({ c } )' for c in constraints )
233+ constraints .append (cli_opts .constraint )
234+ job ._cli_options = other_cli_opts
243235
244- preamble .append (self ._format_option (constr , '--constraint={0}' ))
236+ arg = '&' .join (f'({ c .strip ()} )' for c in constraints )
237+ job ._sched_access = [f'--constraint={ arg } ' ]
238+
239+ if not self ._sched_access_in_submit :
240+ for opt in job .sched_access :
241+ preamble .append (f'{ self ._prefix } { opt } ' )
245242
246243 preamble .append (self ._format_option (hint , '--hint={0}' ))
247244 prefix_patt = re .compile (r'(#\w+)' )
@@ -259,7 +256,12 @@ def emit_preamble(self, job):
259256 return list (filter (None , preamble ))
260257
261258 def submit (self , job ):
262- cmd = f'sbatch { job .script_filename } '
259+ cmd_parts = ['sbatch' ]
260+ if self ._sched_access_in_submit :
261+ cmd_parts += job .sched_access
262+
263+ cmd_parts += [job .script_filename ]
264+ cmd = ' ' .join (cmd_parts )
263265 intervals = itertools .cycle ([1 , 2 , 3 ])
264266 while True :
265267 try :
0 commit comments