|
1
|
|
|
"""Module level configuration. |
|
2
|
|
|
|
|
3
|
|
|
Fuel allows module-wide configuration values to be set using a YAML_ |
|
4
|
|
|
configuration file and `environment variables`_. Environment variables |
|
5
|
|
|
override the configuration file which in its turn overrides the defaults. |
|
6
|
|
|
|
|
7
|
|
|
The configuration is read from ``~/.fuelrc`` if it exists. A custom |
|
8
|
|
|
configuration file can be used by setting the ``FUEL_CONFIG`` environment |
|
9
|
|
|
variable. A configuration file is of the form: |
|
10
|
|
|
|
|
11
|
|
|
.. code-block:: yaml |
|
12
|
|
|
|
|
13
|
|
|
data_path: /home/user/datasets |
|
14
|
|
|
|
|
15
|
|
|
Which could be overwritten by using environment variables: |
|
16
|
|
|
|
|
17
|
|
|
.. code-block:: bash |
|
18
|
|
|
|
|
19
|
|
|
$ FUEL_DATA_PATH=/home/users/other_datasets python |
|
20
|
|
|
|
|
21
|
|
|
This data path is a sequence of paths separated by an os-specific |
|
22
|
|
|
delimiter (':' for Linux and OSX, ';' for Windows). |
|
23
|
|
|
|
|
24
|
|
|
If a setting is not configured and does not provide a default, a |
|
25
|
|
|
:class:`~.ConfigurationError` is raised when it is |
|
26
|
|
|
accessed. |
|
27
|
|
|
|
|
28
|
|
|
Configuration values can be accessed as attributes of |
|
29
|
|
|
:const:`fuel.config`. |
|
30
|
|
|
|
|
31
|
|
|
>>> from fuel import config |
|
32
|
|
|
>>> print(config.data_path) # doctest: +SKIP |
|
33
|
|
|
'~/datasets' |
|
34
|
|
|
|
|
35
|
|
|
The following configurations are supported: |
|
36
|
|
|
|
|
37
|
|
|
.. option:: data_path |
|
38
|
|
|
|
|
39
|
|
|
The path where dataset files are stored. Can also be set using the |
|
40
|
|
|
environment variable ``FUEL_DATA_PATH``. Expected to be a sequence |
|
41
|
|
|
of paths separated by an os-specific delimiter (':' for Linux and |
|
42
|
|
|
OSX, ';' for Windows). |
|
43
|
|
|
|
|
44
|
|
|
|
|
45
|
|
|
.. todo:: |
|
46
|
|
|
|
|
47
|
|
|
Implement this. |
|
48
|
|
|
|
|
49
|
|
|
.. option:: floatX |
|
50
|
|
|
|
|
51
|
|
|
The default :class:`~numpy.dtype` to use for floating point numbers. The |
|
52
|
|
|
default value is ``float64``. A lower value can save memory. |
|
53
|
|
|
|
|
54
|
|
|
.. option:: extra_downloaders |
|
55
|
|
|
|
|
56
|
|
|
A list of package names which, like fuel.downloaders, define an |
|
57
|
|
|
`all_downloaders` attribute listing available downloaders. By default, |
|
58
|
|
|
an empty list. |
|
59
|
|
|
|
|
60
|
|
|
.. option:: extra_converters |
|
61
|
|
|
|
|
62
|
|
|
A list of package names which, like fuel.converters, define an |
|
63
|
|
|
`all_converters` attribute listing available converters. By default, |
|
64
|
|
|
an empty list. |
|
65
|
|
|
|
|
66
|
|
|
.. _YAML: http://yaml.org/ |
|
67
|
|
|
.. _environment variables: |
|
68
|
|
|
https://en.wikipedia.org/wiki/Environment_variable |
|
69
|
|
|
|
|
70
|
|
|
""" |
|
71
|
|
|
import logging |
|
72
|
|
|
import os |
|
73
|
|
|
|
|
74
|
|
|
import six |
|
75
|
|
|
import yaml |
|
76
|
|
|
|
|
77
|
|
|
from .exceptions import ConfigurationError |
|
78
|
|
|
|
|
79
|
|
|
logger = logging.getLogger(__name__) |
|
80
|
|
|
|
|
81
|
|
|
NOT_SET = object() |
|
82
|
|
|
|
|
83
|
|
|
|
|
84
|
|
|
def extra_downloader_converter(value): |
|
85
|
|
|
"""Parses extra_{downloader,converter} arguments. |
|
86
|
|
|
|
|
87
|
|
|
Parameters |
|
88
|
|
|
---------- |
|
89
|
|
|
value : iterable or str |
|
90
|
|
|
If the value is a string, it is split into a list using spaces |
|
91
|
|
|
as delimiters. Otherwise, it is returned as is. |
|
92
|
|
|
|
|
93
|
|
|
""" |
|
94
|
|
|
if isinstance(value, six.string_types): |
|
95
|
|
|
value = value.split(" ") |
|
96
|
|
|
return value |
|
97
|
|
|
|
|
98
|
|
|
|
|
99
|
|
|
def multiple_paths_parser(value): |
|
100
|
|
|
"""Parses data_path argument. |
|
101
|
|
|
|
|
102
|
|
|
Parameters |
|
103
|
|
|
---------- |
|
104
|
|
|
value : str |
|
105
|
|
|
a string of data paths separated by ":". |
|
106
|
|
|
|
|
107
|
|
|
Returns |
|
108
|
|
|
------- |
|
109
|
|
|
value : list |
|
110
|
|
|
a list of strings indicating each data paths. |
|
111
|
|
|
|
|
112
|
|
|
""" |
|
113
|
|
|
if isinstance(value, six.string_types): |
|
114
|
|
|
value = value.split(os.path.pathsep) |
|
115
|
|
|
return value |
|
116
|
|
|
|
|
117
|
|
|
|
|
118
|
|
|
class Configuration(object): |
|
119
|
|
|
def __init__(self): |
|
120
|
|
|
self.config = {} |
|
121
|
|
|
|
|
122
|
|
|
def load_yaml(self): |
|
123
|
|
|
if 'FUEL_CONFIG' in os.environ: |
|
124
|
|
|
yaml_file = os.environ['FUEL_CONFIG'] |
|
125
|
|
|
else: |
|
126
|
|
|
yaml_file = os.path.expanduser('~/.fuelrc') |
|
127
|
|
|
if os.path.isfile(yaml_file): |
|
128
|
|
|
with open(yaml_file) as f: |
|
129
|
|
|
for key, value in yaml.safe_load(f).items(): |
|
130
|
|
|
if key not in self.config: |
|
131
|
|
|
raise ValueError("Unrecognized config in YAML: {}" |
|
132
|
|
|
.format(key)) |
|
133
|
|
|
self.config[key]['yaml'] = value |
|
134
|
|
|
|
|
135
|
|
|
def __getattr__(self, key): |
|
136
|
|
|
if key == 'config' or key not in self.config: |
|
137
|
|
|
raise AttributeError |
|
138
|
|
|
config_setting = self.config[key] |
|
139
|
|
|
if 'value' in config_setting: |
|
140
|
|
|
value = config_setting['value'] |
|
141
|
|
|
elif ('env_var' in config_setting and |
|
142
|
|
|
config_setting['env_var'] in os.environ): |
|
143
|
|
|
value = os.environ[config_setting['env_var']] |
|
144
|
|
|
elif 'yaml' in config_setting: |
|
145
|
|
|
value = config_setting['yaml'] |
|
146
|
|
|
elif 'default' in config_setting: |
|
147
|
|
|
value = config_setting['default'] |
|
148
|
|
|
else: |
|
149
|
|
|
raise ConfigurationError("Configuration not set and no default " |
|
150
|
|
|
"provided: {}.".format(key)) |
|
151
|
|
|
return config_setting['type'](value) |
|
152
|
|
|
|
|
153
|
|
|
def __setattr__(self, key, value): |
|
154
|
|
|
if key != 'config' and key in self.config: |
|
155
|
|
|
self.config[key]['value'] = value |
|
156
|
|
|
else: |
|
157
|
|
|
super(Configuration, self).__setattr__(key, value) |
|
158
|
|
|
|
|
159
|
|
|
def add_config(self, key, type_, default=NOT_SET, env_var=None): |
|
160
|
|
|
"""Add a configuration setting. |
|
161
|
|
|
|
|
162
|
|
|
Parameters |
|
163
|
|
|
---------- |
|
164
|
|
|
key : str |
|
165
|
|
|
The name of the configuration setting. This must be a valid |
|
166
|
|
|
Python attribute name i.e. alphanumeric with underscores. |
|
167
|
|
|
type : function |
|
168
|
|
|
A function such as ``float``, ``int`` or ``str`` which takes |
|
169
|
|
|
the configuration value and returns an object of the correct |
|
170
|
|
|
type. Note that the values retrieved from environment |
|
171
|
|
|
variables are always strings, while those retrieved from the |
|
172
|
|
|
YAML file might already be parsed. Hence, the function provided |
|
173
|
|
|
here must accept both types of input. |
|
174
|
|
|
default : object, optional |
|
175
|
|
|
The default configuration to return if not set. By default none |
|
176
|
|
|
is set and an error is raised instead. |
|
177
|
|
|
env_var : str, optional |
|
178
|
|
|
The environment variable name that holds this configuration |
|
179
|
|
|
value. If not given, this configuration can only be set in the |
|
180
|
|
|
YAML configuration file. |
|
181
|
|
|
|
|
182
|
|
|
""" |
|
183
|
|
|
self.config[key] = {'type': type_} |
|
184
|
|
|
if env_var is not None: |
|
185
|
|
|
self.config[key]['env_var'] = env_var |
|
186
|
|
|
if default is not NOT_SET: |
|
187
|
|
|
self.config[key]['default'] = default |
|
188
|
|
|
|
|
189
|
|
|
config = Configuration() |
|
190
|
|
|
|
|
191
|
|
|
# Define configuration options |
|
192
|
|
|
config.add_config('data_path', type_=multiple_paths_parser, |
|
193
|
|
|
env_var='FUEL_DATA_PATH') |
|
194
|
|
|
config.add_config('default_seed', type_=int, default=1) |
|
195
|
|
|
config.add_config('extra_downloaders', type_=extra_downloader_converter, |
|
196
|
|
|
default=[], env_var='FUEL_EXTRA_DOWNLOADERS') |
|
197
|
|
|
config.add_config('extra_converters', type_=extra_downloader_converter, |
|
198
|
|
|
default=[], env_var='FUEL_EXTRA_CONVERTERS') |
|
199
|
|
|
|
|
200
|
|
|
# Default to Theano's floatX if possible |
|
201
|
|
|
try: |
|
202
|
|
|
from theano import config as theano_config |
|
203
|
|
|
default_floatX = theano_config.floatX |
|
|
|
|
|
|
204
|
|
|
except Exception: |
|
|
|
|
|
|
205
|
|
|
default_floatX = 'float64' |
|
|
|
|
|
|
206
|
|
|
config.add_config('floatX', type_=str, env_var='FUEL_FLOATX', |
|
207
|
|
|
default=default_floatX) |
|
208
|
|
|
|
|
209
|
|
|
config.load_yaml() |
|
210
|
|
|
|
This check looks for invalid names for a range of different identifiers.
You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.
If your project includes a Pylint configuration file, the settings contained in that file take precedence.
To find out more about Pylint, please refer to their site.