|
1
|
|
|
#!/usr/bin/env python |
|
2
|
|
|
# coding=utf-8 |
|
3
|
|
|
from __future__ import division, print_function, unicode_literals |
|
4
|
|
|
|
|
5
|
|
|
import json |
|
6
|
|
|
|
|
7
|
|
|
import sacred.optional as opt |
|
8
|
|
|
import six |
|
9
|
|
|
from sacred.config.custom_containers import DogmaticDict, DogmaticList |
|
10
|
|
|
from sacred.utils import PYTHON_IDENTIFIER |
|
11
|
|
|
|
|
12
|
|
|
|
|
13
|
|
|
def assert_is_valid_key(key): |
|
14
|
|
|
if not isinstance(key, six.string_types): |
|
15
|
|
|
raise KeyError('Invalid key "{}". Config-keys have to be strings, ' |
|
16
|
|
|
'but was {}'.format(key, type(key))) |
|
17
|
|
|
elif key.find('.') > -1 or key.find('$') > -1: |
|
18
|
|
|
raise KeyError('Invalid key "{}". Config-keys cannot ' |
|
19
|
|
|
'contain "." or "$"'.format(key)) |
|
20
|
|
|
elif not PYTHON_IDENTIFIER.match(key): |
|
21
|
|
|
raise KeyError('Key "{}" is not a valid python identifier'.format(key)) |
|
22
|
|
|
|
|
23
|
|
|
|
|
24
|
|
|
def normalize_numpy(obj): |
|
25
|
|
|
if isinstance(obj, opt.np.generic): |
|
26
|
|
|
try: |
|
27
|
|
|
return opt.np.asscalar(obj) |
|
28
|
|
|
except ValueError: |
|
29
|
|
|
pass |
|
30
|
|
|
elif isinstance(obj, opt.np.ndarray): |
|
31
|
|
|
try: |
|
32
|
|
|
return obj.tolist() |
|
33
|
|
|
except (AttributeError, ValueError): |
|
34
|
|
|
pass |
|
35
|
|
|
return obj |
|
36
|
|
|
|
|
37
|
|
|
|
|
38
|
|
|
def normalize_or_die(obj): |
|
39
|
|
|
if isinstance(obj, dict): |
|
40
|
|
|
res = dict() |
|
41
|
|
|
for key, value in obj.items(): |
|
42
|
|
|
assert_is_valid_key(key) |
|
43
|
|
|
res[key] = normalize_or_die(value) |
|
44
|
|
|
return res |
|
45
|
|
|
elif isinstance(obj, (list, tuple)): |
|
46
|
|
|
return list([normalize_or_die(value) for value in obj]) |
|
47
|
|
|
elif opt.has_numpy: |
|
48
|
|
|
obj = normalize_numpy(obj) |
|
49
|
|
|
try: |
|
50
|
|
|
json.dumps(obj) |
|
51
|
|
|
return obj |
|
52
|
|
|
except TypeError: |
|
53
|
|
|
raise ValueError("Invalid value '{}'. All values have to be" |
|
54
|
|
|
"JSON-serializeable".format(obj)) |
|
55
|
|
|
|
|
56
|
|
|
|
|
57
|
|
|
def recursive_fill_in(config, preset): |
|
58
|
|
|
for key in preset: |
|
59
|
|
|
if key not in config: |
|
60
|
|
|
config[key] = preset[key] |
|
61
|
|
|
elif isinstance(config[key], dict): |
|
62
|
|
|
recursive_fill_in(config[key], preset[key]) |
|
63
|
|
|
|
|
64
|
|
|
|
|
65
|
|
|
def chain_evaluate_config_scopes(config_scopes, fixed=None, preset=None, |
|
66
|
|
|
fallback=None): |
|
67
|
|
|
fixed = fixed or {} |
|
68
|
|
|
fallback = fallback or {} |
|
69
|
|
|
final_config = dict(preset or {}) |
|
70
|
|
|
config_summaries = [] |
|
71
|
|
|
for config in config_scopes: |
|
72
|
|
|
cfg = config(fixed=fixed, |
|
73
|
|
|
preset=final_config, |
|
74
|
|
|
fallback=fallback) |
|
75
|
|
|
config_summaries.append(cfg) |
|
76
|
|
|
final_config.update(cfg) |
|
77
|
|
|
|
|
78
|
|
|
if not config_scopes: |
|
79
|
|
|
final_config.update(fixed) |
|
80
|
|
|
|
|
81
|
|
|
return undogmatize(final_config), config_summaries |
|
82
|
|
|
|
|
83
|
|
|
|
|
84
|
|
|
def dogmatize(obj): |
|
|
|
|
|
|
85
|
|
|
if isinstance(obj, dict): |
|
86
|
|
|
return DogmaticDict({key: dogmatize(val) for key, val in obj.items()}) |
|
87
|
|
|
elif isinstance(obj, list): |
|
88
|
|
|
return DogmaticList([dogmatize(value) for value in obj]) |
|
89
|
|
|
elif isinstance(obj, tuple): |
|
90
|
|
|
return tuple(dogmatize(value) for value in obj) |
|
91
|
|
|
else: |
|
92
|
|
|
return obj |
|
93
|
|
|
|
|
94
|
|
|
|
|
95
|
|
|
def undogmatize(obj): |
|
|
|
|
|
|
96
|
|
|
if isinstance(obj, DogmaticDict): |
|
97
|
|
|
return dict({key: undogmatize(value) for key, value in obj.items()}) |
|
98
|
|
|
elif isinstance(obj, DogmaticList): |
|
99
|
|
|
return list([undogmatize(value) for value in obj]) |
|
100
|
|
|
elif isinstance(obj, tuple): |
|
101
|
|
|
return tuple(undogmatize(value) for value in obj) |
|
102
|
|
|
else: |
|
103
|
|
|
return obj |
|
104
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.