Skip to content

Commit fc9dc53

Browse files
committed
Allowed programmatic access to parser
1 parent 141bdad commit fc9dc53

File tree

4 files changed

+111
-43
lines changed

4 files changed

+111
-43
lines changed

pytry/cmdline.py

+11-42
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,37 @@
11
import argparse
22
import sys
33

4-
import pytry
4+
from . import parser
5+
from . import trial
56

67

78
def run():
8-
parser = argparse.ArgumentParser(
9+
parser1 = argparse.ArgumentParser(
910
description='pytry: Run Trials with parameters')
10-
parser.add_argument('filename', metavar='FILE', type=str, nargs=1,
11-
help='.py file containing Trial object')
11+
parser1.add_argument('filename', metavar='FILE', type=str, nargs=1,
12+
help='.py file containing Trial object')
1213

1314
if len(sys.argv) < 2:
14-
parser.parse_args() # this will fail with an error message
15+
parser1.parse_args() # this will fail with an error message
1516
filename = sys.argv[1]
1617

1718
with open(filename) as f:
1819
code = f.read()
19-
objs = dict(__file__ = filename)
20+
objs = dict(__file__=filename)
2021
compiled = compile(code, filename, 'exec')
2122
exec(compiled, objs)
2223

2324
trials = []
2425
for x in objs.values():
2526
if isinstance(x, type):
26-
if issubclass(x, pytry.Trial):
27+
if issubclass(x, trial.Trial):
2728
trials.append(x)
2829

2930
if len(trials) == 0:
3031
print('Error: no pytry.Trial class found in %s' % filename)
3132
elif len(trials) > 1:
3233
print('Error: more than one pytry.Trial class found')
3334
else:
34-
trial = trials[0]()
35-
run_trial(trial, parser)
36-
37-
38-
def str2bool(text):
39-
return text.lower() in ("yes", "true", "t", "1")
40-
41-
42-
def run_trial(trial, parser):
43-
keys = list(trial.param_defaults.keys())
44-
45-
for k in sorted(keys, key=lambda x: (x in trial.system_params, x)):
46-
v = trial.param_defaults[k]
47-
desc = '%s (default=%r)' % (trial.param_descriptions[k], v)
48-
49-
if v is False:
50-
parser.add_argument('--%s' % k, default=v,
51-
action='store_true',
52-
help=desc)
53-
elif v is True:
54-
parser.add_argument('--%s' % k, default=v,
55-
metavar='<X>',
56-
type=str2bool,
57-
action='store',
58-
help=desc)
59-
else:
60-
parser.add_argument('--%s' % k, type=type(v), default=v,
61-
metavar='<X>', action='store',
62-
help=desc)
63-
64-
args = parser.parse_args()
65-
params = vars(args)
66-
del params['filename']
67-
68-
trial.run(**params)
35+
t = trials[0]()
36+
args = parser.parse_args(t, args=None, allow_filename=True)
37+
t.run(**args)

pytry/parser.py

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import argparse
2+
3+
4+
def str2bool(text):
5+
if text.lower() in ("yes", "true", "t", "1"):
6+
return True
7+
elif text.lower() in ("no", "false", "f", "0"):
8+
return False
9+
else:
10+
raise ValueError("invalid boolean value: '%s'" % text)
11+
12+
13+
def parse_args(trial, args, allow_filename=False):
14+
parser = argparse.ArgumentParser(
15+
description='pytry: Run Trials with parameters')
16+
17+
if allow_filename:
18+
parser.add_argument('filename', metavar='FILE', type=str, nargs=1,
19+
help='.py file containing Trial object')
20+
21+
keys = list(trial.param_defaults.keys())
22+
23+
for k in sorted(keys, key=lambda x: (x in trial.system_params, x)):
24+
v = trial.param_defaults[k]
25+
desc = '%s (default=%r)' % (trial.param_descriptions[k], v)
26+
27+
if v is False:
28+
parser.add_argument('--%s' % k, default=v,
29+
action='store_true',
30+
help=desc)
31+
elif v is True:
32+
parser.add_argument('--%s' % k, default=v,
33+
metavar='<X>',
34+
type=str2bool,
35+
action='store',
36+
help=desc)
37+
else:
38+
parser.add_argument('--%s' % k, type=type(v), default=v,
39+
metavar='<X>', action='store',
40+
help=desc)
41+
42+
args = parser.parse_args(args)
43+
params = vars(args)
44+
if allow_filename:
45+
del params['filename']
46+
return params

pytry/tests/test_parser.py

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import pytest
2+
3+
import pytry
4+
5+
class DummyTrial(pytry.Trial):
6+
def params(self):
7+
self.param('a', a=0)
8+
self.param('b', b=0.0)
9+
self.param('c', c='')
10+
self.param('d', d=True)
11+
self.param('e', e=False)
12+
def evaluate(self, p):
13+
return {}
14+
15+
def test_parse_valid():
16+
t = DummyTrial()
17+
18+
p = t.parse_args('--a 1 --b 0.5 --c hi --d False --e'.split())
19+
assert p['a'] == 1
20+
assert p['b'] == 0.5
21+
assert p['c'] == 'hi'
22+
assert p['d'] == False
23+
assert p['e'] == True
24+
25+
p = t.parse_args([])
26+
assert p['a'] == 0
27+
assert p['b'] == 0.0
28+
assert p['c'] == ''
29+
assert p['d'] == True
30+
assert p['e'] == False
31+
32+
def test_parse_unknown_param():
33+
t = DummyTrial()
34+
35+
with pytest.raises(SystemExit):
36+
t.parse_args('--x 1')
37+
38+
def test_parse_invalid_value():
39+
t = DummyTrial()
40+
41+
with pytest.raises(SystemExit):
42+
t.parse_args('--a hi'.split())
43+
with pytest.raises(SystemExit):
44+
t.parse_args('--a 1.5'.split())
45+
with pytest.raises(SystemExit):
46+
t.parse_args('--b hi'.split())
47+
with pytest.raises(SystemExit):
48+
t.parse_args('--d 1.2'.split())

pytry/trial.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import uuid
55

66
from . import write
7+
from . import parser
78

89

910
class Params(object):
@@ -22,7 +23,8 @@ def __init__(self):
2223
def _create_base_params(self):
2324
self.param('data directory', data_dir='data', system=True)
2425
self.param('filename for data', data_filename=None, system=True)
25-
self.param('data file format [txt,npz]', data_format='txt', system=True)
26+
self.param('data file format [txt,npz]',
27+
data_format='txt', system=True)
2628
self.param('print progress information', verbose=True, system=True)
2729
self.param('random number seed', seed=1)
2830

@@ -108,6 +110,9 @@ def do_evaluate(self, p):
108110
def execute_trial(self, p):
109111
return self.do_evaluate(p)
110112

113+
def parse_args(self, args=None):
114+
return parser.parse_args(self, args)
115+
111116
def params(self):
112117
raise NotImplementedError
113118

0 commit comments

Comments
 (0)