test_config.py 12.6 KB
Newer Older
Kai Chen's avatar
Kai Chen committed
1
# Copyright (c) Open-MMLab. All rights reserved.
2
import argparse
Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
3
import json
Kai Chen's avatar
Kai Chen committed
4
import os.path as osp
Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
5
import tempfile
Kai Chen's avatar
Kai Chen committed
6
7

import pytest
8
import yaml
Kai Chen's avatar
Kai Chen committed
9

Kevin's avatar
Kevin committed
10
from mmcv import Config, DictAction, dump, load
Kai Chen's avatar
Kai Chen committed
11

12
13
data_path = osp.join(osp.dirname(osp.dirname(__file__)), 'data')

Kai Chen's avatar
Kai Chen committed
14

Kai Chen's avatar
Kai Chen committed
15
def test_construct():
Kai Chen's avatar
Kai Chen committed
16
17
18
19
20
21
    cfg = Config()
    assert cfg.filename is None
    assert cfg.text == ''
    assert len(cfg) == 0
    assert cfg._cfg_dict == {}

Kai Chen's avatar
Kai Chen committed
22
23
24
    with pytest.raises(TypeError):
        Config([0, 1])

Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
25
    cfg_dict = dict(item1=[1, 2], item2=dict(a=0), item3=True, item4='test')
26
    # test a.py
27
    cfg_file = osp.join(data_path, 'config/a.py')
28
29
30
31
32
33
34
35
36
37
38
39
    cfg = Config(cfg_dict, filename=cfg_file)
    assert isinstance(cfg, Config)
    assert cfg.filename == cfg_file
    assert cfg.text == open(cfg_file, 'r').read()
    assert cfg.dump() == cfg.pretty_text
    with tempfile.TemporaryDirectory() as temp_config_dir:
        dump_file = osp.join(temp_config_dir, 'a.py')
        cfg.dump(dump_file)
        assert cfg.dump() == open(dump_file, 'r').read()
        assert Config.fromfile(dump_file)

    # test b.json
40
    cfg_file = osp.join(data_path, 'config/b.json')
41
42
43
44
45
46
47
48
49
50
51
52
    cfg = Config(cfg_dict, filename=cfg_file)
    assert isinstance(cfg, Config)
    assert cfg.filename == cfg_file
    assert cfg.text == open(cfg_file, 'r').read()
    assert cfg.dump() == json.dumps(cfg_dict)
    with tempfile.TemporaryDirectory() as temp_config_dir:
        dump_file = osp.join(temp_config_dir, 'b.json')
        cfg.dump(dump_file)
        assert cfg.dump() == open(dump_file, 'r').read()
        assert Config.fromfile(dump_file)

    # test c.yaml
53
    cfg_file = osp.join(data_path, 'config/c.yaml')
54
55
56
57
58
59
60
61
62
63
    cfg = Config(cfg_dict, filename=cfg_file)
    assert isinstance(cfg, Config)
    assert cfg.filename == cfg_file
    assert cfg.text == open(cfg_file, 'r').read()
    assert cfg.dump() == yaml.dump(cfg_dict)
    with tempfile.TemporaryDirectory() as temp_config_dir:
        dump_file = osp.join(temp_config_dir, 'c.yaml')
        cfg.dump(dump_file)
        assert cfg.dump() == open(dump_file, 'r').read()
        assert Config.fromfile(dump_file)
Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
64

65
    # test h.py
66
    cfg_file = osp.join(data_path, 'config/h.py')
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
    cfg_dict = dict(
        item1='h.py',
        item2=f'{osp.dirname(__file__)}/data/config',
        item3='abc_h')
    cfg = Config(cfg_dict, filename=cfg_file)
    assert isinstance(cfg, Config)
    assert cfg.filename == cfg_file
    assert cfg.text == open(cfg_file, 'r').read()
    assert cfg.dump() == cfg.pretty_text
    with tempfile.TemporaryDirectory() as temp_config_dir:
        dump_file = osp.join(temp_config_dir, 'h.py')
        cfg.dump(dump_file)
        assert cfg.dump() == open(dump_file, 'r').read()
        assert Config.fromfile(dump_file)
        assert Config.fromfile(dump_file)['item1'] == cfg_dict['item1']
        assert Config.fromfile(dump_file)['item2'] == cfg_dict['item2']
        assert Config.fromfile(dump_file)['item3'] == cfg_dict['item3']

    # test no use_predefined_variable
    cfg_dict = dict(
        item1='{{fileBasename}}',
        item2='{{ fileDirname}}',
        item3='abc_{{ fileBasenameNoExtension }}')
    assert Config.fromfile(cfg_file, False)
    assert Config.fromfile(cfg_file, False)['item1'] == cfg_dict['item1']
    assert Config.fromfile(cfg_file, False)['item2'] == cfg_dict['item2']
    assert Config.fromfile(cfg_file, False)['item3'] == cfg_dict['item3']

    # test p.yaml
