Skip to content

Commit 014b1ec

Browse files
committed
[ENH] Addressed @mgermain comments. Added unit tests.
1 parent 87c0098 commit 014b1ec

File tree

3 files changed

+81
-23
lines changed

3 files changed

+81
-23
lines changed

scripts/smart_dispatch.py

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
#!/usr/bin/env python
22
# -*- coding: utf-8 -*-
33

4-
import re
54
import os
65
import sys
76
import argparse
87
import time as t
98
import numpy as np
9+
from os.path import join as pjoin
1010
from subprocess import check_output
1111
from textwrap import dedent
1212

@@ -55,7 +55,11 @@ def main():
5555
else:
5656
raise ValueError("Unknown subcommand!")
5757

58-
command_manager = CommandManager(os.path.join(path_job_commands, "commands.txt"))
58+
# Keep a log of the command line in the job folder.
59+
command_line = " ".join(sys.argv)
60+
smartdispatch.log_command_line(path_job, command_line)
61+
62+
command_manager = CommandManager(pjoin(path_job_commands, "commands.txt"))
5963

6064
# If resume mode, reset running jobs
6165
if args.mode == "launch":
@@ -84,7 +88,7 @@ def main():
8488

8589
# If no pool size is specified the number of commands is taken
8690
if args.pool is None:
87-
args.pool = command_manager.get_nb_commands_to_run()
91+
args.pool = command_manager.get_nb_commands_to_run(command_line)
8892

8993
# Generating all the worker commands
9094
COMMAND_STRING = 'cd "{cwd}"; smart_worker.py "{commands_file}" "{log_folder}" '\
@@ -104,14 +108,6 @@ def main():
104108
job_generator = job_generator_factory(queue, commands, command_params, CLUSTER_NAME, path_job)
105109
pbs_filenames = job_generator.write_pbs_files(path_job_commands)
106110

107-
# Keep an history of command lines i.e. smart_dispatch.py commands.
108-
with utils.open_with_lock(os.path.join(path_job, "command_line_history.txt"), 'a') as command_line_history_file:
109-
command_line_history_file.write(t.strftime("## %Y-%m-%d %H:%M:%S ##\n"))
110-
command_line = " ".join(sys.argv)
111-
command_line = command_line.replace('"', r'\"') # Make sure we can paste the command line as-is
112-
command_line = re.sub(r'(\[)([^\[\]]*\\ [^\[\]]*)(\])', r'"\1\2\3"', command_line) # Make sure we can paste the command line as-is
113-
command_line_history_file.write(command_line + "\n\n")
114-
115111
# Launch the jobs
116112
print "## {nb_commands} command(s) will be executed in {nb_jobs} job(s) ##".format(nb_commands=nb_commands, nb_jobs=len(pbs_filenames))
117113
print "Batch UID:\n{batch_uid}".format(batch_uid=jobname)
@@ -121,7 +117,7 @@ def main():
121117
qsub_output = check_output('{launcher} {pbs_filename}'.format(launcher=LAUNCHER if args.launcher is None else args.launcher, pbs_filename=pbs_filename), shell=True)
122118
jobs_id += [qsub_output.strip()]
123119

124-
with utils.open_with_lock(os.path.join(path_job, "jobs_id.txt"), 'a') as jobs_id_file:
120+
with utils.open_with_lock(pjoin(path_job, "jobs_id.txt"), 'a') as jobs_id_file:
125121
jobs_id_file.writelines(t.strftime("## %Y-%m-%d %H:%M:%S ##\n"))
126122
jobs_id_file.writelines("\n".join(jobs_id) + "\n")
127123
print "\nJobs id:\n{jobs_id}".format(jobs_id=" ".join(jobs_id))
@@ -167,10 +163,10 @@ def parse_arguments():
167163

168164

169165
def _gen_job_paths(jobname):
170-
path_smartdispatch_logs = os.path.join(os.getcwd(), LOGS_FOLDERNAME)
171-
path_job = os.path.join(path_smartdispatch_logs, jobname)
172-
path_job_logs = os.path.join(path_job, 'logs')
173-
path_job_commands = os.path.join(path_job, 'commands')
166+
path_smartdispatch_logs = pjoin(os.getcwd(), LOGS_FOLDERNAME)
167+
path_job = pjoin(path_smartdispatch_logs, jobname)
168+
path_job_logs = pjoin(path_job, 'logs')
169+
path_job_commands = pjoin(path_job, 'commands')
174170

175171
return path_job, path_job_logs, path_job_commands
176172

@@ -183,10 +179,10 @@ def get_job_folders(jobname):
183179

