Completed
Push — master ( 576803...5d8e11 )
by Klaus
28s
created

tests/test_experiment.py (1 issue)

1
#!/usr/bin/env python
2
# coding=utf-8
3
from __future__ import division, print_function, unicode_literals
4
5
from sacred import Ingredient
6
7
"""Global Docstring"""
8
9
from mock import patch
10
import pytest
11
import sys
12
13
from sacred.experiment import Experiment
14
from sacred.utils import apply_backspaces_and_linefeeds
15
16
17
@pytest.fixture
18
def ex():
19
    return Experiment('ator3000')
20
21
22
def test_main(ex):
23
    @ex.main
24
    def foo():
25
        pass
26
27
    assert 'foo' in ex.commands
28
    assert ex.commands['foo'] == foo
29
    assert ex.default_command == 'foo'
30
31
32
def test_automain_imported(ex):
33
    main_called = [False]
34
35
    with patch.object(sys, 'argv', ['test.py']):
36
37
        @ex.automain
38
        def foo():
39
            main_called[0] = True
40
41
        assert 'foo' in ex.commands
42
        assert ex.commands['foo'] == foo
43
        assert ex.default_command == 'foo'
44
        assert main_called[0] is False
45
46
47
def test_automain_script_runs_main(ex):
48
    global __name__
49
    oldname = __name__
50
    main_called = [False]
51
52
    try:
53
        __name__ = '__main__'
54
        with patch.object(sys, 'argv', ['test.py']):
55
            @ex.automain
56
            def foo():
57
                main_called[0] = True
58
59
            assert 'foo' in ex.commands
60
            assert ex.commands['foo'] == foo
61
            assert ex.default_command == 'foo'
62
            assert main_called[0] is True
63
    finally:
64
        __name__ = oldname
65
66
67
def test_fails_on_unused_config_updates(ex):
68
    @ex.config
69
    def cfg():
70
        a = 1
71
        c = 3
72
73
    @ex.main
74
    def foo(a, b=2):
75
        return a + b
76
77
    # normal config updates work
78
    assert ex.run(config_updates={'a': 3}).result == 5
79
    # not in config but used works
80
    assert ex.run(config_updates={'b': 8}).result == 9
81
    # unused but in config updates work
82
    assert ex.run(config_updates={'c': 9}).result == 3
83
84
    # unused config updates raise
85
    with pytest.raises(KeyError):
86
        ex.run(config_updates={'d': 3})
87
88
89
def test_fails_on_nested_unused_config_updates(ex):
90
    @ex.config
91
    def cfg():
92
        a = {'b': 1}
93
        d = {'e': 3}
94
95
    @ex.main
96
    def foo(a):
97
        return a['b']
98
99
    # normal config updates work
100
    assert ex.run(config_updates={'a': {'b': 2}}).result == 2
101
    # not in config but parent is works
102
    assert ex.run(config_updates={'a': {'c': 5}}).result == 1
103
    # unused but in config works
104
    assert ex.run(config_updates={'d': {'e': 7}}).result == 1
105
106
    # unused nested config updates raise
107
    with pytest.raises(KeyError):
108
        ex.run(config_updates={'d': {'f': 3}})
109
110
111
def test_considers_captured_functions_for_fail_on_unused_config(ex):
112
    @ex.config
113
    def cfg():
114
        a = 1
115
116
    @ex.capture
117
    def transmogrify(a, b=0):
118
        return a + b
119
120
    @ex.main
121
    def foo():
122
        return transmogrify()
123
124
    assert ex.run(config_updates={'a': 7}).result == 7
125
    assert ex.run(config_updates={'b': 3}).result == 4
126
127
    with pytest.raises(KeyError):
128
        ex.run(config_updates={'c': 3})
129
130
131
def test_considers_prefix_for_fail_on_unused_config(ex):
132
    @ex.config
133
    def cfg():
134
        a = {'b': 1}
135
136
    @ex.capture(prefix='a')
137
    def transmogrify(b):
138
        return b
139
140
    @ex.main
141
    def foo():
142
        return transmogrify()
143
144
    assert ex.run(config_updates={'a': {'b': 3}}).result == 3
145
146
    with pytest.raises(KeyError):
147
        ex.run(config_updates={'b': 5})
148
149
    with pytest.raises(KeyError):
150
        ex.run(config_updates={'a': {'c': 5}})
151
152
153
def test_non_existing_prefix_is_treatet_as_empty_dict(ex):
154
    @ex.capture(prefix='nonexisting')
155
    def transmogrify(b=10):
156
        return b
157
158
    @ex.main
159
    def foo():
160
        return transmogrify()
161
162
    assert ex.run().result == 10
163
164
165
def test_using_a_named_config(ex):
166
    @ex.config
167
    def cfg():
168
        a = 1
169
170
    @ex.named_config
171
    def ncfg():
172
        a = 10
173
174
    @ex.main
175
    def run(a):
176
        return a
177
178
    assert ex.run().result == 1
179 View Code Duplication
    assert ex.run(named_configs=['ncfg']).result == 10
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
180
181
182
def test_empty_dict_named_config(ex):
183
    @ex.named_config
184
    def ncfg():
185
        empty_dict = {}
186
        nested_empty_dict = {'k1': {'k2': {}}}
187
188
    @ex.automain
189
    def main(empty_dict=1, nested_empty_dict=2):
190
        return empty_dict, nested_empty_dict
191
192
    assert ex.run().result == (1, 2)
193
    assert ex.run(named_configs=['ncfg']).result == ({}, {'k1': {'k2': {}}})
194
195
196
def test_named_config_and_ingredient():
197
    ing = Ingredient('foo')
198
199
    @ing.config
200
    def cfg():
201
        a = 10
202
203
    ex = Experiment(ingredients=[ing])
204
205
    @ex.config
206
    def default():
207
        b = 20
208
209
    @ex.named_config
210
    def named():
211
        b = 30
212
213
    @ex.main
214
    def main():
215
        pass
216
217
    r = ex.run(named_configs=['named'])
218
    assert r.config['b'] == 30
219
    assert r.config['foo'] == {'a': 10}
220
221
222
def test_captured_out_filter(ex, capsys):
223
    @ex.main
224
    def run_print_mock_progress():
225
        sys.stdout.write('progress 0')
226
        sys.stdout.flush()
227
        for i in range(10):
228
            sys.stdout.write('\b')
229
            sys.stdout.write("{}".format(i))
230
            sys.stdout.flush()
231
232
    ex.captured_out_filter = apply_backspaces_and_linefeeds
233
    # disable logging and set capture mode to python
234
    options = {'--loglevel': 'CRITICAL', '--capture': 'sys'}
235
    with capsys.disabled():
236
        assert ex.run(options=options).captured_out == 'progress 9'
237
238
239
def test_adding_option_hooks(ex):
240
    @ex.option_hook
241
    def hook(options):
242
        pass
243
244
    @ex.option_hook
245
    def hook2(options):
246
        pass
247
248
    assert hook in ex.option_hooks
249
    assert hook2 in ex.option_hooks
250
251
252
def test_option_hooks_without_options_arg_raises(ex):
253
    with pytest.raises(KeyError):
254
        @ex.option_hook
255
        def invalid_hook(wrong_arg_name):
256
            pass
257