Skip to content

Commit 9a2f918

Browse files
committed
Refactored functions and classes related to argument templates
1 parent 5fd1e5c commit 9a2f918

File tree

5 files changed

+99
-109
lines changed

5 files changed

+99
-109
lines changed

scripts/smart_dispatch.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ def main():
3535
jobname = args.commandsFile.name
3636
commands = smartdispatch.get_commands_from_file(args.commandsFile)
3737
else:
38-
# Commands that needs to be parsed and unfolded.
39-
arguments = smartdispatch.unfold_arguments(args.commandAndOptions)
40-
jobname = smartdispatch.generate_name_from_arguments(arguments, max_length=235)
41-
commands = smartdispatch.get_commands_from_arguments(arguments)
38+
# Command that needs to be parsed and unfolded.
39+
command = " ".join(args.commandAndOptions)
40+
jobname = smartdispatch.generate_name_from_command(command, max_length=235)
41+
commands = smartdispatch.unfold_command(command)
4242

4343
commands = smartdispatch.replace_uid_tag(commands)
4444

Original file line numberDiff line numberDiff line change
@@ -1,27 +1,33 @@
11
import re
2+
from collections import OrderedDict
23

34

4-
class FoldedArgumentTemplate(object):
5+
def build_argument_templates_dictionnary():
6+
# Order matter, if some regex is more greedy than another, the it should go after
7+
argument_templates = OrderedDict()
8+
argument_templates[RangeArgumentTemplate.__name__] = RangeArgumentTemplate()
9+
argument_templates[ListArgumentTemplate.__name__] = ListArgumentTemplate()
10+
return argument_templates
11+
12+
13+
class ArgumentTemplate(object):
514
def __init__(self):
6-
self.name = ""
715
self.regex = ""
816

917
def unfold(self, match):
1018
raise NotImplementedError("Subclass must implement method `unfold(self, match)`!")
1119

1220

13-
class ListFoldedArgumentTemplate(FoldedArgumentTemplate):
21+
class ListArgumentTemplate(ArgumentTemplate):
1422
def __init__(self):
15-
self.name = "list"
1623
self.regex = "\[[^]]*\]"
1724

1825
def unfold(self, match):
1926
return match[1:-1].split(' ')
2027

2128

22-
class RangeFoldedArgumentTemplate(FoldedArgumentTemplate):
29+
class RangeArgumentTemplate(ArgumentTemplate):
2330
def __init__(self):
24-
self.name = "range"
2531
self.regex = "\[(\d+):(\d+)(?::(\d+))?\]"
2632

2733
def unfold(self, match):
@@ -30,3 +36,6 @@ def unfold(self, match):
3036
end = int(groups[1])
3137
step = 1 if groups[2] is None else int(groups[2])
3238
return map(str, range(start, end, step))
39+
40+
41+
argument_templates = build_argument_templates_dictionnary()

smartdispatch/smartdispatch.py

Lines changed: 21 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import smartdispatch
99
from smartdispatch import utils
10-
from smartdispatch.folded_argument_template import ListFoldedArgumentTemplate, RangeFoldedArgumentTemplate
10+
from smartdispatch.argument_template import argument_templates
1111

1212
UID_TAG = "{UID}"
1313

@@ -100,65 +100,47 @@ def get_commands_from_file(fileobj):
100100
return fileobj.read().strip().split('\n')
101101

102102

