Completed
Push — master ( 2d5fd3...e2acfa )
by Klaus
01:03
created

tests.test_pickle_numpy_arrays_son_manipulator()   A

Complexity

Conditions 4

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 4
dl 0
loc 17
rs 9.2
1
#!/usr/bin/env python
2
# coding=utf-8
3
from __future__ import division, print_function, unicode_literals
4
5
import datetime
6
7
import mock
8
import mongomock
9
import pytest
10
from sacred.dependencies import get_digest
11
from sacred.observers.mongo import (MongoObserver, MongoDbOption,
12
                                    force_bson_encodeable)
13
from sacred import optional as opt
14
15
T1 = datetime.datetime(1999, 5, 4, 3, 2, 1, 0)
16
T2 = datetime.datetime(1999, 5, 5, 5, 5, 5, 5)
17
18
pymongo = pytest.importorskip("pymongo")
19
20
21
@pytest.fixture
22
def mongo_obs():
23
    db = mongomock.MongoClient().db
24
    runs = db.runs
25
    fs = mock.MagicMock()
26
    return MongoObserver(runs, fs)
27
28
29
def test_mongo_observer_started_event_creates_run(mongo_obs):
30
    exp = {'name': 'test_exp', 'sources': [], 'doc': ''}
31
    host = {'hostname': 'test_host', 'cpu_count': 1, 'python_version': '3.4'}
32
    config = {'config': 'True', 'foo': 'bar', 'answer': 42}
33
    comment = 'test run'
34
    mongo_obs.started_event(exp, host, T1, config, comment)
35
36
    assert mongo_obs.runs.count() == 1
37
    db_run = mongo_obs.runs.find_one()
38
    del db_run['_id']
39
    assert db_run == {
40
        'experiment': exp,
41
        'host': host,
42
        'start_time': T1,
43
        'heartbeat': None,
44
        'info': {},
45
        'captured_out': '',
46
        'artifacts': [],
47
        'config': config,
48
        'comment': comment,
49
        'status': 'RUNNING',
50
        'resources': []
51
    }
52
53
54
def test_mongo_observer_equality(mongo_obs):
55
    runs = mongo_obs.runs
56
    fs = mock.MagicMock()
57
    m = MongoObserver(runs, fs)
58
    assert mongo_obs == m
59
    assert not mongo_obs != m
60
61
    assert not mongo_obs == 'foo'
62
    assert mongo_obs != 'foo'
63
64
65
def test_mongo_observer_heartbeat_event_updates_run(mongo_obs):
66
    exp = {'name': 'test_exp', 'sources': [], 'doc': ''}
67
    host = {'hostname': 'test_host', 'cpu_count': 1, 'python_version': '3.4'}
68
69
    config = {'config': 'True', 'foo': 'bar', 'answer': 42}
70
    mongo_obs.started_event(exp, host, T1, config, 'comment')
71
72
    info = {'my_info': [1, 2, 3], 'nr': 7}
73
    outp = 'some output'
74
    mongo_obs.heartbeat_event(info=info, captured_out=outp, beat_time=T2)
75
76
    assert mongo_obs.runs.count() == 1
77
    db_run = mongo_obs.runs.find_one()
78
    assert db_run['heartbeat'] == T2
79
    assert db_run['info'] == info
80
    assert db_run['captured_out'] == outp
81
82
83
def test_mongo_observer_completed_event_updates_run(mongo_obs):
84
    exp = {'name': 'test_exp', 'sources': [], 'doc': ''}
85
    host = {'hostname': 'test_host', 'cpu_count': 1, 'python_version': '3.4'}
86
    config = {'config': 'True', 'foo': 'bar', 'answer': 42}
87
    mongo_obs.started_event(exp, host, T1, config, 'comment')
88
89
    mongo_obs.completed_event(stop_time=T2, result=42)
90
91
    assert mongo_obs.runs.count() == 1
92
    db_run = mongo_obs.runs.find_one()
93
    assert db_run['stop_time'] == T2
94
    assert db_run['result'] == 42
95
    assert db_run['status'] == 'COMPLETED'
96
97
98
def test_mongo_observer_interrupted_event_updates_run(mongo_obs):
99
    exp = {'name': 'test_exp', 'sources': [], 'doc': ''}
100
    host = {'hostname': 'test_host', 'cpu_count': 1, 'python_version': '3.4'}