96
    cfg_file = osp.join(data_path, 'config/p.yaml')
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
    cfg_dict = dict(item1=f'{osp.dirname(__file__)}/data/config')
    cfg = Config(cfg_dict, filename=cfg_file)
    assert isinstance(cfg, Config)
    assert cfg.filename == cfg_file
    assert cfg.text == open(cfg_file, 'r').read()
    assert cfg.dump() == yaml.dump(cfg_dict)
    with tempfile.TemporaryDirectory() as temp_config_dir:
        dump_file = osp.join(temp_config_dir, 'p.yaml')
        cfg.dump(dump_file)
        assert cfg.dump() == open(dump_file, 'r').read()
        assert Config.fromfile(dump_file)
        assert Config.fromfile(dump_file)['item1'] == cfg_dict['item1']

    # test no use_predefined_variable
    assert Config.fromfile(cfg_file, False)
    assert Config.fromfile(cfg_file, False)['item1'] == '{{ fileDirname }}'

    # test o.json
115
    cfg_file = osp.join(data_path, 'config/o.json')
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
    cfg_dict = dict(item1=f'{osp.dirname(__file__)}/data/config')
    cfg = Config(cfg_dict, filename=cfg_file)
    assert isinstance(cfg, Config)
    assert cfg.filename == cfg_file
    assert cfg.text == open(cfg_file, 'r').read()
    assert cfg.dump() == json.dumps(cfg_dict)
    with tempfile.TemporaryDirectory() as temp_config_dir:
        dump_file = osp.join(temp_config_dir, 'o.json')
        cfg.dump(dump_file)
        assert cfg.dump() == open(dump_file, 'r').read()
        assert Config.fromfile(dump_file)
        assert Config.fromfile(dump_file)['item1'] == cfg_dict['item1']

    # test no use_predefined_variable
    assert Config.fromfile(cfg_file, False)
    assert Config.fromfile(cfg_file, False)['item1'] == '{{ fileDirname }}'

Kai Chen's avatar
Kai Chen committed
133
134

def test_fromfile():
lizz's avatar
lizz committed
135
    for filename in ['a.py', 'a.b.py', 'b.json', 'c.yaml']:
136
        cfg_file = osp.join(data_path, 'config', filename)
Kai Chen's avatar
Kai Chen committed
137
138
139
        cfg = Config.fromfile(cfg_file)
        assert isinstance(cfg, Config)
        assert cfg.filename == cfg_file
Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
140
141
        assert cfg.text == osp.abspath(osp.expanduser(cfg_file)) + '\n' + \
            open(cfg_file, 'r').read()
Kai Chen's avatar
Kai Chen committed
142

143
144
    with pytest.raises(FileNotFoundError):
        Config.fromfile('no_such_file.py')
Kai Chen's avatar
Kai Chen committed
145
    with pytest.raises(IOError):
146
        Config.fromfile(osp.join(data_path, 'color.jpg'))
Kai Chen's avatar
Kai Chen committed
147
148


Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
149
def test_merge_from_base():
150
    cfg_file = osp.join(data_path, 'config/d.py')
Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
151
152
153
    cfg = Config.fromfile(cfg_file)
    assert isinstance(cfg, Config)
    assert cfg.filename == cfg_file
154
    base_cfg_file = osp.join(data_path, 'config/base.py')
Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
155
156
157
158
159
160
161
162
163
164
165
    merge_text = osp.abspath(osp.expanduser(base_cfg_file)) + '\n' + \
        open(base_cfg_file, 'r').read()
    merge_text += '\n' + osp.abspath(osp.expanduser(cfg_file)) + '\n' + \
                  open(cfg_file, 'r').read()
    assert cfg.text == merge_text
    assert cfg.item1 == [2, 3]
    assert cfg.item2.a == 1
    assert cfg.item3 is False
    assert cfg.item4 == 'test_base'

    with pytest.raises(TypeError):
166
        Config.fromfile(osp.join(data_path, 'config/e.py'))
Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
167
168
169


