1717"""
1818import pwd
1919import os
20+ import re
2021
2122import xml .etree .ElementTree as ET
2223
@@ -46,7 +47,7 @@ def format_template(template, *args, **kwargs):
4647 """
4748 if isinstance (template , Template ):
4849 return template .render (* args , ** kwargs )
49- elif '{{' in template or '{%' in template :
50+ elif '{{' in template or '{%' in template :
5051 return Template (template ).render (* args , ** kwargs )
5152 return template .format (* args , ** kwargs )
5253
@@ -78,52 +79,52 @@ class BatchSpawnerBase(Spawner):
7879 # override default server ip since batch jobs normally running remotely
7980 ip = Unicode ("0.0.0.0" , help = "Address for singleuser server to listen at" ).tag (config = True )
8081
81- exec_prefix = Unicode ('sudo -E -u {username}' , \
82+ exec_prefix = Unicode ('sudo -E -u {username}' ,
8283 help = "Standard executon prefix (e.g. the default sudo -E -u {username})"
8384 ).tag (config = True )
8485
8586 # all these req_foo traits will be available as substvars for templated strings
86- req_queue = Unicode ('' , \
87+ req_queue = Unicode ('' ,
8788 help = "Queue name to submit job to resource manager"
8889 ).tag (config = True )
8990
90- req_host = Unicode ('' , \
91+ req_host = Unicode ('' ,
9192 help = "Host name of batch server to submit job to resource manager"
9293 ).tag (config = True )
9394
94- req_memory = Unicode ('' , \
95+ req_memory = Unicode ('' ,
9596 help = "Memory to request from resource manager"
9697 ).tag (config = True )
9798
98- req_nprocs = Unicode ('' , \
99+ req_nprocs = Unicode ('' ,
99100 help = "Number of processors to request from resource manager"
100101 ).tag (config = True )
101102
102- req_ngpus = Unicode ('' , \
103+ req_ngpus = Unicode ('' ,
103104 help = "Number of GPUs to request from resource manager"
104105 ).tag (config = True )
105106
106- req_runtime = Unicode ('' , \
107+ req_runtime = Unicode ('' ,
107108 help = "Length of time for submitted job to run"
108109 ).tag (config = True )
109110
110- req_partition = Unicode ('' , \
111+ req_partition = Unicode ('' ,
111112 help = "Partition name to submit job to resource manager"
112113 ).tag (config = True )
113114
114- req_account = Unicode ('' , \
115+ req_account = Unicode ('' ,
115116 help = "Account name string to pass to the resource manager"
116117 ).tag (config = True )
117118
118- req_options = Unicode ('' , \
119+ req_options = Unicode ('' ,
119120 help = "Other options to include into job submission script"
120121 ).tag (config = True )
121122
122- req_prologue = Unicode ('' , \
123+ req_prologue = Unicode ('' ,
123124 help = "Script to run before single user server starts."
124125 ).tag (config = True )
125126
126- req_epilogue = Unicode ('' , \
127+ req_epilogue = Unicode ('' ,
127128 help = "Script to run after single user server ends."
128129 ).tag (config = True )
129130
@@ -148,8 +149,7 @@ def _req_keepvars_default(self):
148149 "added to the defaults in keepvars, "
149150 "comma separated list." )
150151
151-
152- batch_script = Unicode ('' , \
152+ batch_script = Unicode ('' ,
153153 help = "Template for job submission script. Traits on this class named like req_xyz "
154154 "will be substituted in the template for {xyz} using string.Formatter. "
155155 "Must include {cmd} which will be replaced with the jupyterhub-singleuser command line."
@@ -174,7 +174,7 @@ def get_req_subvars(self):
174174 subvars ['keepvars' ] += ',' + subvars ['keepvars_extra' ]
175175 return subvars
176176
177- batch_submit_cmd = Unicode ('' , \
177+ batch_submit_cmd = Unicode ('' ,
178178 help = "Command to run to submit batch scripts. Formatted using req_xyz traits as {xyz}."
179179 ).tag (config = True )
180180
@@ -244,7 +244,7 @@ def submit_batch_script(self):
244244 return self .job_id
245245
246246 # Override if your batch system needs something more elaborate to read the job status
247- batch_query_cmd = Unicode ('' , \
247+ batch_query_cmd = Unicode ('' ,
248248 help = "Command to run to read job status. Formatted using req_xyz traits as {xyz} "
249249 "and self.job_id as {job_id}."
250250 ).tag (config = True )
@@ -335,7 +335,7 @@ def poll(self):
335335 self .clear_state ()
336336 return 1
337337
338- startup_poll_interval = Float (0.5 , \
338+ startup_poll_interval = Float (0.5 ,
339339 help = "Polling interval (seconds) to check job state during startup"
340340 ).tag (config = True )
341341
@@ -345,8 +345,9 @@ def start(self):
345345 if self .user and self .user .server and self .user .server .port :
346346 self .port = self .user .server .port
347347 self .db .commit ()
348- elif (jupyterhub .version_info < (0 ,7 ) and not self .user .server .port ) or \
349- (jupyterhub .version_info >= (0 ,7 ) and not self .port ):
348+ elif (jupyterhub .version_info < (0 ,7 ) and not self .user .server .port ) or (
349+ jupyterhub .version_info >= (0 ,7 ) and not self .port
350+ ):
350351 self .port = random_port ()
351352 self .db .commit ()
352353 job = yield self .submit_batch_script ()
@@ -367,8 +368,8 @@ def start(self):
367368 else :
368369 self .log .warn ('Job ' + self .job_id + ' neither pending nor running.\n ' +
369370 self .job_status )
370- raise RuntimeError ('The Jupyter batch job has disappeared '
371- ' while pending in the queue or died immediately '
371+ raise RuntimeError ('The Jupyter batch job has disappeared'
372+ ' while pending in the queue or died immediately'
372373 ' after starting.' )
373374 yield gen .sleep (self .startup_poll_interval )
374375
@@ -405,7 +406,6 @@ def stop(self, now=False):
405406 self .job_id , self .current_ip , self .port )
406407 )
407408
408- import re
409409
410410class BatchSpawnerRegexStates (BatchSpawnerBase ):
411411 """Subclass of BatchSpawnerBase that uses config-supplied regular expressions
@@ -442,13 +442,15 @@ def state_ispending(self):
442442 assert self .state_pending_re , "Misconfigured: define state_running_re"
443443 if self .job_status and re .search (self .state_pending_re , self .job_status ):
444444 return True
445- else : return False
445+ else :
446+ return False
446447
447448 def state_isrunning (self ):
448449 assert self .state_running_re , "Misconfigured: define state_running_re"
449450 if self .job_status and re .search (self .state_running_re , self .job_status ):
450451 return True
451- else : return False
452+ else :
453+ return False
452454
453455 def state_gethost (self ):
454456 assert self .state_exechost_re , "Misconfigured: define state_exechost_re"
@@ -461,6 +463,7 @@ def state_gethost(self):
461463 else :
462464 return match .expand (self .state_exechost_exp )
463465
466+
464467class TorqueSpawner (BatchSpawnerRegexStates ):
465468 batch_script = Unicode ("""#!/bin/sh
466469#PBS -q {queue}@{host}
@@ -486,6 +489,7 @@ class TorqueSpawner(BatchSpawnerRegexStates):
486489 state_running_re = Unicode (r'<job_state>R</job_state>' ).tag (config = True )
487490 state_exechost_re = Unicode (r'<exec_host>((?:[\w_-]+\.?)+)/\d+' ).tag (config = True )
488491
492+
489493class MoabSpawner (TorqueSpawner ):
490494 # outputs job id string
491495 batch_submit_cmd = Unicode ('msub' ).tag (config = True )
@@ -496,6 +500,7 @@ class MoabSpawner(TorqueSpawner):
496500 state_running_re = Unicode (r'State="Running"' ).tag (config = True )
497501 state_exechost_re = Unicode (r'AllocNodeList="([^\r\n\t\f :"]*)' ).tag (config = True )
498502
503+
499504class UserEnvMixin :
500505 """Mixin class that computes values for USER, SHELL and HOME in the environment passed to
501506 the job submission subprocess in case the batch system needs these for the batch script."""
@@ -522,23 +527,8 @@ def get_env(self):
522527 env = self .user_env (env )
523528 return env
524529
525- class SlurmSpawner (UserEnvMixin ,BatchSpawnerRegexStates ):
526- """A Spawner that just uses Popen to start local processes."""
527-
528- # all these req_foo traits will be available as substvars for templated strings
529- req_cluster = Unicode ('' , \
530- help = "Cluster name to submit job to resource manager"
531- ).tag (config = True )
532-
533- req_qos = Unicode ('' , \
534- help = "QoS name to submit job to resource manager"
535- ).tag (config = True )
536-
537- req_srun = Unicode ('srun' ,
538- help = "Job step wrapper, default 'srun'. Set to '' you do not want "
539- "to run in job step (affects environment handling)"
540- ).tag (config = True )
541530
531+ class SlurmSpawner (UserEnvMixin ,BatchSpawnerRegexStates ):
542532 batch_script = Unicode ("""#!/bin/bash
543533#SBATCH --output={{homedir}}/jupyterhub_slurmspawner_%j.log
544534#SBATCH --job-name=spawner-jupyterhub
@@ -558,6 +548,21 @@ class SlurmSpawner(UserEnvMixin,BatchSpawnerRegexStates):
558548echo "jupyterhub-singleuser ended gracefully"
559549{{epilogue}}
560550""" ).tag (config = True )
551+
552+ # all these req_foo traits will be available as substvars for templated strings
553+ req_cluster = Unicode ('' ,
554+ help = "Cluster name to submit job to resource manager"
555+ ).tag (config = True )
556+
557+ req_qos = Unicode ('' ,
558+ help = "QoS name to submit job to resource manager"
559+ ).tag (config = True )
560+
561+ req_srun = Unicode ('srun' ,
562+ help = "Job step wrapper, default 'srun'. Set to '' you do not want "
563+ "to run in job step (affects environment handling)"
564+ ).tag (config = True )
565+
561566 # outputs line like "Submitted batch job 209"
562567 batch_submit_cmd = Unicode ('sbatch --parsable' ).tag (config = True )
563568 # outputs status and exec node like "RUNNING hostname"
@@ -579,6 +584,7 @@ def parse_job_id(self, output):
579584 raise e
580585 return id
581586
587+
582588class MultiSlurmSpawner (SlurmSpawner ):
583589 '''When slurm has been compiled with --enable-multiple-slurmd, the
584590 administrator sets the name of the slurmd instance via the slurmd -N
@@ -591,6 +597,7 @@ def state_gethost(self):
591597 host = SlurmSpawner .state_gethost (self )
592598 return self .daemon_resolver .get (host , host )
593599
600+
594601class GridengineSpawner (BatchSpawnerBase ):
595602 batch_script = Unicode ("""#!/bin/bash
596603#$ -j yes
@@ -640,6 +647,7 @@ def state_gethost(self):
640647 self .log .error ("Spawner unable to match host addr in job {0} with status {1}" .format (self .job_id , self .job_status ))
641648 return
642649
650+
643651class CondorSpawner (UserEnvMixin ,BatchSpawnerRegexStates ):
644652 batch_script = Unicode ("""
645653Executable = /bin/sh
@@ -677,6 +685,7 @@ def parse_job_id(self, output):
677685 def cmd_formatted_for_batch (self ):
678686 return super (CondorSpawner ,self ).cmd_formatted_for_batch ().replace ('"' ,'""' ).replace ("'" ,"''" )
679687
688+
680689class LsfSpawner (BatchSpawnerBase ):
681690 '''A Spawner that uses IBM's Platform Load Sharing Facility (LSF) to launch notebooks.'''
682691
@@ -723,7 +732,6 @@ def state_isrunning(self):
723732 if self .job_status :
724733 return self .job_status .split (' ' )[0 ].upper () == 'RUN'
725734
726-
727735 def state_gethost (self ):
728736 if self .job_status :
729737 return self .job_status .split (' ' )[1 ].strip ()
0 commit comments