Mercurial > hg > configuration
annotate configuration/configuration.py @ 89:0804a706d6bf
handle CLI errors with optparse
author | Jeff Hammel <jhammel@mozilla.com> |
---|---|
date | Sat, 28 Apr 2012 15:29:57 -0700 |
parents | 36cf1d9bf40b |
children | 6bf4a58b0988 |
rev | line source |
---|---|
0 | 1 #!/usr/bin/env python |
2 | |
3 """ | |
66 | 4 unified configuration with serialization/deserialization |
0 | 5 """ |
6 | |
34
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
7 import copy |
37
a1f8dec4d4f9
we has another broken test
Jeff Hammel <jhammel@mozilla.com>
parents:
36
diff
changeset
|
8 import os |
0 | 9 import sys |
10 import optparse | |
11 | |
67 | 12 # imports for configuration providers |
4 | 13 try: |
14 import json | |
15 except ImportError: | |
16 try: | |
17 import simplejson as json | |
18 except ImportError: | |
19 json = None | |
5
7910b0ef0bab
stub configuration providers
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
20 try: |
7910b0ef0bab
stub configuration providers
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
21 import yaml |
7910b0ef0bab
stub configuration providers
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
22 except ImportError: |
7910b0ef0bab
stub configuration providers
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
23 yaml = None |
7910b0ef0bab
stub configuration providers
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
24 |
67 | 25 __all__ = ['Configuration', |
26 'configuration_providers', | |
27 'types', | |
28 'UnknownOptionException', | |
29 'MissingValueException', | |
30 'ConfigurationProviderException', | |
31 'TypeCastException', | |
32 'ConfigurationOption'] | |
36
d218df4d0b4c
add test for missing values
Jeff Hammel <jhammel@mozilla.com>
parents:
35
diff
changeset
|
33 |
d218df4d0b4c
add test for missing values
Jeff Hammel <jhammel@mozilla.com>
parents:
35
diff
changeset
|
34 ### exceptions |
d218df4d0b4c
add test for missing values
Jeff Hammel <jhammel@mozilla.com>
parents:
35
diff
changeset
|
35 |
67 | 36 class UnknownOptionException(Exception): |
37 """exception raised when a non-configuration value is present in the configuration""" | |
38 | |
36
d218df4d0b4c
add test for missing values
Jeff Hammel <jhammel@mozilla.com>
parents:
35
diff
changeset
|
39 class MissingValueException(Exception): |
d218df4d0b4c
add test for missing values
Jeff Hammel <jhammel@mozilla.com>
parents:
35
diff
changeset
|
40 """exception raised when a required value is missing""" |
6 | 41 |
41
1bd4ddf2e81d
deserialization should work now
Jeff Hammel <jhammel@mozilla.com>
parents:
38
diff
changeset
|
42 class ConfigurationProviderException(Exception): |
1bd4ddf2e81d
deserialization should work now
Jeff Hammel <jhammel@mozilla.com>
parents:
38
diff
changeset
|
43 """exception raised when a configuration provider is missing, etc""" |
1bd4ddf2e81d
deserialization should work now
Jeff Hammel <jhammel@mozilla.com>
parents:
38
diff
changeset
|
44 |
46 | 45 class TypeCastException(Exception): |
46 """exception raised when a configuration item cannot be coerced to a type""" | |
47 | |
67 | 48 |
26
4fd88b1b08d5
ABC-ing configuration providers
Jeff Hammel <jhammel@mozilla.com>
parents:
25
diff
changeset
|
49 ### configuration providers for serialization/deserialization |
4fd88b1b08d5
ABC-ing configuration providers
Jeff Hammel <jhammel@mozilla.com>
parents:
25
diff
changeset
|
50 |
5
7910b0ef0bab
stub configuration providers
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
51 configuration_providers = [] |
26
4fd88b1b08d5
ABC-ing configuration providers
Jeff Hammel <jhammel@mozilla.com>
parents:
25
diff
changeset
|
52 |
4fd88b1b08d5
ABC-ing configuration providers
Jeff Hammel <jhammel@mozilla.com>
parents:
25
diff
changeset
|
53 class ConfigurationProvider(object): |
4fd88b1b08d5
ABC-ing configuration providers
Jeff Hammel <jhammel@mozilla.com>
parents:
25
diff
changeset
|
54 """ |
4fd88b1b08d5
ABC-ing configuration providers
Jeff Hammel <jhammel@mozilla.com>
parents:
25
diff
changeset
|
55 abstract base class for configuration providers for |
4fd88b1b08d5
ABC-ing configuration providers
Jeff Hammel <jhammel@mozilla.com>
parents:
25
diff
changeset
|
56 serialization/deserialization |
4fd88b1b08d5
ABC-ing configuration providers
Jeff Hammel <jhammel@mozilla.com>
parents:
25
diff
changeset
|
57 """ |
27 | 58 def read(self, filename): |
59 raise NotImplementedError("Abstract base class") | |
60 | |
61 def write(self, config, filename): | |
62 if isinstance(filename, basestring): | |
63 f = file(filename, 'w') | |
64 newfile = True | |
65 else: | |
66 f = filename | |
67 newfile = False | |
68 try: | |
69 self._write(f, config) | |
70 finally: | |
71 # XXX try: finally: works in python >= 2.5 | |
72 if newfile: | |
73 f.close() | |
74 def _write(self, fp, config): | |
75 raise NotImplementedError("Abstract base class") | |
26
4fd88b1b08d5
ABC-ing configuration providers
Jeff Hammel <jhammel@mozilla.com>
parents:
25
diff
changeset
|
76 |
5
7910b0ef0bab
stub configuration providers
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
77 if json: |
38
8909ae1cc4ea
fix serialization (stub) tests
Jeff Hammel <jhammel@mozilla.com>
parents:
37
diff
changeset
|
78 class JSON(ConfigurationProvider): |
27 | 79 indent = 2 |
5
7910b0ef0bab
stub configuration providers
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
80 extensions = ['json'] |
7 | 81 def read(self, filename): |
9 | 82 return json.loads(file(filename).read()) |
27 | 83 def _write(self, fp, config): |
38
8909ae1cc4ea
fix serialization (stub) tests
Jeff Hammel <jhammel@mozilla.com>
parents:
37
diff
changeset
|
84 fp.write(json.dumps(config, indent=self.indent, sort_keys=True)) |
27 | 85 # TODO: could use templates to get order down, etc |
30
b27a7cb2dd5b
stub test for configuration providers
Jeff Hammel <jhammel@mozilla.com>
parents:
29
diff
changeset
|
86 configuration_providers.append(JSON()) |
5
7910b0ef0bab
stub configuration providers
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
87 |
7910b0ef0bab
stub configuration providers
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
88 if yaml: |
38
8909ae1cc4ea
fix serialization (stub) tests
Jeff Hammel <jhammel@mozilla.com>
parents:
37
diff
changeset
|
89 class YAML(ConfigurationProvider): |
30
b27a7cb2dd5b
stub test for configuration providers
Jeff Hammel <jhammel@mozilla.com>
parents:
29
diff
changeset
|
90 extensions = ['yml', 'yaml'] |
87
928654373755
change default flow style for yaml, http://pyyaml.org/wiki/PyYAMLDocumentation
Jeff Hammel <jhammel@mozilla.com>
parents:
86
diff
changeset
|
91 dump_args = {'default_flow_style': False} |
5
7910b0ef0bab
stub configuration providers
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
92 def read(self, filename): |
6 | 93 f = file(filename) |
94 config = yaml.load(f) | |
95 f.close() | |
96 return config | |
27 | 97 def _write(self, fp, config): |
87
928654373755
change default flow style for yaml, http://pyyaml.org/wiki/PyYAMLDocumentation
Jeff Hammel <jhammel@mozilla.com>
parents:
86
diff
changeset
|
98 fp.write(yaml.dump(config, **self.dump_args)) |
27 | 99 # TODO: could use templates to get order down, etc |
6 | 100 |
30
b27a7cb2dd5b
stub test for configuration providers
Jeff Hammel <jhammel@mozilla.com>
parents:
29
diff
changeset
|
101 configuration_providers.append(YAML()) |
b27a7cb2dd5b
stub test for configuration providers
Jeff Hammel <jhammel@mozilla.com>
parents:
29
diff
changeset
|
102 |
50
113e8c2f7cab
start to hook up deserializers
Jeff Hammel <jhammel@mozilla.com>
parents:
49
diff
changeset
|
103 # TODO: add a configuration provider for taking command-line arguments |
113e8c2f7cab
start to hook up deserializers
Jeff Hammel <jhammel@mozilla.com>
parents:
49
diff
changeset
|
104 # from a file |
113e8c2f7cab
start to hook up deserializers
Jeff Hammel <jhammel@mozilla.com>
parents:
49
diff
changeset
|
105 |
30
b27a7cb2dd5b
stub test for configuration providers
Jeff Hammel <jhammel@mozilla.com>
parents:
29
diff
changeset
|
106 __all__.extend([i.__class__.__name__ for i in configuration_providers]) |
4 | 107 |
44
b3db38b14567
stub adding an option of keeping track of what is parsed
Jeff Hammel <jhammel@mozilla.com>
parents:
43
diff
changeset
|
108 ### optparse interface |
b3db38b14567
stub adding an option of keeping track of what is parsed
Jeff Hammel <jhammel@mozilla.com>
parents:
43
diff
changeset
|
109 |
b3db38b14567
stub adding an option of keeping track of what is parsed
Jeff Hammel <jhammel@mozilla.com>
parents:
43
diff
changeset
|
110 class ConfigurationOption(optparse.Option): |
b3db38b14567
stub adding an option of keeping track of what is parsed
Jeff Hammel <jhammel@mozilla.com>
parents:
43
diff
changeset
|
111 """option that keeps track if it is seen""" |
b3db38b14567
stub adding an option of keeping track of what is parsed
Jeff Hammel <jhammel@mozilla.com>
parents:
43
diff
changeset
|
112 # TODO: this should be configurable or something |
b3db38b14567
stub adding an option of keeping track of what is parsed
Jeff Hammel <jhammel@mozilla.com>
parents:
43
diff
changeset
|
113 def take_action(self, action, dest, opt, value, values, parser): |
b3db38b14567
stub adding an option of keeping track of what is parsed
Jeff Hammel <jhammel@mozilla.com>
parents:
43
diff
changeset
|
114 optparse.Option.take_action(self, action, dest, opt, value, values, parser) |
82 | 115 |
116 # add the parsed option to the set of things parsed | |
44
b3db38b14567
stub adding an option of keeping track of what is parsed
Jeff Hammel <jhammel@mozilla.com>
parents:
43
diff
changeset
|
117 if not hasattr(parser, 'parsed'): |
b3db38b14567
stub adding an option of keeping track of what is parsed
Jeff Hammel <jhammel@mozilla.com>
parents:
43
diff
changeset
|
118 parser.parsed = set() |
b3db38b14567
stub adding an option of keeping track of what is parsed
Jeff Hammel <jhammel@mozilla.com>
parents:
43
diff
changeset
|
119 parser.parsed.add(dest) |
82 | 120 |
121 # switch on types | |
122 formatter = getattr(parser, 'cli_formatter') | |
123 if formatter: | |
124 formatter = formatter(dest) | |
125 setattr(values, dest, formatter(getattr(values, dest))) | |
44
b3db38b14567
stub adding an option of keeping track of what is parsed
Jeff Hammel <jhammel@mozilla.com>
parents:
43
diff
changeset
|
126 |
21
0fe74db6a56c
a hacky way to do CLI types handlers
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
127 ### plugins for option types |
0fe74db6a56c
a hacky way to do CLI types handlers
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
128 ### TODO: this could use a bit of thought |
31 | 129 ### They should probably be classes |
80
35416ad14098
notes to self about how to make this better; still needs a little thought
Jeff Hammel <jhammel@mozilla.com>
parents:
78
diff
changeset
|
130 # class Option(object): |
35416ad14098
notes to self about how to make this better; still needs a little thought
Jeff Hammel <jhammel@mozilla.com>
parents:
78
diff
changeset
|
131 # def arguments(self, name, value): |
35416ad14098
notes to self about how to make this better; still needs a little thought
Jeff Hammel <jhammel@mozilla.com>
parents:
78
diff
changeset
|
132 # """return arguments appropriate for construction of an optparse.Option |
35416ad14098
notes to self about how to make this better; still needs a little thought
Jeff Hammel <jhammel@mozilla.com>
parents:
78
diff
changeset
|
133 # def take_action(self, ...): |
35416ad14098
notes to self about how to make this better; still needs a little thought
Jeff Hammel <jhammel@mozilla.com>
parents:
78
diff
changeset
|
134 # """do something appropriate based on type""" |
35416ad14098
notes to self about how to make this better; still needs a little thought
Jeff Hammel <jhammel@mozilla.com>
parents:
78
diff
changeset
|
135 |
81
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
136 class BaseCLI(object): |
80
35416ad14098
notes to self about how to make this better; still needs a little thought
Jeff Hammel <jhammel@mozilla.com>
parents:
78
diff
changeset
|
137 """base_cli for all option types""" |
35416ad14098
notes to self about how to make this better; still needs a little thought
Jeff Hammel <jhammel@mozilla.com>
parents:
78
diff
changeset
|
138 |
81
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
139 def __call__(self, name, value): |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
140 """return args, kwargs needed to instantiate an optparse option""" |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
141 |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
142 args = value.get('flags', ['--%s' % name]) |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
143 if not args: |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
144 # No CLI interface |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
145 return (), {} |
21
0fe74db6a56c
a hacky way to do CLI types handlers
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
146 |
81
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
147 kw = {'dest': name} |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
148 help = value.get('help', name) |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
149 if 'default' in value: |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
150 kw['default'] = value['default'] |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
151 help += ' [DEFAULT: %s]' % value['default'] |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
152 kw['help'] = help |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
153 kw['action'] = 'store' |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
154 return args, kw |
21
0fe74db6a56c
a hacky way to do CLI types handlers
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
155 |
82 | 156 def take_action(self, value): |
157 return value | |
158 | |
81
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
159 class BoolCLI(BaseCLI): |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
160 |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
161 def __call__(self, name, value): |
21
0fe74db6a56c
a hacky way to do CLI types handlers
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
162 |
81
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
163 # preserve the default values |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
164 help = value.get('help') |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
165 flags = value.get('flags') |
23 | 166 |
81
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
167 args, kw = BaseCLI.__call__(self, name, value) |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
168 kw['help'] = help # reset |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
169 if value.get('default'): |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
170 kw['action'] = 'store_false' |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
171 if not flags: |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
172 args = ['--no-%s' % name] |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
173 if not help: |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
174 kw['help'] = 'disable %s' % name |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
175 else: |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
176 kw['action'] = 'store_true' |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
177 if not help: |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
178 kw['help'] = 'enable %s' % name |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
179 return args, kw |
21
0fe74db6a56c
a hacky way to do CLI types handlers
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
180 |
81
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
181 class ListCLI(BaseCLI): |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
182 |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
183 def __call__(self, name, value): |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
184 args, kw = BaseCLI.__call__(self, name, value) |
21
0fe74db6a56c
a hacky way to do CLI types handlers
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
185 |
81
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
186 # TODO: could use 'extend' |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
187 # - http://hg.mozilla.org/build/mozharness/file/5f44ba08f4be/mozharness/base/config.py#l41 |
21
0fe74db6a56c
a hacky way to do CLI types handlers
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
188 |
81
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
189 # TODO: what about nested types? |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
190 kw['action'] = 'append' |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
191 return args, kw |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
192 |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
193 class IntCLI(BaseCLI): |
21
0fe74db6a56c
a hacky way to do CLI types handlers
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
194 |
81
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
195 def __call__(self, name, value): |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
196 args, kw = BaseCLI.__call__(self, name, value) |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
197 kw['type'] = 'int' |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
198 return args, kw |
23 | 199 |
81
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
200 class FloatCLI(BaseCLI): |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
201 |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
202 def __call__(self, name, value): |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
203 args, kw = BaseCLI.__call__(self, name, value) |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
204 kw['type'] = 'float' |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
205 return args, kw |
23 | 206 |
82 | 207 class DictCLI(ListCLI): |
208 | |
209 delimeter = '=' | |
210 | |
211 def take_action(self, value): | |
212 bad = [i for i in value if self.delimeter not in i] | |
213 if bad: | |
214 raise AssertionError("Each value must be delimited by '%s': %s" % (self.delimeter, bad)) | |
215 return dict([i.split(self.delimeter, 1) for i in value]) | |
216 | |
60 | 217 # TODO: 'dict'-type cli interface |
218 | |
81
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
219 types = {bool: BoolCLI(), |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
220 int: IntCLI(), |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
221 float: FloatCLI(), |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
222 list: ListCLI(), |
82 | 223 dict: DictCLI(), |
88
36cf1d9bf40b
slightly improve type system
Jeff Hammel <jhammel@mozilla.com>
parents:
87
diff
changeset
|
224 str: BaseCLI(), |
81
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
225 None: BaseCLI()} # default |
82 | 226 |
81
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
227 __all__ += [i.__class__.__name__ for i in types.values()] |
4 | 228 |
59
b8f066b8ab62
begin migration path towards inheriting from ConfigParser; ideally, Configuration should live in its own class and the CLI class should inherit from that
Jeff Hammel <jhammel@mozilla.com>
parents:
54
diff
changeset
|
229 class Configuration(optparse.OptionParser): |
29
fadcc6ab51d4
more (de/)serialization stubbing
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
230 """declarative configuration object""" |
fadcc6ab51d4
more (de/)serialization stubbing
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
231 |
fadcc6ab51d4
more (de/)serialization stubbing
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
232 options = {} # configuration basis |
1 | 233 |
75
c119eb07a378
rename/shuffle options to make more sense
Jeff Hammel <jhammel@mozilla.com>
parents:
67
diff
changeset
|
234 def __init__(self, configuration_providers=configuration_providers, types=types, load=None, dump='--dump', **parser_args): |
61
ef2d1c6211b9
more stubbing to make Configuration an OptionParser
Jeff Hammel <jhammel@mozilla.com>
parents:
60
diff
changeset
|
235 |
84
34c13cde0255
move towards dict or items system
Jeff Hammel <jhammel@mozilla.com>
parents:
82
diff
changeset
|
236 # sanity check |
34c13cde0255
move towards dict or items system
Jeff Hammel <jhammel@mozilla.com>
parents:
82
diff
changeset
|
237 if isinstance(self.options, dict): |
34c13cde0255
move towards dict or items system
Jeff Hammel <jhammel@mozilla.com>
parents:
82
diff
changeset
|
238 self.option_dict = self.options |
34c13cde0255
move towards dict or items system
Jeff Hammel <jhammel@mozilla.com>
parents:
82
diff
changeset
|
239 elif isinstance(self.options, list): |
34c13cde0255
move towards dict or items system
Jeff Hammel <jhammel@mozilla.com>
parents:
82
diff
changeset
|
240 # XXX could also be tuple, etc |
34c13cde0255
move towards dict or items system
Jeff Hammel <jhammel@mozilla.com>
parents:
82
diff
changeset
|
241 self.option_dict = dict(self.options) |
34c13cde0255
move towards dict or items system
Jeff Hammel <jhammel@mozilla.com>
parents:
82
diff
changeset
|
242 else: |
34c13cde0255
move towards dict or items system
Jeff Hammel <jhammel@mozilla.com>
parents:
82
diff
changeset
|
243 raise NotImplementedError |
34c13cde0255
move towards dict or items system
Jeff Hammel <jhammel@mozilla.com>
parents:
82
diff
changeset
|
244 |
61
ef2d1c6211b9
more stubbing to make Configuration an OptionParser
Jeff Hammel <jhammel@mozilla.com>
parents:
60
diff
changeset
|
245 # setup configuration |
2 | 246 self.config = {} |
6 | 247 self.configuration_providers = configuration_providers |
21
0fe74db6a56c
a hacky way to do CLI types handlers
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
248 self.types = types |
61
ef2d1c6211b9
more stubbing to make Configuration an OptionParser
Jeff Hammel <jhammel@mozilla.com>
parents:
60
diff
changeset
|
249 |
ef2d1c6211b9
more stubbing to make Configuration an OptionParser
Jeff Hammel <jhammel@mozilla.com>
parents:
60
diff
changeset
|
250 # setup optionparser |
ef2d1c6211b9
more stubbing to make Configuration an OptionParser
Jeff Hammel <jhammel@mozilla.com>
parents:
60
diff
changeset
|
251 if 'description' not in parser_args: |
ef2d1c6211b9
more stubbing to make Configuration an OptionParser
Jeff Hammel <jhammel@mozilla.com>
parents:
60
diff
changeset
|
252 parser_args['description'] = getattr(self, '__doc__', '') |
ef2d1c6211b9
more stubbing to make Configuration an OptionParser
Jeff Hammel <jhammel@mozilla.com>
parents:
60
diff
changeset
|
253 if 'formatter' not in parser_args: |
ef2d1c6211b9
more stubbing to make Configuration an OptionParser
Jeff Hammel <jhammel@mozilla.com>
parents:
60
diff
changeset
|
254 class PlainDescriptionFormatter(optparse.IndentedHelpFormatter): |
ef2d1c6211b9
more stubbing to make Configuration an OptionParser
Jeff Hammel <jhammel@mozilla.com>
parents:
60
diff
changeset
|
255 """description formatter for console script entry point""" |
ef2d1c6211b9
more stubbing to make Configuration an OptionParser
Jeff Hammel <jhammel@mozilla.com>
parents:
60
diff
changeset
|
256 def format_description(self, description): |
ef2d1c6211b9
more stubbing to make Configuration an OptionParser
Jeff Hammel <jhammel@mozilla.com>
parents:
60
diff
changeset
|
257 if description: |
ef2d1c6211b9
more stubbing to make Configuration an OptionParser
Jeff Hammel <jhammel@mozilla.com>
parents:
60
diff
changeset
|
258 return description.strip() + '\n' |
ef2d1c6211b9
more stubbing to make Configuration an OptionParser
Jeff Hammel <jhammel@mozilla.com>
parents:
60
diff
changeset
|
259 else: |
ef2d1c6211b9
more stubbing to make Configuration an OptionParser
Jeff Hammel <jhammel@mozilla.com>
parents:
60
diff
changeset
|
260 return '' |
ef2d1c6211b9
more stubbing to make Configuration an OptionParser
Jeff Hammel <jhammel@mozilla.com>
parents:
60
diff
changeset
|
261 parser_args['formatter'] = PlainDescriptionFormatter() |
ef2d1c6211b9
more stubbing to make Configuration an OptionParser
Jeff Hammel <jhammel@mozilla.com>
parents:
60
diff
changeset
|
262 parser_args.setdefault('option_class', ConfigurationOption) |
59
b8f066b8ab62
begin migration path towards inheriting from ConfigParser; ideally, Configuration should live in its own class and the CLI class should inherit from that
Jeff Hammel <jhammel@mozilla.com>
parents:
54
diff
changeset
|
263 optparse.OptionParser.__init__(self, **parser_args) |
61
ef2d1c6211b9
more stubbing to make Configuration an OptionParser
Jeff Hammel <jhammel@mozilla.com>
parents:
60
diff
changeset
|
264 self.parsed = set() |
ef2d1c6211b9
more stubbing to make Configuration an OptionParser
Jeff Hammel <jhammel@mozilla.com>
parents:
60
diff
changeset
|
265 self.optparse_options(self) |
63 | 266 # add option(s) for configuration_providers |
75
c119eb07a378
rename/shuffle options to make more sense
Jeff Hammel <jhammel@mozilla.com>
parents:
67
diff
changeset
|
267 if load: |
c119eb07a378
rename/shuffle options to make more sense
Jeff Hammel <jhammel@mozilla.com>
parents:
67
diff
changeset
|
268 self.add_option(load, |
c119eb07a378
rename/shuffle options to make more sense
Jeff Hammel <jhammel@mozilla.com>
parents:
67
diff
changeset
|
269 dest='load', action='append', |
c119eb07a378
rename/shuffle options to make more sense
Jeff Hammel <jhammel@mozilla.com>
parents:
67
diff
changeset
|
270 help="load configuration from a file") |
63 | 271 |
272 # add an option for dumping | |
273 formats = self.formats() | |
274 if formats and dump: | |
275 self.add_option(dump, dest='dump', | |
276 help="dump configuration to a file; Formats: %s" % formats) | |
277 | |
2 | 278 |
29
fadcc6ab51d4
more (de/)serialization stubbing
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
279 ### methods for iteration |
67 | 280 ### TODO: make the class a real iterator |
29
fadcc6ab51d4
more (de/)serialization stubbing
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
281 |
11
e00afe2c83bf
stubbing configuration parser
Jeff Hammel <jhammel@mozilla.com>
parents:
10
diff
changeset
|
282 def items(self): |
e00afe2c83bf
stubbing configuration parser
Jeff Hammel <jhammel@mozilla.com>
parents:
10
diff
changeset
|
283 # TODO: allow options to be a list of 2-tuples |
84
34c13cde0255
move towards dict or items system
Jeff Hammel <jhammel@mozilla.com>
parents:
82
diff
changeset
|
284 if isinstance(self.options, dict): |
34c13cde0255
move towards dict or items system
Jeff Hammel <jhammel@mozilla.com>
parents:
82
diff
changeset
|
285 return self.options.items() |
34c13cde0255
move towards dict or items system
Jeff Hammel <jhammel@mozilla.com>
parents:
82
diff
changeset
|
286 return self.options |
11
e00afe2c83bf
stubbing configuration parser
Jeff Hammel <jhammel@mozilla.com>
parents:
10
diff
changeset
|
287 |
24
39f2611db9be
rename a bunch of things and begin to work on the sanity of validation
Jeff Hammel <jhammel@mozilla.com>
parents:
23
diff
changeset
|
288 ### methods for validating configuration |
2 | 289 |
24
39f2611db9be
rename a bunch of things and begin to work on the sanity of validation
Jeff Hammel <jhammel@mozilla.com>
parents:
23
diff
changeset
|
290 def check(self, config): |
39f2611db9be
rename a bunch of things and begin to work on the sanity of validation
Jeff Hammel <jhammel@mozilla.com>
parents:
23
diff
changeset
|
291 """ |
39f2611db9be
rename a bunch of things and begin to work on the sanity of validation
Jeff Hammel <jhammel@mozilla.com>
parents:
23
diff
changeset
|
292 check validity of configuration to be added |
39f2611db9be
rename a bunch of things and begin to work on the sanity of validation
Jeff Hammel <jhammel@mozilla.com>
parents:
23
diff
changeset
|
293 """ |
39f2611db9be
rename a bunch of things and begin to work on the sanity of validation
Jeff Hammel <jhammel@mozilla.com>
parents:
23
diff
changeset
|
294 |
39f2611db9be
rename a bunch of things and begin to work on the sanity of validation
Jeff Hammel <jhammel@mozilla.com>
parents:
23
diff
changeset
|
295 # ensure options in configuration are in self.options |
86 | 296 unknown_options = [i for i in config if i not in self.option_dict] |
24
39f2611db9be
rename a bunch of things and begin to work on the sanity of validation
Jeff Hammel <jhammel@mozilla.com>
parents:
23
diff
changeset
|
297 if unknown_options: |
67 | 298 raise UnknownOptionException("Unknown options: %s" % ', '.join(unknown_options)) |
6 | 299 |
67 | 300 # ensure options are of the right type (if specified) |
24
39f2611db9be
rename a bunch of things and begin to work on the sanity of validation
Jeff Hammel <jhammel@mozilla.com>
parents:
23
diff
changeset
|
301 for key, value in config.items(): |
86 | 302 _type = self.option_dict[key].get('type') |
303 if _type is None and 'default' in self.option_dict[key]: | |
304 _type = type(self.option_dict[key]['default']) | |
67 | 305 if _type is not None and not isinstance(value, _type): |
46 | 306 try: |
307 config[key] = _type(value) | |
308 except BaseException, e: | |
309 raise TypeCastException("Could not coerce %s, %s, to type %s: %s" % (key, value, _type.__name__, e)) | |
24
39f2611db9be
rename a bunch of things and begin to work on the sanity of validation
Jeff Hammel <jhammel@mozilla.com>
parents:
23
diff
changeset
|
310 |
39f2611db9be
rename a bunch of things and begin to work on the sanity of validation
Jeff Hammel <jhammel@mozilla.com>
parents:
23
diff
changeset
|
311 return config |
39f2611db9be
rename a bunch of things and begin to work on the sanity of validation
Jeff Hammel <jhammel@mozilla.com>
parents:
23
diff
changeset
|
312 |
39f2611db9be
rename a bunch of things and begin to work on the sanity of validation
Jeff Hammel <jhammel@mozilla.com>
parents:
23
diff
changeset
|
313 def validate(self): |
39f2611db9be
rename a bunch of things and begin to work on the sanity of validation
Jeff Hammel <jhammel@mozilla.com>
parents:
23
diff
changeset
|
314 """validate resultant configuration""" |
67 | 315 |
78 | 316 for key, value in self.items(): |
35
321fe58a9eae
flush out validate function
Jeff Hammel <jhammel@mozilla.com>
parents:
34
diff
changeset
|
317 if key not in self.config: |
321fe58a9eae
flush out validate function
Jeff Hammel <jhammel@mozilla.com>
parents:
34
diff
changeset
|
318 required = value.get('required') |
321fe58a9eae
flush out validate function
Jeff Hammel <jhammel@mozilla.com>
parents:
34
diff
changeset
|
319 if required: |
321fe58a9eae
flush out validate function
Jeff Hammel <jhammel@mozilla.com>
parents:
34
diff
changeset
|
320 if isinstance(required, basestring): |
321fe58a9eae
flush out validate function
Jeff Hammel <jhammel@mozilla.com>
parents:
34
diff
changeset
|
321 required_message = required |
321fe58a9eae
flush out validate function
Jeff Hammel <jhammel@mozilla.com>
parents:
34
diff
changeset
|
322 else: |
321fe58a9eae
flush out validate function
Jeff Hammel <jhammel@mozilla.com>
parents:
34
diff
changeset
|
323 required_message = "Parameter %s is required but not present" % key |
67 | 324 # TODO: this should probably raise all missing values vs |
37
a1f8dec4d4f9
we has another broken test
Jeff Hammel <jhammel@mozilla.com>
parents:
36
diff
changeset
|
325 # one by one |
36
d218df4d0b4c
add test for missing values
Jeff Hammel <jhammel@mozilla.com>
parents:
35
diff
changeset
|
326 raise MissingValueException(required_message) |
24
39f2611db9be
rename a bunch of things and begin to work on the sanity of validation
Jeff Hammel <jhammel@mozilla.com>
parents:
23
diff
changeset
|
327 # TODO: configuration should be locked after this is called |
39f2611db9be
rename a bunch of things and begin to work on the sanity of validation
Jeff Hammel <jhammel@mozilla.com>
parents:
23
diff
changeset
|
328 |
39f2611db9be
rename a bunch of things and begin to work on the sanity of validation
Jeff Hammel <jhammel@mozilla.com>
parents:
23
diff
changeset
|
329 ### methods for adding configuration |
6 | 330 |
2 | 331 def __call__(self, *args): |
332 """add items to configuration and check it""" | |
67 | 333 |
24
39f2611db9be
rename a bunch of things and begin to work on the sanity of validation
Jeff Hammel <jhammel@mozilla.com>
parents:
23
diff
changeset
|
334 for config in args: |
39f2611db9be
rename a bunch of things and begin to work on the sanity of validation
Jeff Hammel <jhammel@mozilla.com>
parents:
23
diff
changeset
|
335 self.add(config) |
34
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
336 |
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
337 # add defaults if not present |
78 | 338 for key, value in self.items(): |
34
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
339 if 'default' in value and key not in self.config: |
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
340 self.config[key] = value['default'] |
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
341 |
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
342 # validate total configuration |
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
343 self.validate() |
24
39f2611db9be
rename a bunch of things and begin to work on the sanity of validation
Jeff Hammel <jhammel@mozilla.com>
parents:
23
diff
changeset
|
344 # TODO: configuration should be locked after this is called |
2 | 345 |
24
39f2611db9be
rename a bunch of things and begin to work on the sanity of validation
Jeff Hammel <jhammel@mozilla.com>
parents:
23
diff
changeset
|
346 def add(self, config, check=True): |
2 | 347 """update configuration: not undoable""" |
6 | 348 |
24
39f2611db9be
rename a bunch of things and begin to work on the sanity of validation
Jeff Hammel <jhammel@mozilla.com>
parents:
23
diff
changeset
|
349 self.check(config) # check config to be added |
2 | 350 self.config.update(config) |
351 # TODO: option to extend; augment lists/dicts | |
352 | |
18
d8871956536e
remove cruft and start to organize
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
353 ### methods for optparse |
d8871956536e
remove cruft and start to organize
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
354 ### XXX could go in a subclass |
d8871956536e
remove cruft and start to organize
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
355 |
82 | 356 def cli_formatter(self, option): |
86 | 357 handler = self.types[self.option_dict[option].get('type')] |
82 | 358 return getattr(handler, 'take_action', lambda x: 1) |
359 | |
88
36cf1d9bf40b
slightly improve type system
Jeff Hammel <jhammel@mozilla.com>
parents:
87
diff
changeset
|
360 def option_type(self, name): |
36cf1d9bf40b
slightly improve type system
Jeff Hammel <jhammel@mozilla.com>
parents:
87
diff
changeset
|
361 value = self.option_dict[name] |
36cf1d9bf40b
slightly improve type system
Jeff Hammel <jhammel@mozilla.com>
parents:
87
diff
changeset
|
362 if 'type' in value: |
36cf1d9bf40b
slightly improve type system
Jeff Hammel <jhammel@mozilla.com>
parents:
87
diff
changeset
|
363 return value['type'] |
36cf1d9bf40b
slightly improve type system
Jeff Hammel <jhammel@mozilla.com>
parents:
87
diff
changeset
|
364 if 'default' in value: |
36cf1d9bf40b
slightly improve type system
Jeff Hammel <jhammel@mozilla.com>
parents:
87
diff
changeset
|
365 return type(value['default']) |
36cf1d9bf40b
slightly improve type system
Jeff Hammel <jhammel@mozilla.com>
parents:
87
diff
changeset
|
366 |
17
a78ab14ae376
separate thing to add options to its own function
Jeff Hammel <jhammel@mozilla.com>
parents:
15
diff
changeset
|
367 def optparse_options(self, parser): |
a78ab14ae376
separate thing to add options to its own function
Jeff Hammel <jhammel@mozilla.com>
parents:
15
diff
changeset
|
368 """add optparse options to a OptionParser instance""" |
11
e00afe2c83bf
stubbing configuration parser
Jeff Hammel <jhammel@mozilla.com>
parents:
10
diff
changeset
|
369 for key, value in self.items(): |
88
36cf1d9bf40b
slightly improve type system
Jeff Hammel <jhammel@mozilla.com>
parents:
87
diff
changeset
|
370 handler = self.types[self.option_type(key)] |
21
0fe74db6a56c
a hacky way to do CLI types handlers
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
371 args, kw = handler(key, value) |
11
e00afe2c83bf
stubbing configuration parser
Jeff Hammel <jhammel@mozilla.com>
parents:
10
diff
changeset
|
372 if not args: |
21
0fe74db6a56c
a hacky way to do CLI types handlers
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
373 # No CLI interface |
11
e00afe2c83bf
stubbing configuration parser
Jeff Hammel <jhammel@mozilla.com>
parents:
10
diff
changeset
|
374 continue |
12 | 375 parser.add_option(*args, **kw) |
17
a78ab14ae376
separate thing to add options to its own function
Jeff Hammel <jhammel@mozilla.com>
parents:
15
diff
changeset
|
376 |
63 | 377 def parse_args(self, *args, **kw): |
81
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
378 |
f3b2563b2a91
move to a class-based architecture
Jeff Hammel <jhammel@mozilla.com>
parents:
80
diff
changeset
|
379 self.parsed = set() |
63 | 380 options, args = optparse.OptionParser.parse_args(self, *args, **kw) |
381 | |
382 # get CLI configuration options | |
383 cli_config = dict([(key, value) for key, value in options.__dict__.items() | |
86 | 384 if key in self.option_dict and key in self.parsed]) |
63 | 385 |
386 # deserialize configuration | |
387 configuration_files = getattr(options, 'load', args) | |
388 missing = [i for i in configuration_files | |
389 if not os.path.exists(i)] | |
390 if missing: | |
64 | 391 self.error("Missing files: %s" % ', '.join(missing)) |
63 | 392 config = [] |
393 for f in configuration_files: | |
394 try: | |
395 config.append(self.deserialize(f)) | |
396 except BaseException, e: | |
397 parser.error(str(e)) | |
398 config.append(cli_config) | |
399 | |
400 missingvalues = None | |
401 try: | |
402 # generate configuration | |
403 self(*config) | |
404 except MissingValueException, missingvalues: | |
89
0804a706d6bf
handle CLI errors with optparse
Jeff Hammel <jhammel@mozilla.com>
parents:
88
diff
changeset
|
405 # errors are handled below |
63 | 406 pass |
407 | |
408 # dump configuration, if specified | |
409 dump = getattr(options, 'dump') | |
410 if dump: | |
411 # TODO: have a way of specifying format other than filename | |
412 self.serialize(dump) | |
413 | |
414 if missingvalues and not dump: | |
415 # XXX assuming if you don't have values you were just dumping | |
89
0804a706d6bf
handle CLI errors with optparse
Jeff Hammel <jhammel@mozilla.com>
parents:
88
diff
changeset
|
416 self.error(str(missingvalues)) |
63 | 417 |
64 | 418 # update options from config |
419 options.__dict__.update(self.config) | |
420 | |
63 | 421 # return parsed arguments |
422 return options, args | |
423 | |
28
c516ab813079
begin stubbing serialization/deserialization
Jeff Hammel <jhammel@mozilla.com>
parents:
27
diff
changeset
|
424 ### serialization/deserialization |
c516ab813079
begin stubbing serialization/deserialization
Jeff Hammel <jhammel@mozilla.com>
parents:
27
diff
changeset
|
425 |
43 | 426 def formats(self): |
427 """formats for deserialization""" | |
428 retval = [] | |
429 for provider in self.configuration_providers: | |
430 if provider.extensions and hasattr(provider, 'write'): | |
431 retval.append(provider.extensions[0]) | |
432 return retval | |
433 | |
28
c516ab813079
begin stubbing serialization/deserialization
Jeff Hammel <jhammel@mozilla.com>
parents:
27
diff
changeset
|
434 def configuration_provider(self, format): |
c516ab813079
begin stubbing serialization/deserialization
Jeff Hammel <jhammel@mozilla.com>
parents:
27
diff
changeset
|
435 """configuration provider guess for a given filename""" |
c516ab813079
begin stubbing serialization/deserialization
Jeff Hammel <jhammel@mozilla.com>
parents:
27
diff
changeset
|
436 for provider in self.configuration_providers: |
c516ab813079
begin stubbing serialization/deserialization
Jeff Hammel <jhammel@mozilla.com>
parents:
27
diff
changeset
|
437 if format in provider.extensions: |
c516ab813079
begin stubbing serialization/deserialization
Jeff Hammel <jhammel@mozilla.com>
parents:
27
diff
changeset
|
438 return provider |
c516ab813079
begin stubbing serialization/deserialization
Jeff Hammel <jhammel@mozilla.com>
parents:
27
diff
changeset
|
439 |
34
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
440 def filename2format(self, filename): |
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
441 extension = os.path.splitext(filename)[-1] |
38
8909ae1cc4ea
fix serialization (stub) tests
Jeff Hammel <jhammel@mozilla.com>
parents:
37
diff
changeset
|
442 return extension.lstrip('.') or None |
34
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
443 |
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
444 def serialize(self, filename, format=None, full=False): |
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
445 """ |
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
446 serialize configuration to a file |
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
447 - filename: path of file to serialize to |
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
448 - format: format of configuration provider |
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
449 - full: whether to serialize non-set optional strings [TODO] |
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
450 """ |
29
fadcc6ab51d4
more (de/)serialization stubbing
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
451 # TODO: allow file object vs file name |
28
c516ab813079
begin stubbing serialization/deserialization
Jeff Hammel <jhammel@mozilla.com>
parents:
27
diff
changeset
|
452 |
34
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
453 if not format: |
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
454 format = self.filename2format(filename) |
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
455 if not format: |
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
456 raise Exception('Please specify a format') |
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
457 # TODO: more specific exception type |
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
458 |
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
459 provider = self.configuration_provider(format) |
38
8909ae1cc4ea
fix serialization (stub) tests
Jeff Hammel <jhammel@mozilla.com>
parents:
37
diff
changeset
|
460 if not provider: |
8909ae1cc4ea
fix serialization (stub) tests
Jeff Hammel <jhammel@mozilla.com>
parents:
37
diff
changeset
|
461 raise Exception("Provider not found for format: %s" % format) |
34
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
462 |
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
463 config = copy.deepcopy(self.config) |
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
464 |
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
465 provider.write(config, filename) |
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
466 |
28
c516ab813079
begin stubbing serialization/deserialization
Jeff Hammel <jhammel@mozilla.com>
parents:
27
diff
changeset
|
467 def deserialize(self, filename, format=None): |
c516ab813079
begin stubbing serialization/deserialization
Jeff Hammel <jhammel@mozilla.com>
parents:
27
diff
changeset
|
468 """load configuration from a file""" |
29
fadcc6ab51d4
more (de/)serialization stubbing
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
469 # TODO: allow file object vs file name |
28
c516ab813079
begin stubbing serialization/deserialization
Jeff Hammel <jhammel@mozilla.com>
parents:
27
diff
changeset
|
470 |
50
113e8c2f7cab
start to hook up deserializers
Jeff Hammel <jhammel@mozilla.com>
parents:
49
diff
changeset
|
471 assert os.path.exists(filename) |
113e8c2f7cab
start to hook up deserializers
Jeff Hammel <jhammel@mozilla.com>
parents:
49
diff
changeset
|
472 |
41
1bd4ddf2e81d
deserialization should work now
Jeff Hammel <jhammel@mozilla.com>
parents:
38
diff
changeset
|
473 # get the format |
29
fadcc6ab51d4
more (de/)serialization stubbing
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
474 if not format: |
41
1bd4ddf2e81d
deserialization should work now
Jeff Hammel <jhammel@mozilla.com>
parents:
38
diff
changeset
|
475 format = self.filename2format(filename) |
1bd4ddf2e81d
deserialization should work now
Jeff Hammel <jhammel@mozilla.com>
parents:
38
diff
changeset
|
476 |
1bd4ddf2e81d
deserialization should work now
Jeff Hammel <jhammel@mozilla.com>
parents:
38
diff
changeset
|
477 # get the providers in some sensible order |
1bd4ddf2e81d
deserialization should work now
Jeff Hammel <jhammel@mozilla.com>
parents:
38
diff
changeset
|
478 providers = self.configuration_providers[:] |
1bd4ddf2e81d
deserialization should work now
Jeff Hammel <jhammel@mozilla.com>
parents:
38
diff
changeset
|
479 if format: |
1bd4ddf2e81d
deserialization should work now
Jeff Hammel <jhammel@mozilla.com>
parents:
38
diff
changeset
|
480 providers.sort(key=lambda x: int(format in x.extensions), reverse=True) |
34
79aca36abd9a
fill in defaults if not present
Jeff Hammel <jhammel@mozilla.com>
parents:
31
diff
changeset
|
481 |
41
1bd4ddf2e81d
deserialization should work now
Jeff Hammel <jhammel@mozilla.com>
parents:
38
diff
changeset
|
482 # deserialize the data |
1bd4ddf2e81d
deserialization should work now
Jeff Hammel <jhammel@mozilla.com>
parents:
38
diff
changeset
|
483 for provider in providers: |
1bd4ddf2e81d
deserialization should work now
Jeff Hammel <jhammel@mozilla.com>
parents:
38
diff
changeset
|
484 try: |
1bd4ddf2e81d
deserialization should work now
Jeff Hammel <jhammel@mozilla.com>
parents:
38
diff
changeset
|
485 return provider.read(filename) |
1bd4ddf2e81d
deserialization should work now
Jeff Hammel <jhammel@mozilla.com>
parents:
38
diff
changeset
|
486 except: |
1bd4ddf2e81d
deserialization should work now
Jeff Hammel <jhammel@mozilla.com>
parents:
38
diff
changeset
|
487 continue |
1bd4ddf2e81d
deserialization should work now
Jeff Hammel <jhammel@mozilla.com>
parents:
38
diff
changeset
|
488 else: |
1bd4ddf2e81d
deserialization should work now
Jeff Hammel <jhammel@mozilla.com>
parents:
38
diff
changeset
|
489 raise ConfigurationProviderException("Could not load %s" % filename) |