103-
def get_commands_from_arguments(arguments):
104-
''' Obtains commands from the product of every unfolded arguments.
105-
Parameters
106-
----------
107-
arguments : list of list of str
108-
list of unfolded arguments
109-
Returns
110-
-------
111-
commands : list of str
112-
commands resulting from the product of every unfolded arguments
113-
'''
114-
return ["".join(argvalues) for argvalues in itertools.product(*arguments)]
115-
116-
117-
def unfold_arguments(arguments):
118-
''' Unfolds folded arguments into a list of unfolded arguments.
103+
def unfold_command(command):
104+
''' Unfolds a command into a list of unfolded commands.
119105
120-
An argument can be folded e.g. a list of unfolded arguments separated by spaces.
121-
An unfolded argument unfolds to itself.
106+
Unfolding is performed for every folded arguments (see *Arguments templates*)
107+
found in `command`. Then, resulting commands are generated using the product
108+
of every unfolded arguments.
122109
123110
Parameters
124111
----------
125-
arguments : list of str
126-
arguments to unfold
112+
command : list of str
113+
command to unfold
127114
128115
Returns
129116
-------
130-
unfolded_arguments : list of str
131-
result of the unfolding
117+
commands : list of str
118+
commands obtained after unfolding `command`
132119
133-
Complex arguments
134-
-----------------
120+
Arguments template
121+
------------------
135122
*list*: "[item1 item2 ... itemN]"
136123
*range*: "[start:end]" or "[start:end:step]"
137124
'''
138-
text = utils.encode_escaped_characters(" ".join(arguments))
139-
140-
# Order matter, if some regex is more greedy than another, the it should go after
141-
folded_argument_templates = [RangeFoldedArgumentTemplate(), ListFoldedArgumentTemplate()]
142-
folded_argument_templates_dict = {arg.name: arg for arg in folded_argument_templates}
125+
text = utils.encode_escaped_characters(command)
143126

144127
# Build the master regex with all argument's regex
145-
regex = "(" + "|".join(["(?P<{0}>{1})".format(arg.name, arg.regex) for arg in folded_argument_templates]) + ")"
128+
regex = "(" + "|".join(["(?P<{0}>{1})".format(name, arg.regex) for name, arg in argument_templates.items()]) + ")"
146129

147130
pos = 0
148-
unfolded_arguments = []
131+
arguments = []
149132
for match in re.finditer(regex, text):
150133
# Add already unfolded argument
151-
unfolded_arguments.append([text[pos:match.start()]])
134+
arguments.append([text[pos:match.start()]])
152135

153136
# Unfold argument
154-
folded_argument_template_name, matched_text = [(k, v) for k, v in match.groupdict().items() if v is not None][0]
155-
folded_argument_template = folded_argument_templates_dict[folded_argument_template_name]
156-
unfolded_arguments.append(folded_argument_template.unfold(matched_text))
137+
argument_template_name, matched_text = next((k, v) for k, v in match.groupdict().items() if v is not None)
138+
arguments.append(argument_templates[argument_template_name].unfold(matched_text))
157139
pos = match.end()
158140

159-
unfolded_arguments.append([text[pos:]]) # Add remaining unfolded arguments
160-
unfolded_arguments = [map(utils.decode_escaped_characters, argvalues) for argvalues in unfolded_arguments]
161-
return unfolded_arguments
141+
arguments.append([text[pos:]]) # Add remaining unfolded arguments
142+
arguments = [map(utils.decode_escaped_characters, argvalues) for argvalues in arguments]
143+
return ["".join(argvalues) for argvalues in itertools.product(*arguments)]
162144

163145

164146
def replace_uid_tag(commands):

smartdispatch/tests/test_folded_argument_template.py renamed to smartdispatch/tests/test_argument_template.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
from nose.tools import assert_equal, assert_true
1+
import re
2+
from nose.tools import assert_true
23
from numpy.testing import assert_array_equal
34

4-
from smartdispatch.folded_argument_template import ListFoldedArgumentTemplate, RangeFoldedArgumentTemplate
5-
6-
import re
5+
from smartdispatch.argument_template import ListArgumentTemplate, RangeArgumentTemplate
76

87

9-
def test_list_folded_argument_template():
8+
def test_list_argument_template():
109
# Test valid enumeration folded arguments
11-
arg = ListFoldedArgumentTemplate()
10+
arg = ListArgumentTemplate()
1211
folded_arguments = [("[]", [""]),
1312
("[1]", ["1"]),
1413
("[1 ]", ["1", ""]),
@@ -24,8 +23,8 @@ def test_list_folded_argument_template():
2423
assert_true(re.match(arg.regex, "[1 2 3") is None)
2524

2625

27-
def test_range_folded_argument_template():
28-
arg = RangeFoldedArgumentTemplate()
26+
def test_range_argument_template():
27+
arg = RangeArgumentTemplate()
2928
folded_arguments = [("[1:4]", ["1", "2", "3"]),
3029
("[1:4:2]", ["1", "3"]),
3130
]

smartdispatch/tests/test_smartdispatch.py

Lines changed: 52 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -77,71 +77,71 @@ def test_get_commands_from_file():
7777
assert_array_equal(smartdispatch.get_commands_from_file(fileobj), commands)
7878

7979

80-
def test_get_commands_from_arguments():
80+
def test_unfold_command():
8181
# Test with one argument
82-
args = [["ls"]]
83-
assert_equal(smartdispatch.get_commands_from_arguments(args), ["ls"])
82+
cmd = "ls"
83+
assert_equal(smartdispatch.unfold_command(cmd), ["ls"])
8484

85-
args = [["echo 1"]]
86-
assert_equal(smartdispatch.get_commands_from_arguments(args), ["echo 1"])
85+
cmd = "echo 1"
86+
assert_equal(smartdispatch.unfold_command(cmd), ["echo 1"])
8787

8888
# Test two arguments
89-
args = smartdispatch.unfold_arguments(["echo [1 2]"])
90-
assert_equal(smartdispatch.get_commands_from_arguments(args), ["echo 1", "echo 2"])
89+
cmd = "echo [1 2]"
90+
assert_equal(smartdispatch.unfold_command(cmd), ["echo 1", "echo 2"])
9191

92-
args = smartdispatch.unfold_arguments(["echo test [1 2] yay"])
93-
assert_equal(smartdispatch.get_commands_from_arguments(args), ["echo test 1 yay", "echo test 2 yay"])
92+
cmd = "echo test [1 2] yay"
93+
assert_equal(smartdispatch.unfold_command(cmd), ["echo test 1 yay", "echo test 2 yay"])
9494

95-
args = smartdispatch.unfold_arguments(["echo test[1 2]"])
96-
assert_equal(smartdispatch.get_commands_from_arguments(args), ["echo test1", "echo test2"])
95+
cmd = "echo test[1 2]"
96+
assert_equal(smartdispatch.unfold_command(cmd), ["echo test1", "echo test2"])
9797

98-
args = smartdispatch.unfold_arguments(["echo test[1 2]yay"])
99-
assert_equal(smartdispatch.get_commands_from_arguments(args), ["echo test1yay", "echo test2yay"])
98+
cmd = "echo test[1 2]yay"
99+
assert_equal(smartdispatch.unfold_command(cmd), ["echo test1yay", "echo test2yay"])
100100

101101
# Test multiple folded arguments
102-
args = smartdispatch.unfold_arguments(["python my_command.py", "[0.01 0.000001 0.00000000001]", "-1", "[omicron mu]"])
103-
assert_equal(smartdispatch.get_commands_from_arguments(args), ["python my_command.py 0.01 -1 omicron",
104-
"python my_command.py 0.01 -1 mu",
105-
"python my_command.py 0.000001 -1 omicron",
106-
"python my_command.py 0.000001 -1 mu",
107-
"python my_command.py 0.00000000001 -1 omicron",
108-
"python my_command.py 0.00000000001 -1 mu"])
102+
cmd = "python my_command.py [0.01 0.000001 0.00000000001] -1 [omicron mu]"
103+
assert_equal(smartdispatch.unfold_command(cmd), ["python my_command.py 0.01 -1 omicron",
104+
"python my_command.py 0.01 -1 mu",
105+
"python my_command.py 0.000001 -1 omicron",
106+
"python my_command.py 0.000001 -1 mu",
107+
"python my_command.py 0.00000000001 -1 omicron",
108+
"python my_command.py 0.00000000001 -1 mu"])
109109

110110
# Test multiple folded arguments and not unfoldable brackets
111-
args = smartdispatch.unfold_arguments(["python my_command.py [0.01 0.000001 0.00000000001] -1 \[[42 133,666]\] slow [omicron mu]"])
112-
assert_equal(smartdispatch.get_commands_from_arguments(args), ["python my_command.py 0.01 -1 [42] slow omicron",
113-
"python my_command.py 0.01 -1 [42] slow mu",
114-
"python my_command.py 0.01 -1 [133,666] slow omicron",
115-
"python my_command.py 0.01 -1 [133,666] slow mu",
116-
"python my_command.py 0.000001 -1 [42] slow omicron",
117-
"python my_command.py 0.000001 -1 [42] slow mu",
118-
"python my_command.py 0.000001 -1 [133,666] slow omicron",
119-
"python my_command.py 0.000001 -1 [133,666] slow mu",
120-
"python my_command.py 0.00000000001 -1 [42] slow omicron",
121-
"python my_command.py 0.00000000001 -1 [42] slow mu",
122-
"python my_command.py 0.00000000001 -1 [133,666] slow omicron",
123-
"python my_command.py 0.00000000001 -1 [133,666] slow mu"])
111+
cmd = "python my_command.py [0.01 0.000001 0.00000000001] -1 \[[42 133,666]\] slow [omicron mu]"
112+
assert_equal(smartdispatch.unfold_command(cmd), ["python my_command.py 0.01 -1 [42] slow omicron",
113+
"python my_command.py 0.01 -1 [42] slow mu",
114+
"python my_command.py 0.01 -1 [133,666] slow omicron",
115+
"python my_command.py 0.01 -1 [133,666] slow mu",
116+
"python my_command.py 0.000001 -1 [42] slow omicron",
117+
"python my_command.py 0.000001 -1 [42] slow mu",
118+
"python my_command.py 0.000001 -1 [133,666] slow omicron",
119+
"python my_command.py 0.000001 -1 [133,666] slow mu",
120+
"python my_command.py 0.00000000001 -1 [42] slow omicron",
121+
"python my_command.py 0.00000000001 -1 [42] slow mu",
122+
"python my_command.py 0.00000000001 -1 [133,666] slow omicron",
123+
"python my_command.py 0.00000000001 -1 [133,666] slow mu"])
124124

125125
# Test multiple different folded arguments
126-
args = smartdispatch.unfold_arguments(["python my_command.py [0.01 0.001] -[1:5] slow"])
127-
assert_equal(smartdispatch.get_commands_from_arguments(args), ["python my_command.py 0.01 -1 slow",
128-
"python my_command.py 0.01 -2 slow",
129-
"python my_command.py 0.01 -3 slow",
130-
"python my_command.py 0.01 -4 slow",
131-
"python my_command.py 0.001 -1 slow",
132-
"python my_command.py 0.001 -2 slow",
133-
"python my_command.py 0.001 -3 slow",
134-
"python my_command.py 0.001 -4 slow"])
135-
136-
args = smartdispatch.unfold_arguments(["python my_command.py -[1:5] slow [0.01 0.001]"])
137-
assert_equal(smartdispatch.get_commands_from_arguments(args), ["python my_command.py -1 slow 0.01",
138-
"python my_command.py -1 slow 0.001",
139-
"python my_command.py -2 slow 0.01",
140-
"python my_command.py -2 slow 0.001",
141-
"python my_command.py -3 slow 0.01",
142-
"python my_command.py -3 slow 0.001",
143-
"python my_command.py -4 slow 0.01",
144-
"python my_command.py -4 slow 0.001"])
126+
cmd = "python my_command.py [0.01 0.001] -[1:5] slow"
127+
assert_equal(smartdispatch.unfold_command(cmd), ["python my_command.py 0.01 -1 slow",
128+
"python my_command.py 0.01 -2 slow",
129+
"python my_command.py 0.01 -3 slow",
130+
"python my_command.py 0.01 -4 slow",
131+
"python my_command.py 0.001 -1 slow",
132+
"python my_command.py 0.001 -2 slow",
133+
"python my_command.py 0.001 -3 slow",
134+
"python my_command.py 0.001 -4 slow"])
135+
136+
cmd = "python my_command.py -[1:5] slow [0.01 0.001]"
137+
assert_equal(smartdispatch.unfold_command(cmd), ["python my_command.py -1 slow 0.01",
138+
"python my_command.py -1 slow 0.001",
139+
"python my_command.py -2 slow 0.01",
140+
"python my_command.py -2 slow 0.001",
141+
"python my_command.py -3 slow 0.01",
142+
"python my_command.py -3 slow 0.001",
143+
"python my_command.py -4 slow 0.01",
144+
"python my_command.py -4 slow 0.001"])
145145

146146

147147
def test_replace_uid_tag():

0 commit comments

Comments
 (0)