101
    config = {'config': 'True', 'foo': 'bar', 'answer': 42}
102
    mongo_obs.started_event(exp, host, T1, config, 'comment')
103
104
    mongo_obs.interrupted_event(interrupt_time=T2)
105
106
    assert mongo_obs.runs.count() == 1
107
    db_run = mongo_obs.runs.find_one()
108
    assert db_run['stop_time'] == T2
109
    assert db_run['status'] == 'INTERRUPTED'
110
111
112
def test_mongo_observer_failed_event_updates_run(mongo_obs):
113
    exp = {'name': 'test_exp', 'sources': [], 'doc': ''}
114
    host = {'hostname': 'test_host', 'cpu_count': 1, 'python_version': '3.4'}
115
    config = {'config': 'True', 'foo': 'bar', 'answer': 42}
116
    mongo_obs.started_event(exp, host, T1, config, 'comment')
117
118
    fail_trace = "lots of errors and\nso\non..."
119
    mongo_obs.failed_event(fail_time=T2,
120
                           fail_trace=fail_trace)
121
122
    assert mongo_obs.runs.count() == 1
123
    db_run = mongo_obs.runs.find_one()
124
    assert db_run['stop_time'] == T2
125
    assert db_run['status'] == 'FAILED'
126
    assert db_run['fail_trace'] == fail_trace
127
128
129
def test_mongo_observer_artifact_event(mongo_obs):
130
    exp = {'name': 'test_exp', 'sources': [], 'doc': ''}
131
    host = {'hostname': 'test_host', 'cpu_count': 1, 'python_version': '3.4'}
132
    config = {'config': 'True', 'foo': 'bar', 'answer': 42}
133
    mongo_obs.started_event(exp, host, T1, config, 'comment')
134
135
    filename = "setup.py"
136
137
    mongo_obs.artifact_event(filename)
138
139
    assert mongo_obs.fs.put.called
140
    assert mongo_obs.fs.put.call_args[1]['filename'].endswith(filename)
141
142
    db_run = mongo_obs.runs.find_one()
143
    assert db_run['artifacts']
144
145
146
def test_mongo_observer_resource_event(mongo_obs):
147
    exp = {'name': 'test_exp', 'sources': [], 'doc': ''}
148
    host = {'hostname': 'test_host', 'cpu_count': 1, 'python_version': '3.4'}
149
    config = {'config': 'True', 'foo': 'bar', 'answer': 42}
150
    mongo_obs.started_event(exp, host, T1, config, 'comment')
151
152
    filename = "setup.py"
153
    md5 = get_digest(filename)
154
155
    mongo_obs.resource_event(filename)
156
157
    assert mongo_obs.fs.exists.called
158
    mongo_obs.fs.exists.assert_any_call(filename=filename)
159
160
    db_run = mongo_obs.runs.find_one()
161
    assert db_run['resources'] == [(filename, md5)]
162
163
164
def test_force_bson_encodable_doesnt_change_valid_document():
165
    d = {'int': 1, 'string': 'foo', 'float': 23.87, 'list': ['a', 1, True],
166
         'bool': True, 'cr4zy: _but_ [legal) Key!': '$illegal.key.as.value',
167
         'datetime': datetime.datetime.now(), 'tuple': (1, 2.0, 'three'),
168
         'none': None}
169
    assert force_bson_encodeable(d) == d
170
171
172
def test_force_bson_encodable_substitutes_illegal_value_with_strings():
173
    d = {
174
        'a_module': datetime,
175
        'some_legal_stuff': {'foo': 'bar', 'baz': [1, 23, 4]},
176
        'nested': {
177
            'dict': {
178
                'with': {
179
                    'illegal_module': mock
180
                }
181
            }
182
        },
183
        '$illegal': 'because it starts with a $',
184
        'il.legal': 'because it contains a .',
185
        12.7: 'illegal because it is not a string key'
186
    }
187
    expected = {
188
        'a_module': str(datetime),
189
        'some_legal_stuff': {'foo': 'bar', 'baz': [1, 23, 4]},
190
        'nested': {
191
            'dict': {
192
                'with': {
193
                    'illegal_module': str(mock)
194
                }
195
            }
196
        },
197
        '@illegal': 'because it starts with a $',
198
        'il,legal': 'because it contains a .',
199
        '12,7': 'illegal because it is not a string key'
200
    }