def test_merge_from_multiple_bases():
170
    cfg_file = osp.join(data_path, 'config/l.py')
Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
171
172
173
174
175
176
177
178
    cfg = Config.fromfile(cfg_file)
    assert isinstance(cfg, Config)
    assert cfg.filename == cfg_file
    # cfg.field
    assert cfg.item1 == [1, 2]
    assert cfg.item2.a == 0
    assert cfg.item3 is False
    assert cfg.item4 == 'test'
Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
179
180
181
    assert cfg.item5 == dict(a=0, b=1)
    assert cfg.item6 == [dict(a=0), dict(b=1)]
    assert cfg.item7 == dict(a=[0, 1, 2], b=dict(c=[3.1, 4.2, 5.3]))
Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
182
183

    with pytest.raises(KeyError):
184
        Config.fromfile(osp.join(data_path, 'config/m.py'))
Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
185
186
187


def test_merge_recursive_bases():
188
    cfg_file = osp.join(data_path, 'config/f.py')
Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
189
190
191
192
193
194
195
196
197
198
199
    cfg = Config.fromfile(cfg_file)
    assert isinstance(cfg, Config)
    assert cfg.filename == cfg_file
    # cfg.field
    assert cfg.item1 == [2, 3]
    assert cfg.item2.a == 1
    assert cfg.item3 is False
    assert cfg.item4 == 'test_recursive_bases'


def test_merge_from_dict():
200
    cfg_file = osp.join(data_path, 'config/a.py')
Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
201
    cfg = Config.fromfile(cfg_file)
202
    input_options = {'item2.a': 1, 'item2.b': 0.1, 'item3': False}
Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
203
    cfg.merge_from_dict(input_options)
204
    assert cfg.item2 == dict(a=1, b=0.1)
Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
205
206
207
208
    assert cfg.item3 is False


def test_merge_delete():
209
    cfg_file = osp.join(data_path, 'config/delete.py')
Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
210
211
212
213
214
215
216
217
218
    cfg = Config.fromfile(cfg_file)
    # cfg.field
    assert cfg.item1 == [1, 2]
    assert cfg.item2 == dict(b=0)
    assert cfg.item3 is True
    assert cfg.item4 == 'test'
    assert '_delete_' not in cfg.item2


219
220
def test_merge_intermediate_variable():

221
    cfg_file = osp.join(data_path, 'config/i_child.py')
222
223
224
225
226
227
228
229
230
231
232
    cfg = Config.fromfile(cfg_file)
    # cfg.field
    assert cfg.item1 == [1, 2]
    assert cfg.item2 == dict(a=0)
    assert cfg.item3 is True
    assert cfg.item4 == 'test'
    assert cfg.item_cfg == dict(b=2)
    assert cfg.item5 == dict(cfg=dict(b=1))
    assert cfg.item6 == dict(cfg=dict(b=2))


233
def test_fromfile_in_config():
234
    cfg_file = osp.join(data_path, 'config/code.py')
235
236
237
238
239
240
241
242
243
    cfg = Config.fromfile(cfg_file)
    # cfg.field
    assert cfg.cfg.item1 == [1, 2]
    assert cfg.cfg.item2 == dict(a=0)
    assert cfg.cfg.item3 is True
    assert cfg.cfg.item4 == 'test'
    assert cfg.item5 == 1


Kai Chen's avatar
Kai Chen committed
244
245
246
247
def test_dict():
    cfg_dict = dict(item1=[1, 2], item2=dict(a=0), item3=True, item4='test')

    for filename in ['a.py', 'b.json', 'c.yaml']:
248
        cfg_file = osp.join(data_path, 'config', filename)
Kai Chen's avatar
Kai Chen committed
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
        cfg = Config.fromfile(cfg_file)

        # len(cfg)
        assert len(cfg) == 4
        # cfg.keys()
        assert set(cfg.keys()) == set(cfg_dict.keys())
        assert set(cfg._cfg_dict.keys()) == set(cfg_dict.keys())
        # cfg.values()
        for value in cfg.values():
            assert value in cfg_dict.values()
        # cfg.items()
        for name, value in cfg.items():
            assert name in cfg_dict
            assert value in cfg_dict.values()
        # cfg.field
        assert cfg.item1 == cfg_dict['item1']
        assert cfg.item2 == cfg_dict['item2']
        assert cfg.item2.a == 0
        assert cfg.item3 == cfg_dict['item3']
        assert cfg.item4 == cfg_dict['item4']
269
270
        with pytest.raises(AttributeError):
            cfg.not_exist
