Skip to content

Commit e8a0279

Browse files
committed
Merge branch 'jinja2_templates'
2 parents b932c05 + 6bcb70b commit e8a0279

File tree

3 files changed

+31
-13
lines changed

3 files changed

+31
-13
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ Common attributes of batch submission / resource manager environments will inclu
3737
* job names instead of PIDs
3838

3939
`BatchSpawnerBase` provides several general mechanisms:
40-
* configurable traits `req_foo` that are exposed as `{foo}` in job template scripts
40+
* configurable traits `req_foo` that are exposed as `{foo}` in job template scripts. Templates (submit scripts in particular) may also use the full power of [jinja2](http://jinja.pocoo.org/). Templates are automatically detected if a `{{` or `{%` is present, otherwise str.format() used.
4141
* configurable command templates for submitting/querying/cancelling jobs
4242
* a generic concept of job-ID and ID-based job state tracking
4343
* overrideable hooks for subclasses to plug in logic at numerous points

batchspawner/batchspawner.py

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
import xml.etree.ElementTree as ET
2222

23+
from jinja2 import Template
24+
2325
from tornado import gen
2426
from tornado.process import Subprocess
2527
from subprocess import CalledProcessError
@@ -35,6 +37,20 @@
3537
import jupyterhub
3638

3739

40+
def format_template(template, *args, **kwargs):
41+
"""Format a template, either using jinja2 or str.format().
42+
43+
Use jinja2 if the template is a jinja2.Template, or contains '{{' or
44+
'{%'. Otherwise, use str.format() for backwards compatability with
45+
old scripts (but you can't mix them).
46+
"""
47+
if isinstance(template, Template):
48+
return template.render(*args, **kwargs)
49+
elif '{{' in template or '{%' in template:
50+
return Template(template).render(*args, **kwargs)
51+
return template.format(*args, **kwargs)
52+
53+
3854
class BatchSpawnerBase(Spawner):
3955
"""Base class for spawners using resource manager batch job submission mechanisms
4056
@@ -181,11 +197,11 @@ def run_command(self, cmd, input=None, env=None):
181197
@gen.coroutine
182198
def submit_batch_script(self):
183199
subvars = self.get_req_subvars()
184-
cmd = self.batch_submit_cmd.format(**subvars)
200+
cmd = format_template(self.batch_submit_cmd, **subvars)
185201
subvars['cmd'] = self.cmd_formatted_for_batch()
186202
if hasattr(self, 'user_options'):
187203
subvars.update(self.user_options)
188-
script = self.batch_script.format(**subvars)
204+
script = format_template(self.batch_script, **subvars)
189205
self.log.info('Spawner submitting job using ' + cmd)
190206
self.log.info('Spawner submitted script:\n' + script)
191207
out = yield self.run_command(cmd, input=script, env=self.get_env())
@@ -211,7 +227,7 @@ def read_job_state(self):
211227
return self.job_status
212228
subvars = self.get_req_subvars()
213229
subvars['job_id'] = self.job_id
214-
cmd = self.batch_query_cmd.format(**subvars)
230+
cmd = format_template(self.batch_query_cmd, **subvars)
215231
self.log.debug('Spawner querying job: ' + cmd)
216232
try:
217233
out = yield self.run_command(cmd)
@@ -230,7 +246,7 @@ def read_job_state(self):
230246
def cancel_batch_job(self):
231247
subvars = self.get_req_subvars()
232248
subvars['job_id'] = self.job_id
233-
cmd = self.batch_cancel_cmd.format(**subvars)
249+
cmd = format_template(self.batch_cancel_cmd, **subvars)
234250
self.log.info('Cancelling job ' + self.job_id + ': ' + cmd)
235251
yield self.run_command(cmd)
236252

@@ -477,18 +493,19 @@ class SlurmSpawner(UserEnvMixin,BatchSpawnerRegexStates):
477493
).tag(config=True)
478494

479495
batch_script = Unicode("""#!/bin/bash
480-
#SBATCH --partition={partition}
481-
#SBATCH --time={runtime}
482-
#SBATCH --output={homedir}/jupyterhub_slurmspawner_%j.log
496+
#SBATCH --output={{homedir}}/jupyterhub_slurmspawner_%j.log
483497
#SBATCH --job-name=spawner-jupyterhub
484-
#SBATCH --workdir={homedir}
485-
#SBATCH --mem={memory}
486-
#SBATCH --export={keepvars}
498+
#SBATCH --workdir={{homedir}}
499+
#SBATCH --export={{keepvars}}
487500
#SBATCH --get-user-env=L
488-
#SBATCH {options}
501+
{% if partition %}#SBATCH --partition={{partition}}
502+
{% endif %}{% if runtime %}#SBATCH --time={{runtime}}
503+
{% endif %}{% if memory %}#SBATCH --mem={{memory}}
504+
{% endif %}{% if nprocs %}#SBATCH --cpus-per-task={{nprocs}}
505+
{% endif %}{% if options %}#SBATCH {{options}}{% endif %}
489506
490507
which jupyterhub-singleuser
491-
{cmd}
508+
{{cmd}}
492509
""").tag(config=True)
493510
# outputs line like "Submitted batch job 209"
494511
batch_submit_cmd = Unicode('sudo -E -u {username} sbatch --parsable').tag(config=True)

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
jinja2
12
jupyterhub>=0.5

0 commit comments

Comments
 (0)