201
    assert force_bson_encodeable(d) == expected
202
203
204
@pytest.mark.skipif(not opt.has_numpy, reason='needs numpy')
205
def test_numpy_array_to_list_son_manipulator():
206
    from sacred.observers.mongo import NumpyArraysToList
207
    import numpy as np
208
    sonm = NumpyArraysToList()
209
    document = {
210
        'foo': 'bar',
211
        'some_array': np.eye(3),
212
        'nested': {
213
            'ones': np.ones(5)
214
        }
215
    }
216
    mod_doc = sonm.transform_incoming(document, 'fake_collection')
217
    assert mod_doc['foo'] == 'bar'
218
    assert mod_doc['some_array'] == [[1.0, 0.0, 0.0],
219
                                     [0.0, 1.0, 0.0],
220
                                     [0.0, 0.0, 1.0]]
221
    assert mod_doc['nested']['ones'] == [1.0, 1.0, 1.0, 1.0, 1.0]
222
223
224
@pytest.mark.skipif(not opt.has_pandas, reason='needs pandas')
225
def test_pandas_to_json_son_manipulator():
226
    from sacred.observers.mongo import PandasToJson
227
    import numpy as np
228
    import pandas as pd
229
    sonm = PandasToJson()
230
    document = {
231
        'foo': 'bar',
232
        'some_array': pd.DataFrame(np.eye(3), columns=list('ABC')),
233
        'nested': {
234
            'ones': pd.Series(np.ones(5))
235
        }
236
    }
237
    mod_doc = sonm.transform_incoming(document, 'fake_collection')
238
    assert mod_doc['foo'] == 'bar'
239
    assert mod_doc['some_array'] == {'A': {'0': 1.0, '1': 0.0, '2': 0.0},
240
                                     'B': {'0': 0.0, '1': 1.0, '2': 0.0},
241
                                     'C': {'0': 0.0, '1': 0.0, '2': 1.0}}
242
    assert mod_doc['nested']['ones'] == {"0": 1.0, "1": 1.0, "2": 1.0,
243
                                         "3": 1.0, "4": 1.0}
244
245
246
# ###################### MongoDbOption ###################################### #
247
248
def test_parse_mongo_db_arg():
249
    assert MongoDbOption.parse_mongo_db_arg('foo') == ('localhost:27017',
250
                                                       'foo', '')
251
252
253
def test_parse_mongo_db_arg_collection():
254
    assert MongoDbOption.parse_mongo_db_arg('foo.bar') == ('localhost:27017',
255
                                                           'foo', 'bar')
256
257
258
def test_parse_mongo_db_arg_hostname():
259
    assert MongoDbOption.parse_mongo_db_arg('localhost:28017') == \
260
        ('localhost:28017', 'sacred', '')
261
262
    assert MongoDbOption.parse_mongo_db_arg('www.mymongo.db:28017') == \
263
        ('www.mymongo.db:28017', 'sacred', '')
264
265
    assert MongoDbOption.parse_mongo_db_arg('123.45.67.89:27017') == \
266
        ('123.45.67.89:27017', 'sacred', '')
267
268
269
def test_parse_mongo_db_arg_hostname_dbname():
270
    assert MongoDbOption.parse_mongo_db_arg('localhost:28017:foo') == \
271
        ('localhost:28017', 'foo', '')
272
273
    assert MongoDbOption.parse_mongo_db_arg('www.mymongo.db:28017:bar') == \
274
        ('www.mymongo.db:28017', 'bar', '')
275
276
    assert MongoDbOption.parse_mongo_db_arg('123.45.67.89:27017:baz') == \
277
        ('123.45.67.89:27017', 'baz', '')
278
279
280
def test_parse_mongo_db_arg_hostname_dbname_collection_name():
281
    assert MongoDbOption.parse_mongo_db_arg('localhost:28017:foo.bar') == \
282
        ('localhost:28017', 'foo', 'bar')
283
284
    assert MongoDbOption.parse_mongo_db_arg('www.mymongo.db:28017:bar.baz') ==\
285
        ('www.mymongo.db:28017', 'bar', 'baz')
286
287
    assert MongoDbOption.parse_mongo_db_arg('123.45.67.89:27017:baz.foo') == \
288
        ('123.45.67.89:27017', 'baz', 'foo')
289