Completed
Push — master ( 2f3aad...e06a88 )
by Klaus
01:09
created

CaptureOption   A

Complexity

Total Complexity 1

Size/Duplication

Total Lines 10
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 10
rs 10
wmc 1

1 Method

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