Kai Chen's avatar
Kai Chen committed
271
272
273
274
275
        # field in cfg, cfg[field], cfg.get()
        for name in ['item1', 'item2', 'item3', 'item4']:
            assert name in cfg
            assert cfg[name] == cfg_dict[name]
            assert cfg.get(name) == cfg_dict[name]
276
            assert cfg.get('not_exist') is None
Kai Chen's avatar
Kai Chen committed
277
            assert cfg.get('not_exist', 0) == 0
278
279
280
            with pytest.raises(KeyError):
                cfg['not_exist']
        assert 'item1' in cfg
Kai Chen's avatar
Kai Chen committed
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
        assert 'not_exist' not in cfg
        # cfg.update()
        cfg.update(dict(item1=0))
        assert cfg.item1 == 0
        cfg.update(dict(item2=dict(a=1)))
        assert cfg.item2.a == 1


def test_setattr():
    cfg = Config()
    cfg.item1 = [1, 2]
    cfg.item2 = {'a': 0}
    cfg['item5'] = {'a': {'b': None}}
    assert cfg._cfg_dict['item1'] == [1, 2]
    assert cfg.item1 == [1, 2]
    assert cfg._cfg_dict['item2'] == {'a': 0}
    assert cfg.item2.a == 0
    assert cfg._cfg_dict['item5'] == {'a': {'b': None}}
    assert cfg.item5.a.b is None
Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
300
301
302


def test_pretty_text():
303
    cfg_file = osp.join(data_path, 'config/l.py')
Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
304
305
306
307
308
309
310
    cfg = Config.fromfile(cfg_file)
    with tempfile.TemporaryDirectory() as temp_config_dir:
        text_cfg_filename = osp.join(temp_config_dir, '_text_config.py')
        with open(text_cfg_filename, 'w') as f:
            f.write(cfg.pretty_text)
        text_cfg = Config.fromfile(text_cfg_filename)
    assert text_cfg._cfg_dict == cfg._cfg_dict
311
312
313
314
315
316
317
318
319
320
321


def test_dict_action():
    parser = argparse.ArgumentParser(description='Train a detector')
    parser.add_argument(
        '--options', nargs='+', action=DictAction, help='custom options')
    args = parser.parse_args(
        ['--options', 'item2.a=1', 'item2.b=0.1', 'item2.c=x', 'item3=false'])
    out_dict = {'item2.a': 1, 'item2.b': 0.1, 'item2.c': 'x', 'item3': False}
    assert args.options == out_dict

322
    cfg_file = osp.join(data_path, 'config/a.py')
323
324
325
326
    cfg = Config.fromfile(cfg_file)
    cfg.merge_from_dict(args.options)
    assert cfg.item2 == dict(a=1, b=0.1, c='x')
    assert cfg.item3 is False
327
328
329


def test_dump_mapping():
330
    cfg_file = osp.join(data_path, 'config/n.py')
331
332
333
334
335
336
337
338
    cfg = Config.fromfile(cfg_file)

    with tempfile.TemporaryDirectory() as temp_config_dir:
        text_cfg_filename = osp.join(temp_config_dir, '_text_config.py')
        cfg.dump(text_cfg_filename)
        text_cfg = Config.fromfile(text_cfg_filename)

    assert text_cfg._cfg_dict == cfg._cfg_dict
339
340
341


def test_reserved_key():
342
    cfg_file = osp.join(data_path, 'config/g.py')
343
344
    with pytest.raises(KeyError):
        Config.fromfile(cfg_file)
345
346
347
348
349
350
351
352
353
354
355
356
357
358


def test_syntax_error():
    temp_cfg_file = tempfile.NamedTemporaryFile(suffix='.py')
    temp_cfg_path = temp_cfg_file.name
    # write a file with syntax error
    with open(temp_cfg_path, 'w') as f:
        f.write('a=0b=dict(c=1)')
    with pytest.raises(
            SyntaxError,
            match='There are syntax errors in config '
            f'file {temp_cfg_path}'):
        Config.fromfile(temp_cfg_path)
    temp_cfg_file.close()
Kevin's avatar
Kevin committed
359
360
361


def test_pickle_support():
362
    cfg_file = osp.join(data_path, 'config/n.py')
Kevin's avatar
Kevin committed
363
364
365
366
367
368
369
370
    cfg = Config.fromfile(cfg_file)

    with tempfile.TemporaryDirectory() as temp_config_dir:
        pkl_cfg_filename = osp.join(temp_config_dir, '_pickle.pkl')
        dump(cfg, pkl_cfg_filename)
        pkl_cfg = load(pkl_cfg_filename)

    assert pkl_cfg._cfg_dict == cfg._cfg_dict