184180
if not os.path.exists(path_job_logs):
185181
os.makedirs(path_job_logs)
186-
if not os.path.exists(os.path.join(path_job_logs, "worker")):
187-
os.makedirs(os.path.join(path_job_logs, "worker"))
188-
if not os.path.exists(os.path.join(path_job_logs, "job")):
189-
os.makedirs(os.path.join(path_job_logs, "job"))
182+
if not os.path.exists(pjoin(path_job_logs, "worker")):
183+
os.makedirs(pjoin(path_job_logs, "worker"))
184+
if not os.path.exists(pjoin(path_job_logs, "job")):
185+
os.makedirs(pjoin(path_job_logs, "job"))
190186

191187
return path_job, path_job_logs, path_job_commands
192188

@@ -200,8 +196,8 @@ def create_job_folders(jobname):
200196

201197
if not os.path.exists(path_job_logs):
202198
os.makedirs(path_job_logs)
203-
os.makedirs(os.path.join(path_job_logs, "worker"))
204-
os.makedirs(os.path.join(path_job_logs, "job"))
199+
os.makedirs(pjoin(path_job_logs, "worker"))
200+
os.makedirs(pjoin(path_job_logs, "job"))
205201

206202
return path_job, path_job_logs, path_job_commands
207203

smartdispatch/smartdispatch.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import re
55
import itertools
66
import time as t
7+
from os.path import join as pjoin
78

89
import smartdispatch
910
from smartdispatch import utils
@@ -119,3 +120,23 @@ def get_available_queues(cluster_name=utils.detect_cluster()):
119120

120121
queues_infos = utils.load_dict_from_json_file(config_filepath)
121122
return queues_infos
123+
124+
125+
def log_command_line(path_job, command_line):
126+
""" Logs a command line in a job folder.
127+
128+
The command line is append to a file named 'command_line.log' that resides
129+
in the given job folder. The current date and time is also added along
130+
each command line logged.
131+
132+
Notes
133+
-----
134+
Commands save in log file might differ from sys.argv since we want to make sure
135+
we can paste the command line as-is in the terminal. This means that the quotes
136+
symbole " and the square brackets will be escaped.
137+
"""
138+
with utils.open_with_lock(pjoin(path_job, "command_line.log"), 'a') as command_line_log:
139+
command_line_log.write(t.strftime("## %Y-%m-%d %H:%M:%S ##\n"))
140+
command_line = command_line.replace('"', r'\"') # Make sure we can paste the command line as-is
141+
command_line = re.sub(r'(\[)([^\[\]]*\\ [^\[\]]*)(\])', r'"\1\2\3"', command_line) # Make sure we can paste the command line as-is
142+
command_line_log.write(command_line + "\n\n")

smartdispatch/tests/test_smartdispatch.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
1-
import smartdispatch
1+
import os
2+
import re
3+
import shutil
4+
import time as t
5+
from os.path import join as pjoin
26
from StringIO import StringIO
37

8+
import tempfile
49
from nose.tools import assert_true, assert_equal
510
from numpy.testing import assert_array_equal
11+
12+
import smartdispatch
613
from smartdispatch import utils
714

815

@@ -137,3 +144,37 @@ def test_get_available_queues():
137144

138145
queues_infos = smartdispatch.get_available_queues(cluster_name="mammouth")
139146
assert_true(len(queues_infos) > 0)
147+
148+
149+
def test_log_command_line():
150+
temp_dir = tempfile.mkdtemp()
151+
command_line_log_file = pjoin(temp_dir, "command_line.log")
152+
153+
command_1 = "echo 1 2 3"
154+
smartdispatch.log_command_line(temp_dir, command_1)
155+
assert_true(os.path.isfile(command_line_log_file))
156+
157+
lines = open(command_line_log_file).read().strip().split("\n")
158+
assert_equal(len(lines), 2) # Datetime, the command line.
159+
assert_true(t.strftime("## %Y-%m-%d %H:%M:") in lines[0]) # Don't check second.
160+
assert_equal(lines[1], command_1)
161+
162+
command_2 = "echo \"bob\"" # With quotes.
163+
smartdispatch.log_command_line(temp_dir, command_2)
164+
assert_true(os.path.isfile(command_line_log_file))
165+
166+
lines = open(command_line_log_file).read().strip().split("\n")
167+
assert_equal(len(lines), 5)
168+
assert_true(t.strftime("## %Y-%m-%d %H:%M:") in lines[3]) # Don't check second.
169+
assert_equal(lines[4], command_2.replace('"', r'\"'))
170+
171+
command_3 = "echo [asd]" # With square brackets.
172+
smartdispatch.log_command_line(temp_dir, command_3)
173+
assert_true(os.path.isfile(command_line_log_file))
174+
175+
lines = open(command_line_log_file).read().strip().split("\n")
176+
assert_equal(len(lines), 8)
177+
assert_true(t.strftime("## %Y-%m-%d %H:%M:") in lines[6]) # Don't check second.
178+
assert_equal(lines[7], re.sub(r'(\[)([^\[\]]*\\ [^\[\]]*)(\])', r'"\1\2\3"', command_3))
179+
180+
shutil.rmtree(temp_dir)

0 commit comments

Comments
 (0)