forked from IDSIA/sacred
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcommandline_options.py
293 lines (219 loc) · 8.21 KB
/
commandline_options.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
#!/usr/bin/env python
# coding=utf-8
"""
This module provides the basis for all command-line options (flags) in sacred.
It defines the base class CommandLineOption and the standard supported flags.
Some further options that add observers to the run are defined alongside those.
"""
import warnings
from sacred.commands import print_config
from sacred.settings import SETTINGS
from sacred.utils import convert_camel_case_to_snake_case, get_inheritors
class CommandLineOption:
"""
Base class for all command-line options.
To implement a new command-line option just inherit from this class.
Then add the `flag` class-attribute to specify the name and a class
docstring with the description.
If your command-line option should take an argument you must also provide
its name via the `arg` class attribute and its description as
`arg_description`.
Finally you need to implement the `execute` classmethod. It receives the
value of the argument (if applicable) and the current run. You can modify
the run object in any way.
If the command line option depends on one or more installed packages, those
should be imported in the `apply` method to get a proper ImportError
if the packages are not available.
"""
_enabled = True
short_flag = None
""" The (one-letter) short form (defaults to first letter of flag) """
arg = None
""" Name of the argument (optional) """
arg_description = None
""" Description of the argument (optional) """
@classmethod
def get_flag(cls):
# Get the flag name from the class name
flag = cls.__name__
if flag.endswith("Option"):
flag = flag[:-6]
return "--" + convert_camel_case_to_snake_case(flag)
@classmethod
def get_short_flag(cls):
if cls.short_flag is None:
return "-" + cls.get_flag()[2]
else:
return "-" + cls.short_flag
@classmethod
def get_flags(cls):
"""
Return the short and the long version of this option.
The long flag (e.g. '--foo_bar'; used on the command-line like this:
--foo_bar[=ARGS]) is derived from the class-name by stripping away any
-Option suffix and converting the rest to snake_case.
The short flag (e.g. '-f'; used on the command-line like this:
-f [ARGS]) the short_flag class-member if that is set, or the first
letter of the long flag otherwise.
Returns
-------
(str, str)
tuple of short-flag, and long-flag
"""
return cls.get_short_flag(), cls.get_flag()
@classmethod
def apply(cls, args, run):
"""
Modify the current Run base on this command-line option.
This function is executed after constructing the Run object, but
before actually starting it.
Parameters
----------
args : bool | str
If this command-line option accepts an argument this will be value
of that argument if set or None.
Otherwise it is either True or False.
run : sacred.run.Run
The current run to be modified
"""
pass
def gather_command_line_options(filter_disabled=None):
"""Get a sorted list of all CommandLineOption subclasses."""
if filter_disabled is None:
filter_disabled = not SETTINGS.COMMAND_LINE.SHOW_DISABLED_OPTIONS
options = [
opt
for opt in get_inheritors(CommandLineOption)
if not filter_disabled or opt._enabled
]
return sorted(options, key=lambda opt: opt.__name__)
class HelpOption(CommandLineOption):
"""Print this help message and exit."""
class DebugOption(CommandLineOption):
"""
Suppress warnings about missing observers and don't filter the stacktrace.
Also enables usage with ipython --pdb.
"""
@classmethod
def apply(cls, args, run):
"""Set this run to debug mode."""
run.debug = True
class PDBOption(CommandLineOption):
"""Automatically enter post-mortem debugging with pdb on failure."""
short_flag = "D"
@classmethod
def apply(cls, args, run):
run.pdb = True
class LoglevelOption(CommandLineOption):
"""Adjust the loglevel."""
arg = "LEVEL"
arg_description = (
"Loglevel either as 0 - 50 or as string: DEBUG(10), "
"INFO(20), WARNING(30), ERROR(40), CRITICAL(50)"
)
@classmethod
def apply(cls, args, run):
"""Adjust the loglevel of the root-logger of this run."""
# TODO: sacred.initialize.create_run already takes care of this
try:
lvl = int(args)
except ValueError:
lvl = args
run.root_logger.setLevel(lvl)
class CommentOption(CommandLineOption):
"""Adds a message to the run."""
arg = "COMMENT"
arg_description = "A comment that should be stored along with the run."
@classmethod
def apply(cls, args, run):
"""Add a comment to this run."""
run.meta_info["comment"] = args
class BeatIntervalOption(CommandLineOption):
"""Control the rate of heartbeat events."""
arg = "BEAT_INTERVAL"
arg_description = "Time between two heartbeat events measured in seconds."
@classmethod
def apply(cls, args, run):
"""Set the heart-beat interval for this run."""
run.beat_interval = float(args)
class UnobservedOption(CommandLineOption):
"""Ignore all observers for this run."""
@classmethod
def apply(cls, args, run):
"""Set this run to unobserved mode."""
run.unobserved = True
class QueueOption(CommandLineOption):
"""Only queue this run, do not start it."""
@classmethod
def apply(cls, args, run):
"""Set this run to queue only mode."""
run.queue_only = True
class ForceOption(CommandLineOption):
"""Disable warnings about suspicious changes for this run."""
@classmethod
def apply(cls, args, run):
"""Set this run to not warn about suspicous changes."""
run.force = True
class PriorityOption(CommandLineOption):
"""Sets the priority for a queued up experiment."""
short_flag = "P"
arg = "PRIORITY"
arg_description = "The (numeric) priority for this run."
@classmethod
def apply(cls, args, run):
"""Add priority info for this run."""
try:
priority = float(args)
except ValueError:
raise ValueError(
"The PRIORITY argument must be a number! " "(but was '{}')".format(args)
)
run.meta_info["priority"] = priority
class EnforceCleanOption(CommandLineOption):
"""Fail if any version control repository is dirty."""
@classmethod
def apply(cls, args, run):
try:
import git # NOQA
except ImportError:
warnings.warn(
"GitPython must be installed to use the " "--enforce-clean option."
)
raise
repos = run.experiment_info["repositories"]
if not repos:
raise RuntimeError(
"No version control detected. "
"Cannot enforce clean repository.\n"
"Make sure that your sources under VCS and the "
"corresponding python package is installed."
)
else:
for repo in repos:
if repo["dirty"]:
raise RuntimeError(
"EnforceClean: Uncommited changes in "
'the "{}" repository.'.format(repo)
)
class PrintConfigOption(CommandLineOption):
"""Always print the configuration first."""
@classmethod
def apply(cls, args, run):
print_config(run)
print("-" * 79)
class NameOption(CommandLineOption):
"""Set the name for this run."""
arg = "NAME"
arg_description = "Name for this run."
@classmethod
def apply(cls, args, run):
run.experiment_info["name"] = args
run.run_logger = run.root_logger.getChild(args)
class CaptureOption(CommandLineOption):
"""Control the way stdout and stderr are captured."""
short_flag = "C"
arg = "CAPTURE_MODE"
arg_description = "stdout/stderr capture mode. One of [no, sys, fd]"
@classmethod
def apply(cls, args, run):
run.capture_mode = args