OLD | NEW |
1 # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. | 1 # copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr | 2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
3 # | 3 # |
4 # This file is part of logilab-common. | 4 # This file is part of logilab-common. |
5 # | 5 # |
6 # logilab-common is free software: you can redistribute it and/or modify it unde
r | 6 # logilab-common is free software: you can redistribute it and/or modify it unde
r |
7 # the terms of the GNU Lesser General Public License as published by the Free | 7 # the terms of the GNU Lesser General Public License as published by the Free |
8 # Software Foundation, either version 2.1 of the License, or (at your option) an
y | 8 # Software Foundation, either version 2.1 of the License, or (at your option) an
y |
9 # later version. | 9 # later version. |
10 # | 10 # |
11 # logilab-common is distributed in the hope that it will be useful, but WITHOUT | 11 # logilab-common is distributed in the hope that it will be useful, but WITHOUT |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
89 [MY CONFIG] | 89 [MY CONFIG] |
90 | 90 |
91 dothis=no | 91 dothis=no |
92 | 92 |
93 value=bacon | 93 value=bacon |
94 | 94 |
95 # you can also document the option | 95 # you can also document the option |
96 multiple=4,5,6 | 96 multiple=4,5,6 |
97 | 97 |
98 number=3 | 98 number=3 |
99 >>> | 99 |
| 100 Note : starting with Python 2.7 ConfigParser is able to take into |
| 101 account the order of occurrences of the options into a file (by |
| 102 using an OrderedDict). If you have two options changing some common |
| 103 state, like a 'disable-all-stuff' and a 'enable-some-stuff-a', their |
| 104 order of appearance will be significant : the last specified in the |
| 105 file wins. For earlier version of python and logilab.common newer |
| 106 than 0.61 the behaviour is unspecified. |
| 107 |
100 """ | 108 """ |
| 109 |
| 110 from __future__ import print_function |
| 111 |
101 __docformat__ = "restructuredtext en" | 112 __docformat__ = "restructuredtext en" |
102 | 113 |
103 __all__ = ('OptionsManagerMixIn', 'OptionsProviderMixIn', | 114 __all__ = ('OptionsManagerMixIn', 'OptionsProviderMixIn', |
104 'ConfigurationMixIn', 'Configuration', | 115 'ConfigurationMixIn', 'Configuration', |
105 'OptionsManager2ConfigurationAdapter') | 116 'OptionsManager2ConfigurationAdapter') |
106 | 117 |
107 import os | 118 import os |
108 import sys | 119 import sys |
109 import re | 120 import re |
110 from os.path import exists, expanduser | 121 from os.path import exists, expanduser |
111 from copy import copy | 122 from copy import copy |
112 from ConfigParser import ConfigParser, NoOptionError, NoSectionError, \ | |
113 DuplicateSectionError | |
114 from warnings import warn | 123 from warnings import warn |
115 | 124 |
116 from logilab.common.compat import callable, raw_input, str_encode as _encode | 125 from six import string_types |
| 126 from six.moves import range, configparser as cp, input |
117 | 127 |
| 128 from logilab.common.compat import str_encode as _encode |
| 129 from logilab.common.deprecation import deprecated |
118 from logilab.common.textutils import normalize_text, unquote | 130 from logilab.common.textutils import normalize_text, unquote |
119 from logilab.common import optik_ext as optparse | 131 from logilab.common import optik_ext |
120 | 132 |
121 OptionError = optparse.OptionError | 133 OptionError = optik_ext.OptionError |
122 | 134 |
123 REQUIRED = [] | 135 REQUIRED = [] |
124 | 136 |
125 class UnsupportedAction(Exception): | 137 class UnsupportedAction(Exception): |
126 """raised by set_option when it doesn't know what to do for an action""" | 138 """raised by set_option when it doesn't know what to do for an action""" |
127 | 139 |
128 | 140 |
129 def _get_encoding(encoding, stream): | 141 def _get_encoding(encoding, stream): |
130 encoding = encoding or getattr(stream, 'encoding', None) | 142 encoding = encoding or getattr(stream, 'encoding', None) |
131 if not encoding: | 143 if not encoding: |
132 import locale | 144 import locale |
133 encoding = locale.getpreferredencoding() | 145 encoding = locale.getpreferredencoding() |
134 return encoding | 146 return encoding |
135 | 147 |
136 | 148 |
137 # validation functions ######################################################## | 149 # validation functions ######################################################## |
138 | 150 |
| 151 # validators will return the validated value or raise optparse.OptionValueError |
| 152 # XXX add to documentation |
| 153 |
139 def choice_validator(optdict, name, value): | 154 def choice_validator(optdict, name, value): |
140 """validate and return a converted value for option of type 'choice' | 155 """validate and return a converted value for option of type 'choice' |
141 """ | 156 """ |
142 if not value in optdict['choices']: | 157 if not value in optdict['choices']: |
143 msg = "option %s: invalid value: %r, should be in %s" | 158 msg = "option %s: invalid value: %r, should be in %s" |
144 raise optparse.OptionValueError(msg % (name, value, optdict['choices'])) | 159 raise optik_ext.OptionValueError(msg % (name, value, optdict['choices'])
) |
145 return value | 160 return value |
146 | 161 |
147 def multiple_choice_validator(optdict, name, value): | 162 def multiple_choice_validator(optdict, name, value): |
148 """validate and return a converted value for option of type 'choice' | 163 """validate and return a converted value for option of type 'choice' |
149 """ | 164 """ |
150 choices = optdict['choices'] | 165 choices = optdict['choices'] |
151 values = optparse.check_csv(None, name, value) | 166 values = optik_ext.check_csv(None, name, value) |
152 for value in values: | 167 for value in values: |
153 if not value in choices: | 168 if not value in choices: |
154 msg = "option %s: invalid value: %r, should be in %s" | 169 msg = "option %s: invalid value: %r, should be in %s" |
155 raise optparse.OptionValueError(msg % (name, value, choices)) | 170 raise optik_ext.OptionValueError(msg % (name, value, choices)) |
156 return values | 171 return values |
157 | 172 |
158 def csv_validator(optdict, name, value): | 173 def csv_validator(optdict, name, value): |
159 """validate and return a converted value for option of type 'csv' | 174 """validate and return a converted value for option of type 'csv' |
160 """ | 175 """ |
161 return optparse.check_csv(None, name, value) | 176 return optik_ext.check_csv(None, name, value) |
162 | 177 |
163 def yn_validator(optdict, name, value): | 178 def yn_validator(optdict, name, value): |
164 """validate and return a converted value for option of type 'yn' | 179 """validate and return a converted value for option of type 'yn' |
165 """ | 180 """ |
166 return optparse.check_yn(None, name, value) | 181 return optik_ext.check_yn(None, name, value) |
167 | 182 |
168 def named_validator(optdict, name, value): | 183 def named_validator(optdict, name, value): |
169 """validate and return a converted value for option of type 'named' | 184 """validate and return a converted value for option of type 'named' |
170 """ | 185 """ |
171 return optparse.check_named(None, name, value) | 186 return optik_ext.check_named(None, name, value) |
172 | 187 |
173 def file_validator(optdict, name, value): | 188 def file_validator(optdict, name, value): |
174 """validate and return a filepath for option of type 'file'""" | 189 """validate and return a filepath for option of type 'file'""" |
175 return optparse.check_file(None, name, value) | 190 return optik_ext.check_file(None, name, value) |
176 | 191 |
177 def color_validator(optdict, name, value): | 192 def color_validator(optdict, name, value): |
178 """validate and return a valid color for option of type 'color'""" | 193 """validate and return a valid color for option of type 'color'""" |
179 return optparse.check_color(None, name, value) | 194 return optik_ext.check_color(None, name, value) |
180 | 195 |
181 def password_validator(optdict, name, value): | 196 def password_validator(optdict, name, value): |
182 """validate and return a string for option of type 'password'""" | 197 """validate and return a string for option of type 'password'""" |
183 return optparse.check_password(None, name, value) | 198 return optik_ext.check_password(None, name, value) |
184 | 199 |
185 def date_validator(optdict, name, value): | 200 def date_validator(optdict, name, value): |
186 """validate and return a mx DateTime object for option of type 'date'""" | 201 """validate and return a mx DateTime object for option of type 'date'""" |
187 return optparse.check_date(None, name, value) | 202 return optik_ext.check_date(None, name, value) |
188 | 203 |
189 def time_validator(optdict, name, value): | 204 def time_validator(optdict, name, value): |
190 """validate and return a time object for option of type 'time'""" | 205 """validate and return a time object for option of type 'time'""" |
191 return optparse.check_time(None, name, value) | 206 return optik_ext.check_time(None, name, value) |
192 | 207 |
193 def bytes_validator(optdict, name, value): | 208 def bytes_validator(optdict, name, value): |
194 """validate and return an integer for option of type 'bytes'""" | 209 """validate and return an integer for option of type 'bytes'""" |
195 return optparse.check_bytes(None, name, value) | 210 return optik_ext.check_bytes(None, name, value) |
196 | 211 |
197 | 212 |
198 VALIDATORS = {'string': unquote, | 213 VALIDATORS = {'string': unquote, |
199 'int': int, | 214 'int': int, |
200 'float': float, | 215 'float': float, |
201 'file': file_validator, | 216 'file': file_validator, |
202 'font': unquote, | 217 'font': unquote, |
203 'color': color_validator, | 218 'color': color_validator, |
204 'regexp': re.compile, | 219 'regexp': re.compile, |
205 'csv': csv_validator, | 220 'csv': csv_validator, |
206 'yn': yn_validator, | 221 'yn': yn_validator, |
207 'bool': yn_validator, | 222 'bool': yn_validator, |
208 'named': named_validator, | 223 'named': named_validator, |
209 'password': password_validator, | 224 'password': password_validator, |
210 'date': date_validator, | 225 'date': date_validator, |
211 'time': time_validator, | 226 'time': time_validator, |
212 'bytes': bytes_validator, | 227 'bytes': bytes_validator, |
213 'choice': choice_validator, | 228 'choice': choice_validator, |
214 'multiple_choice': multiple_choice_validator, | 229 'multiple_choice': multiple_choice_validator, |
215 } | 230 } |
216 | 231 |
217 def _call_validator(opttype, optdict, option, value): | 232 def _call_validator(opttype, optdict, option, value): |
218 if opttype not in VALIDATORS: | 233 if opttype not in VALIDATORS: |
219 raise Exception('Unsupported type "%s"' % opttype) | 234 raise Exception('Unsupported type "%s"' % opttype) |
220 try: | 235 try: |
221 return VALIDATORS[opttype](optdict, option, value) | 236 return VALIDATORS[opttype](optdict, option, value) |
222 except TypeError: | 237 except TypeError: |
223 try: | 238 try: |
224 return VALIDATORS[opttype](value) | 239 return VALIDATORS[opttype](value) |
225 except optparse.OptionValueError: | 240 except optik_ext.OptionValueError: |
226 raise | 241 raise |
227 except: | 242 except: |
228 raise optparse.OptionValueError('%s value (%r) should be of type %s'
% | 243 raise optik_ext.OptionValueError('%s value (%r) should be of type %s
' % |
229 (option, value, opttype)) | 244 (option, value, opttype)) |
230 | 245 |
231 # user input functions ######################################################## | 246 # user input functions ######################################################## |
232 | 247 |
| 248 # user input functions will ask the user for input on stdin then validate |
| 249 # the result and return the validated value or raise optparse.OptionValueError |
| 250 # XXX add to documentation |
| 251 |
233 def input_password(optdict, question='password:'): | 252 def input_password(optdict, question='password:'): |
234 from getpass import getpass | 253 from getpass import getpass |
235 while True: | 254 while True: |
236 value = getpass(question) | 255 value = getpass(question) |
237 value2 = getpass('confirm: ') | 256 value2 = getpass('confirm: ') |
238 if value == value2: | 257 if value == value2: |
239 return value | 258 return value |
240 print 'password mismatch, try again' | 259 print('password mismatch, try again') |
241 | 260 |
242 def input_string(optdict, question): | 261 def input_string(optdict, question): |
243 value = raw_input(question).strip() | 262 value = input(question).strip() |
244 return value or None | 263 return value or None |
245 | 264 |
246 def _make_input_function(opttype): | 265 def _make_input_function(opttype): |
247 def input_validator(optdict, question): | 266 def input_validator(optdict, question): |
248 while True: | 267 while True: |
249 value = raw_input(question) | 268 value = input(question) |
250 if not value.strip(): | 269 if not value.strip(): |
251 return None | 270 return None |
252 try: | 271 try: |
253 return _call_validator(opttype, optdict, None, value) | 272 return _call_validator(opttype, optdict, None, value) |
254 except optparse.OptionValueError, ex: | 273 except optik_ext.OptionValueError as ex: |
255 msg = str(ex).split(':', 1)[-1].strip() | 274 msg = str(ex).split(':', 1)[-1].strip() |
256 print 'bad value: %s' % msg | 275 print('bad value: %s' % msg) |
257 return input_validator | 276 return input_validator |
258 | 277 |
259 INPUT_FUNCTIONS = { | 278 INPUT_FUNCTIONS = { |
260 'string': input_string, | 279 'string': input_string, |
261 'password': input_password, | 280 'password': input_password, |
262 } | 281 } |
263 | 282 |
264 for opttype in VALIDATORS.keys(): | 283 for opttype in VALIDATORS.keys(): |
265 INPUT_FUNCTIONS.setdefault(opttype, _make_input_function(opttype)) | 284 INPUT_FUNCTIONS.setdefault(opttype, _make_input_function(opttype)) |
266 | 285 |
| 286 # utility functions ############################################################ |
| 287 |
267 def expand_default(self, option): | 288 def expand_default(self, option): |
268 """monkey patch OptionParser.expand_default since we have a particular | 289 """monkey patch OptionParser.expand_default since we have a particular |
269 way to handle defaults to avoid overriding values in the configuration | 290 way to handle defaults to avoid overriding values in the configuration |
270 file | 291 file |
271 """ | 292 """ |
272 if self.parser is None or not self.default_tag: | 293 if self.parser is None or not self.default_tag: |
273 return option.help | 294 return option.help |
274 optname = option._long_opts[0][2:] | 295 optname = option._long_opts[0][2:] |
275 try: | 296 try: |
276 provider = self.parser.options_manager._all_options[optname] | 297 provider = self.parser.options_manager._all_options[optname] |
277 except KeyError: | 298 except KeyError: |
278 value = None | 299 value = None |
279 else: | 300 else: |
280 optdict = provider.get_option_def(optname) | 301 optdict = provider.get_option_def(optname) |
281 optname = provider.option_name(optname, optdict) | 302 optname = provider.option_attrname(optname, optdict) |
282 value = getattr(provider.config, optname, optdict) | 303 value = getattr(provider.config, optname, optdict) |
283 value = format_option_value(optdict, value) | 304 value = format_option_value(optdict, value) |
284 if value is optparse.NO_DEFAULT or not value: | 305 if value is optik_ext.NO_DEFAULT or not value: |
285 value = self.NO_DEFAULT_VALUE | 306 value = self.NO_DEFAULT_VALUE |
286 return option.help.replace(self.default_tag, str(value)) | 307 return option.help.replace(self.default_tag, str(value)) |
287 | 308 |
288 | 309 |
289 def convert(value, optdict, name=''): | 310 def _validate(value, optdict, name=''): |
290 """return a validated value for an option according to its type | 311 """return a validated value for an option according to its type |
291 | 312 |
292 optional argument name is only used for error message formatting | 313 optional argument name is only used for error message formatting |
293 """ | 314 """ |
294 try: | 315 try: |
295 _type = optdict['type'] | 316 _type = optdict['type'] |
296 except KeyError: | 317 except KeyError: |
297 # FIXME | 318 # FIXME |
298 return value | 319 return value |
299 return _call_validator(_type, optdict, name, value) | 320 return _call_validator(_type, optdict, name, value) |
| 321 convert = deprecated('[0.60] convert() was renamed _validate()')(_validate) |
| 322 |
| 323 # format and output functions ################################################## |
300 | 324 |
301 def comment(string): | 325 def comment(string): |
302 """return string as a comment""" | 326 """return string as a comment""" |
303 lines = [line.strip() for line in string.splitlines()] | 327 lines = [line.strip() for line in string.splitlines()] |
304 return '# ' + ('%s# ' % os.linesep).join(lines) | 328 return '# ' + ('%s# ' % os.linesep).join(lines) |
305 | 329 |
306 def format_time(value): | 330 def format_time(value): |
307 if not value: | 331 if not value: |
308 return '0' | 332 return '0' |
309 if value != int(value): | 333 if value != int(value): |
(...skipping 29 matching lines...) Expand all Loading... |
339 """return the user input's value from a 'compiled' value""" | 363 """return the user input's value from a 'compiled' value""" |
340 if isinstance(value, (list, tuple)): | 364 if isinstance(value, (list, tuple)): |
341 value = ','.join(value) | 365 value = ','.join(value) |
342 elif isinstance(value, dict): | 366 elif isinstance(value, dict): |
343 value = ','.join(['%s:%s' % (k, v) for k, v in value.items()]) | 367 value = ','.join(['%s:%s' % (k, v) for k, v in value.items()]) |
344 elif hasattr(value, 'match'): # optdict.get('type') == 'regexp' | 368 elif hasattr(value, 'match'): # optdict.get('type') == 'regexp' |
345 # compiled regexp | 369 # compiled regexp |
346 value = value.pattern | 370 value = value.pattern |
347 elif optdict.get('type') == 'yn': | 371 elif optdict.get('type') == 'yn': |
348 value = value and 'yes' or 'no' | 372 value = value and 'yes' or 'no' |
349 elif isinstance(value, (str, unicode)) and value.isspace(): | 373 elif isinstance(value, string_types) and value.isspace(): |
350 value = "'%s'" % value | 374 value = "'%s'" % value |
351 elif optdict.get('type') == 'time' and isinstance(value, (float, int, long))
: | 375 elif optdict.get('type') == 'time' and isinstance(value, (float, int, long))
: |
352 value = format_time(value) | 376 value = format_time(value) |
353 elif optdict.get('type') == 'bytes' and hasattr(value, '__int__'): | 377 elif optdict.get('type') == 'bytes' and hasattr(value, '__int__'): |
354 value = format_bytes(value) | 378 value = format_bytes(value) |
355 return value | 379 return value |
356 | 380 |
357 def ini_format_section(stream, section, options, encoding=None, doc=None): | 381 def ini_format_section(stream, section, options, encoding=None, doc=None): |
358 """format an options section using the INI format""" | 382 """format an options section using the INI format""" |
359 encoding = _get_encoding(encoding, stream) | 383 encoding = _get_encoding(encoding, stream) |
360 if doc: | 384 if doc: |
361 print >> stream, _encode(comment(doc), encoding) | 385 print(_encode(comment(doc), encoding), file=stream) |
362 print >> stream, '[%s]' % section | 386 print('[%s]' % section, file=stream) |
363 ini_format(stream, options, encoding) | 387 ini_format(stream, options, encoding) |
364 | 388 |
365 def ini_format(stream, options, encoding): | 389 def ini_format(stream, options, encoding): |
366 """format options using the INI format""" | 390 """format options using the INI format""" |
367 for optname, optdict, value in options: | 391 for optname, optdict, value in options: |
368 value = format_option_value(optdict, value) | 392 value = format_option_value(optdict, value) |
369 help = optdict.get('help') | 393 help = optdict.get('help') |
370 if help: | 394 if help: |
371 help = normalize_text(help, line_len=79, indent='# ') | 395 help = normalize_text(help, line_len=79, indent='# ') |
372 print >> stream | 396 print(file=stream) |
373 print >> stream, _encode(help, encoding) | 397 print(_encode(help, encoding), file=stream) |
374 else: | 398 else: |
375 print >> stream | 399 print(file=stream) |
376 if value is None: | 400 if value is None: |
377 print >> stream, '#%s=' % optname | 401 print('#%s=' % optname, file=stream) |
378 else: | 402 else: |
379 value = _encode(value, encoding).strip() | 403 value = _encode(value, encoding).strip() |
380 print >> stream, '%s=%s' % (optname, value) | 404 print('%s=%s' % (optname, value), file=stream) |
381 | 405 |
382 format_section = ini_format_section | 406 format_section = ini_format_section |
383 | 407 |
384 def rest_format_section(stream, section, options, encoding=None, doc=None): | 408 def rest_format_section(stream, section, options, encoding=None, doc=None): |
385 """format an options section using the INI format""" | 409 """format an options section using as ReST formatted output""" |
386 encoding = _get_encoding(encoding, stream) | 410 encoding = _get_encoding(encoding, stream) |
387 if section: | 411 if section: |
388 print >> stream, '%s\n%s' % (section, "'"*len(section)) | 412 print >> stream, '%s\n%s' % (section, "'"*len(section)) |
389 if doc: | 413 if doc: |
390 print >> stream, _encode(normalize_text(doc, line_len=79, indent=''), | 414 print >> stream, _encode(normalize_text(doc, line_len=79, indent=''), |
391 encoding) | 415 encoding) |
392 print >> stream | 416 print >> stream |
393 for optname, optdict, value in options: | 417 for optname, optdict, value in options: |
394 help = optdict.get('help') | 418 help = optdict.get('help') |
395 print >> stream, ':%s:' % optname | 419 print >> stream, ':%s:' % optname |
396 if help: | 420 if help: |
397 help = normalize_text(help, line_len=79, indent=' ') | 421 help = normalize_text(help, line_len=79, indent=' ') |
398 print >> stream, _encode(help, encoding) | 422 print >> stream, _encode(help, encoding) |
399 if value: | 423 if value: |
400 value = _encode(format_option_value(optdict, value), encoding) | 424 value = _encode(format_option_value(optdict, value), encoding) |
401 print >> stream, '' | 425 print >> stream, '' |
402 print >> stream, ' Default: ``%s``' % value.replace("`` ", "```` ``
") | 426 print >> stream, ' Default: ``%s``' % value.replace("`` ", "```` ``
") |
403 | 427 |
| 428 # Options Manager ############################################################## |
404 | 429 |
405 class OptionsManagerMixIn(object): | 430 class OptionsManagerMixIn(object): |
406 """MixIn to handle a configuration from both a configuration file and | 431 """MixIn to handle a configuration from both a configuration file and |
407 command line options | 432 command line options |
408 """ | 433 """ |
409 | 434 |
410 def __init__(self, usage, config_file=None, version=None, quiet=0): | 435 def __init__(self, usage, config_file=None, version=None, quiet=0): |
411 self.config_file = config_file | 436 self.config_file = config_file |
412 self.reset_parsers(usage, version=version) | 437 self.reset_parsers(usage, version=version) |
413 # list of registered options providers | 438 # list of registered options providers |
414 self.options_providers = [] | 439 self.options_providers = [] |
415 # dictionary associating option name to checker | 440 # dictionary associating option name to checker |
416 self._all_options = {} | 441 self._all_options = {} |
417 self._short_options = {} | 442 self._short_options = {} |
418 self._nocallback_options = {} | 443 self._nocallback_options = {} |
419 self._mygroups = dict() | 444 self._mygroups = dict() |
420 # verbosity | 445 # verbosity |
421 self.quiet = quiet | 446 self.quiet = quiet |
422 self._maxlevel = 0 | 447 self._maxlevel = 0 |
423 | 448 |
424 def reset_parsers(self, usage='', version=None): | 449 def reset_parsers(self, usage='', version=None): |
425 # configuration file parser | 450 # configuration file parser |
426 self.cfgfile_parser = ConfigParser() | 451 self.cfgfile_parser = cp.ConfigParser() |
427 # command line parser | 452 # command line parser |
428 self.cmdline_parser = optparse.OptionParser(usage=usage, version=version
) | 453 self.cmdline_parser = optik_ext.OptionParser(usage=usage, version=versio
n) |
429 self.cmdline_parser.options_manager = self | 454 self.cmdline_parser.options_manager = self |
430 self._optik_option_attrs = set(self.cmdline_parser.option_class.ATTRS) | 455 self._optik_option_attrs = set(self.cmdline_parser.option_class.ATTRS) |
431 | 456 |
432 def register_options_provider(self, provider, own_group=True): | 457 def register_options_provider(self, provider, own_group=True): |
433 """register an options provider""" | 458 """register an options provider""" |
434 assert provider.priority <= 0, "provider's priority can't be >= 0" | 459 assert provider.priority <= 0, "provider's priority can't be >= 0" |
435 for i in range(len(self.options_providers)): | 460 for i in range(len(self.options_providers)): |
436 if provider.priority > self.options_providers[i].priority: | 461 if provider.priority > self.options_providers[i].priority: |
437 self.options_providers.insert(i, provider) | 462 self.options_providers.insert(i, provider) |
438 break | 463 break |
(...skipping 15 matching lines...) Expand all Loading... |
454 self.add_option_group(gname, gdoc, goptions, provider) | 479 self.add_option_group(gname, gdoc, goptions, provider) |
455 | 480 |
456 def add_option_group(self, group_name, doc, options, provider): | 481 def add_option_group(self, group_name, doc, options, provider): |
457 """add an option group including the listed options | 482 """add an option group including the listed options |
458 """ | 483 """ |
459 assert options | 484 assert options |
460 # add option group to the command line parser | 485 # add option group to the command line parser |
461 if group_name in self._mygroups: | 486 if group_name in self._mygroups: |
462 group = self._mygroups[group_name] | 487 group = self._mygroups[group_name] |
463 else: | 488 else: |
464 group = optparse.OptionGroup(self.cmdline_parser, | 489 group = optik_ext.OptionGroup(self.cmdline_parser, |
465 title=group_name.capitalize()) | 490 title=group_name.capitalize()) |
466 self.cmdline_parser.add_option_group(group) | 491 self.cmdline_parser.add_option_group(group) |
467 group.level = provider.level | 492 group.level = provider.level |
468 self._mygroups[group_name] = group | 493 self._mygroups[group_name] = group |
469 # add section to the config file | 494 # add section to the config file |
470 if group_name != "DEFAULT": | 495 if group_name != "DEFAULT": |
471 self.cfgfile_parser.add_section(group_name) | 496 self.cfgfile_parser.add_section(group_name) |
472 # add provider's specific options | 497 # add provider's specific options |
473 for opt, optdict in options: | 498 for opt, optdict in options: |
474 self.add_optik_option(provider, group, opt, optdict) | 499 self.add_optik_option(provider, group, opt, optdict) |
(...skipping 15 matching lines...) Expand all Loading... |
490 optdict = copy(optdict) | 515 optdict = copy(optdict) |
491 others = {} | 516 others = {} |
492 if 'action' in optdict: | 517 if 'action' in optdict: |
493 self._nocallback_options[provider] = opt | 518 self._nocallback_options[provider] = opt |
494 else: | 519 else: |
495 optdict['action'] = 'callback' | 520 optdict['action'] = 'callback' |
496 optdict['callback'] = self.cb_set_provider_option | 521 optdict['callback'] = self.cb_set_provider_option |
497 # default is handled here and *must not* be given to optik if you | 522 # default is handled here and *must not* be given to optik if you |
498 # want the whole machinery to work | 523 # want the whole machinery to work |
499 if 'default' in optdict: | 524 if 'default' in optdict: |
500 if (optparse.OPTPARSE_FORMAT_DEFAULT and 'help' in optdict and | 525 if ('help' in optdict |
501 optdict.get('default') is not None and | 526 and optdict.get('default') is not None |
502 not optdict['action'] in ('store_true', 'store_false')): | 527 and not optdict['action'] in ('store_true', 'store_false')): |
503 optdict['help'] += ' [current: %default]' | 528 optdict['help'] += ' [current: %default]' |
504 del optdict['default'] | 529 del optdict['default'] |
505 args = ['--' + str(opt)] | 530 args = ['--' + str(opt)] |
506 if 'short' in optdict: | 531 if 'short' in optdict: |
507 self._short_options[optdict['short']] = opt | 532 self._short_options[optdict['short']] = opt |
508 args.append('-' + optdict['short']) | 533 args.append('-' + optdict['short']) |
509 del optdict['short'] | 534 del optdict['short'] |
510 # cleanup option definition dict before giving it to optik | 535 # cleanup option definition dict before giving it to optik |
511 for key in optdict.keys(): | 536 for key in list(optdict.keys()): |
512 if not key in self._optik_option_attrs: | 537 if not key in self._optik_option_attrs: |
513 optdict.pop(key) | 538 optdict.pop(key) |
514 return args, optdict | 539 return args, optdict |
515 | 540 |
516 def cb_set_provider_option(self, option, opt, value, parser): | 541 def cb_set_provider_option(self, option, opt, value, parser): |
517 """optik callback for option setting""" | 542 """optik callback for option setting""" |
518 if opt.startswith('--'): | 543 if opt.startswith('--'): |
519 # remove -- on long option | 544 # remove -- on long option |
520 opt = opt[2:] | 545 opt = opt[2:] |
521 else: | 546 else: |
(...skipping 26 matching lines...) Expand all Loading... |
548 continue | 573 continue |
549 if not section in sections: | 574 if not section in sections: |
550 sections.append(section) | 575 sections.append(section) |
551 alloptions = options_by_section.setdefault(section, []) | 576 alloptions = options_by_section.setdefault(section, []) |
552 alloptions += options | 577 alloptions += options |
553 stream = stream or sys.stdout | 578 stream = stream or sys.stdout |
554 encoding = _get_encoding(encoding, stream) | 579 encoding = _get_encoding(encoding, stream) |
555 printed = False | 580 printed = False |
556 for section in sections: | 581 for section in sections: |
557 if printed: | 582 if printed: |
558 print >> stream, '\n' | 583 print('\n', file=stream) |
559 format_section(stream, section.upper(), options_by_section[section], | 584 format_section(stream, section.upper(), options_by_section[section], |
560 encoding) | 585 encoding) |
561 printed = True | 586 printed = True |
562 | 587 |
563 def generate_manpage(self, pkginfo, section=1, stream=None): | 588 def generate_manpage(self, pkginfo, section=1, stream=None): |
564 """write a man page for the current configuration into the given | 589 """write a man page for the current configuration into the given |
565 stream or stdout | 590 stream or stdout |
566 """ | 591 """ |
567 self._monkeypatch_expand_default() | 592 self._monkeypatch_expand_default() |
568 try: | 593 try: |
569 optparse.generate_manpage(self.cmdline_parser, pkginfo, | 594 optik_ext.generate_manpage(self.cmdline_parser, pkginfo, |
570 section, stream=stream or sys.stdout, | 595 section, stream=stream or sys.stdout, |
571 level=self._maxlevel) | 596 level=self._maxlevel) |
572 finally: | 597 finally: |
573 self._unmonkeypatch_expand_default() | 598 self._unmonkeypatch_expand_default() |
574 | 599 |
575 # initialization methods ################################################## | 600 # initialization methods ################################################## |
576 | 601 |
577 def load_provider_defaults(self): | 602 def load_provider_defaults(self): |
578 """initialize configuration using default values""" | 603 """initialize configuration using default values""" |
579 for provider in self.options_providers: | 604 for provider in self.options_providers: |
580 provider.load_defaults() | 605 provider.load_defaults() |
581 | 606 |
582 def load_file_configuration(self, config_file=None): | 607 def load_file_configuration(self, config_file=None): |
583 """load the configuration from file""" | 608 """load the configuration from file""" |
584 self.read_config_file(config_file) | 609 self.read_config_file(config_file) |
585 self.load_config_file() | 610 self.load_config_file() |
586 | 611 |
587 def read_config_file(self, config_file=None): | 612 def read_config_file(self, config_file=None): |
588 """read the configuration file but do not load it (i.e. dispatching | 613 """read the configuration file but do not load it (i.e. dispatching |
589 values to each options provider) | 614 values to each options provider) |
590 """ | 615 """ |
591 helplevel = 1 | 616 helplevel = 1 |
592 while helplevel <= self._maxlevel: | 617 while helplevel <= self._maxlevel: |
593 opt = '-'.join(['long'] * helplevel) + '-help' | 618 opt = '-'.join(['long'] * helplevel) + '-help' |
594 if opt in self._all_options: | 619 if opt in self._all_options: |
595 break # already processed | 620 break # already processed |
596 def helpfunc(option, opt, val, p, level=helplevel): | 621 def helpfunc(option, opt, val, p, level=helplevel): |
597 print self.help(level) | 622 print(self.help(level)) |
598 sys.exit(0) | 623 sys.exit(0) |
599 helpmsg = '%s verbose help.' % ' '.join(['more'] * helplevel) | 624 helpmsg = '%s verbose help.' % ' '.join(['more'] * helplevel) |
600 optdict = {'action' : 'callback', 'callback' : helpfunc, | 625 optdict = {'action' : 'callback', 'callback' : helpfunc, |
601 'help' : helpmsg} | 626 'help' : helpmsg} |
602 provider = self.options_providers[0] | 627 provider = self.options_providers[0] |
603 self.add_optik_option(provider, self.cmdline_parser, opt, optdict) | 628 self.add_optik_option(provider, self.cmdline_parser, opt, optdict) |
604 provider.options += ( (opt, optdict), ) | 629 provider.options += ( (opt, optdict), ) |
605 helplevel += 1 | 630 helplevel += 1 |
606 if config_file is None: | 631 if config_file is None: |
607 config_file = self.config_file | 632 config_file = self.config_file |
608 if config_file is not None: | 633 if config_file is not None: |
609 config_file = expanduser(config_file) | 634 config_file = expanduser(config_file) |
610 if config_file and exists(config_file): | 635 if config_file and exists(config_file): |
611 parser = self.cfgfile_parser | 636 parser = self.cfgfile_parser |
612 parser.read([config_file]) | 637 parser.read([config_file]) |
613 # normalize sections'title | 638 # normalize sections'title |
614 for sect, values in parser._sections.items(): | 639 for sect, values in parser._sections.items(): |
615 if not sect.isupper() and values: | 640 if not sect.isupper() and values: |
616 parser._sections[sect.upper()] = values | 641 parser._sections[sect.upper()] = values |
617 elif not self.quiet: | 642 elif not self.quiet: |
618 msg = 'No config file found, using default configuration' | 643 msg = 'No config file found, using default configuration' |
619 print >> sys.stderr, msg | 644 print(msg, file=sys.stderr) |
620 return | 645 return |
621 | 646 |
622 def input_config(self, onlysection=None, inputlevel=0, stream=None): | 647 def input_config(self, onlysection=None, inputlevel=0, stream=None): |
623 """interactively get configuration values by asking to the user and gene
rate | 648 """interactively get configuration values by asking to the user and gene
rate |
624 a configuration file | 649 a configuration file |
625 """ | 650 """ |
626 if onlysection is not None: | 651 if onlysection is not None: |
627 onlysection = onlysection.upper() | 652 onlysection = onlysection.upper() |
628 for provider in self.options_providers: | 653 for provider in self.options_providers: |
629 for section, option, optdict in provider.all_options(): | 654 for section, option, optdict in provider.all_options(): |
630 if onlysection is not None and section != onlysection: | 655 if onlysection is not None and section != onlysection: |
631 continue | 656 continue |
632 if not 'type' in optdict: | 657 if not 'type' in optdict: |
633 # ignore action without type (callback, store_true...) | 658 # ignore action without type (callback, store_true...) |
634 continue | 659 continue |
635 provider.input_option(option, optdict, inputlevel) | 660 provider.input_option(option, optdict, inputlevel) |
636 # now we can generate the configuration file | 661 # now we can generate the configuration file |
637 if stream is not None: | 662 if stream is not None: |
638 self.generate_config(stream) | 663 self.generate_config(stream) |
639 | 664 |
640 def load_config_file(self): | 665 def load_config_file(self): |
641 """dispatch values previously read from a configuration file to each | 666 """dispatch values previously read from a configuration file to each |
642 options provider) | 667 options provider) |
643 """ | 668 """ |
644 parser = self.cfgfile_parser | 669 parser = self.cfgfile_parser |
645 for provider in self.options_providers: | 670 for section in parser.sections(): |
646 for section, option, optdict in provider.all_options(): | 671 for option, value in parser.items(section): |
647 try: | 672 try: |
648 value = parser.get(section, option) | 673 self.global_set_option(option, value) |
649 provider.set_option(option, value, optdict=optdict) | 674 except (KeyError, OptionError): |
650 except (NoSectionError, NoOptionError), ex: | 675 # TODO handle here undeclared options appearing in the co
nfig file |
651 continue | 676 continue |
652 | 677 |
653 def load_configuration(self, **kwargs): | 678 def load_configuration(self, **kwargs): |
654 """override configuration according to given parameters | 679 """override configuration according to given parameters |
655 """ | 680 """ |
656 for opt, opt_value in kwargs.items(): | 681 for opt, opt_value in kwargs.items(): |
657 opt = opt.replace('_', '-') | 682 opt = opt.replace('_', '-') |
658 provider = self._all_options[opt] | 683 provider = self._all_options[opt] |
659 provider.set_option(opt, opt_value) | 684 provider.set_option(opt, opt_value) |
660 | 685 |
661 def load_command_line_configuration(self, args=None): | 686 def load_command_line_configuration(self, args=None): |
(...skipping 17 matching lines...) Expand all Loading... |
679 setattr(config, attr, value) | 704 setattr(config, attr, value) |
680 return args | 705 return args |
681 finally: | 706 finally: |
682 self._unmonkeypatch_expand_default() | 707 self._unmonkeypatch_expand_default() |
683 | 708 |
684 | 709 |
685 # help methods ############################################################ | 710 # help methods ############################################################ |
686 | 711 |
687 def add_help_section(self, title, description, level=0): | 712 def add_help_section(self, title, description, level=0): |
688 """add a dummy option section for help purpose """ | 713 """add a dummy option section for help purpose """ |
689 group = optparse.OptionGroup(self.cmdline_parser, | 714 group = optik_ext.OptionGroup(self.cmdline_parser, |
690 title=title.capitalize(), | 715 title=title.capitalize(), |
691 description=description) | 716 description=description) |
692 group.level = level | 717 group.level = level |
693 self._maxlevel = max(self._maxlevel, level) | 718 self._maxlevel = max(self._maxlevel, level) |
694 self.cmdline_parser.add_option_group(group) | 719 self.cmdline_parser.add_option_group(group) |
695 | 720 |
696 def _monkeypatch_expand_default(self): | 721 def _monkeypatch_expand_default(self): |
697 # monkey patch optparse to deal with our default values | 722 # monkey patch optik_ext to deal with our default values |
698 try: | 723 try: |
699 self.__expand_default_backup = optparse.HelpFormatter.expand_default | 724 self.__expand_default_backup = optik_ext.HelpFormatter.expand_defaul
t |
700 optparse.HelpFormatter.expand_default = expand_default | 725 optik_ext.HelpFormatter.expand_default = expand_default |
701 except AttributeError: | 726 except AttributeError: |
702 # python < 2.4: nothing to be done | 727 # python < 2.4: nothing to be done |
703 pass | 728 pass |
704 def _unmonkeypatch_expand_default(self): | 729 def _unmonkeypatch_expand_default(self): |
705 # remove monkey patch | 730 # remove monkey patch |
706 if hasattr(optparse.HelpFormatter, 'expand_default'): | 731 if hasattr(optik_ext.HelpFormatter, 'expand_default'): |
707 # unpatch optparse to avoid side effects | 732 # unpatch optik_ext to avoid side effects |
708 optparse.HelpFormatter.expand_default = self.__expand_default_backup | 733 optik_ext.HelpFormatter.expand_default = self.__expand_default_backu
p |
709 | 734 |
710 def help(self, level=0): | 735 def help(self, level=0): |
711 """return the usage string for available options """ | 736 """return the usage string for available options """ |
712 self.cmdline_parser.formatter.output_level = level | 737 self.cmdline_parser.formatter.output_level = level |
713 self._monkeypatch_expand_default() | 738 self._monkeypatch_expand_default() |
714 try: | 739 try: |
715 return self.cmdline_parser.format_help() | 740 return self.cmdline_parser.format_help() |
716 finally: | 741 finally: |
717 self._unmonkeypatch_expand_default() | 742 self._unmonkeypatch_expand_default() |
718 | 743 |
719 | 744 |
720 class Method(object): | 745 class Method(object): |
721 """used to ease late binding of default method (so you can define options | 746 """used to ease late binding of default method (so you can define options |
722 on the class using default methods on the configuration instance) | 747 on the class using default methods on the configuration instance) |
723 """ | 748 """ |
724 def __init__(self, methname): | 749 def __init__(self, methname): |
725 self.method = methname | 750 self.method = methname |
726 self._inst = None | 751 self._inst = None |
727 | 752 |
728 def bind(self, instance): | 753 def bind(self, instance): |
729 """bind the method to its instance""" | 754 """bind the method to its instance""" |
730 if self._inst is None: | 755 if self._inst is None: |
731 self._inst = instance | 756 self._inst = instance |
732 | 757 |
733 def __call__(self, *args, **kwargs): | 758 def __call__(self, *args, **kwargs): |
734 assert self._inst, 'unbound method' | 759 assert self._inst, 'unbound method' |
735 return getattr(self._inst, self.method)(*args, **kwargs) | 760 return getattr(self._inst, self.method)(*args, **kwargs) |
736 | 761 |
| 762 # Options Provider ############################################################# |
737 | 763 |
738 class OptionsProviderMixIn(object): | 764 class OptionsProviderMixIn(object): |
739 """Mixin to provide options to an OptionsManager""" | 765 """Mixin to provide options to an OptionsManager""" |
740 | 766 |
741 # those attributes should be overridden | 767 # those attributes should be overridden |
742 priority = -1 | 768 priority = -1 |
743 name = 'default' | 769 name = 'default' |
744 options = () | 770 options = () |
745 level = 0 | 771 level = 0 |
746 | 772 |
747 def __init__(self): | 773 def __init__(self): |
748 self.config = optparse.Values() | 774 self.config = optik_ext.Values() |
749 for option in self.options: | 775 for option in self.options: |
750 try: | 776 try: |
751 option, optdict = option | 777 option, optdict = option |
752 except ValueError: | 778 except ValueError: |
753 raise Exception('Bad option: %r' % option) | 779 raise Exception('Bad option: %r' % option) |
754 if isinstance(optdict.get('default'), Method): | 780 if isinstance(optdict.get('default'), Method): |
755 optdict['default'].bind(self) | 781 optdict['default'].bind(self) |
756 elif isinstance(optdict.get('callback'), Method): | 782 elif isinstance(optdict.get('callback'), Method): |
757 optdict['callback'].bind(self) | 783 optdict['callback'].bind(self) |
758 self.load_defaults() | 784 self.load_defaults() |
(...skipping 11 matching lines...) Expand all Loading... |
770 | 796 |
771 def option_default(self, opt, optdict=None): | 797 def option_default(self, opt, optdict=None): |
772 """return the default value for an option""" | 798 """return the default value for an option""" |
773 if optdict is None: | 799 if optdict is None: |
774 optdict = self.get_option_def(opt) | 800 optdict = self.get_option_def(opt) |
775 default = optdict.get('default') | 801 default = optdict.get('default') |
776 if callable(default): | 802 if callable(default): |
777 default = default() | 803 default = default() |
778 return default | 804 return default |
779 | 805 |
780 def option_name(self, opt, optdict=None): | 806 def option_attrname(self, opt, optdict=None): |
781 """get the config attribute corresponding to opt | 807 """get the config attribute corresponding to opt |
782 """ | 808 """ |
783 if optdict is None: | 809 if optdict is None: |
784 optdict = self.get_option_def(opt) | 810 optdict = self.get_option_def(opt) |
785 return optdict.get('dest', opt.replace('-', '_')) | 811 return optdict.get('dest', opt.replace('-', '_')) |
| 812 option_name = deprecated('[0.60] OptionsProviderMixIn.option_name() was rena
med to option_attrname()')(option_attrname) |
786 | 813 |
787 def option_value(self, opt): | 814 def option_value(self, opt): |
788 """get the current value for the given option""" | 815 """get the current value for the given option""" |
789 return getattr(self.config, self.option_name(opt), None) | 816 return getattr(self.config, self.option_attrname(opt), None) |
790 | 817 |
791 def set_option(self, opt, value, action=None, optdict=None): | 818 def set_option(self, opt, value, action=None, optdict=None): |
792 """method called to set an option (registered in the options list) | 819 """method called to set an option (registered in the options list) |
793 """ | 820 """ |
794 # print "************ setting option", opt," to value", value | |
795 if optdict is None: | 821 if optdict is None: |
796 optdict = self.get_option_def(opt) | 822 optdict = self.get_option_def(opt) |
797 if value is not None: | 823 if value is not None: |
798 value = convert(value, optdict, opt) | 824 value = _validate(value, optdict, opt) |
799 if action is None: | 825 if action is None: |
800 action = optdict.get('action', 'store') | 826 action = optdict.get('action', 'store') |
801 if optdict.get('type') == 'named': # XXX need specific handling | 827 if optdict.get('type') == 'named': # XXX need specific handling |
802 optname = self.option_name(opt, optdict) | 828 optname = self.option_attrname(opt, optdict) |
803 currentvalue = getattr(self.config, optname, None) | 829 currentvalue = getattr(self.config, optname, None) |
804 if currentvalue: | 830 if currentvalue: |
805 currentvalue.update(value) | 831 currentvalue.update(value) |
806 value = currentvalue | 832 value = currentvalue |
807 if action == 'store': | 833 if action == 'store': |
808 setattr(self.config, self.option_name(opt, optdict), value) | 834 setattr(self.config, self.option_attrname(opt, optdict), value) |
809 elif action in ('store_true', 'count'): | 835 elif action in ('store_true', 'count'): |
810 setattr(self.config, self.option_name(opt, optdict), 0) | 836 setattr(self.config, self.option_attrname(opt, optdict), 0) |
811 elif action == 'store_false': | 837 elif action == 'store_false': |
812 setattr(self.config, self.option_name(opt, optdict), 1) | 838 setattr(self.config, self.option_attrname(opt, optdict), 1) |
813 elif action == 'append': | 839 elif action == 'append': |
814 opt = self.option_name(opt, optdict) | 840 opt = self.option_attrname(opt, optdict) |
815 _list = getattr(self.config, opt, None) | 841 _list = getattr(self.config, opt, None) |
816 if _list is None: | 842 if _list is None: |
817 if isinstance(value, (list, tuple)): | 843 if isinstance(value, (list, tuple)): |
818 _list = value | 844 _list = value |
819 elif value is not None: | 845 elif value is not None: |
820 _list = [] | 846 _list = [] |
821 _list.append(value) | 847 _list.append(value) |
822 setattr(self.config, opt, _list) | 848 setattr(self.config, opt, _list) |
823 elif isinstance(_list, tuple): | 849 elif isinstance(_list, tuple): |
824 setattr(self.config, opt, _list + (value,)) | 850 setattr(self.config, opt, _list + (value,)) |
825 else: | 851 else: |
826 _list.append(value) | 852 _list.append(value) |
827 elif action == 'callback': | 853 elif action == 'callback': |
828 optdict['callback'](None, opt, value, None) | 854 optdict['callback'](None, opt, value, None) |
829 else: | 855 else: |
830 raise UnsupportedAction(action) | 856 raise UnsupportedAction(action) |
831 | 857 |
832 def input_option(self, option, optdict, inputlevel=99): | 858 def input_option(self, option, optdict, inputlevel=99): |
833 default = self.option_default(option, optdict) | 859 default = self.option_default(option, optdict) |
834 if default is REQUIRED: | 860 if default is REQUIRED: |
835 defaultstr = '(required): ' | 861 defaultstr = '(required): ' |
836 elif optdict.get('level', 0) > inputlevel: | 862 elif optdict.get('level', 0) > inputlevel: |
837 return | 863 return |
838 elif optdict['type'] == 'password' or default is None: | 864 elif optdict['type'] == 'password' or default is None: |
839 defaultstr = ': ' | 865 defaultstr = ': ' |
840 else: | 866 else: |
841 defaultstr = '(default: %s): ' % format_option_value(optdict, defaul
t) | 867 defaultstr = '(default: %s): ' % format_option_value(optdict, defaul
t) |
842 print ':%s:' % option | 868 print(':%s:' % option) |
843 print optdict.get('help') or option | 869 print(optdict.get('help') or option) |
844 inputfunc = INPUT_FUNCTIONS[optdict['type']] | 870 inputfunc = INPUT_FUNCTIONS[optdict['type']] |
845 value = inputfunc(optdict, defaultstr) | 871 value = inputfunc(optdict, defaultstr) |
846 while default is REQUIRED and not value: | 872 while default is REQUIRED and not value: |
847 print 'please specify a value' | 873 print('please specify a value') |
848 value = inputfunc(optdict, '%s: ' % option) | 874 value = inputfunc(optdict, '%s: ' % option) |
849 if value is None and default is not None: | 875 if value is None and default is not None: |
850 value = default | 876 value = default |
851 self.set_option(option, value, optdict=optdict) | 877 self.set_option(option, value, optdict=optdict) |
852 | 878 |
853 def get_option_def(self, opt): | 879 def get_option_def(self, opt): |
854 """return the dictionary defining an option given it's name""" | 880 """return the dictionary defining an option given it's name""" |
855 assert self.options | 881 assert self.options |
856 for option in self.options: | 882 for option in self.options: |
857 if option[0] == opt: | 883 if option[0] == opt: |
(...skipping 28 matching lines...) Expand all Loading... |
886 yield None, sections.pop(None) | 912 yield None, sections.pop(None) |
887 for section, options in sections.items(): | 913 for section, options in sections.items(): |
888 yield section.upper(), options | 914 yield section.upper(), options |
889 | 915 |
890 def options_and_values(self, options=None): | 916 def options_and_values(self, options=None): |
891 if options is None: | 917 if options is None: |
892 options = self.options | 918 options = self.options |
893 for optname, optdict in options: | 919 for optname, optdict in options: |
894 yield (optname, optdict, self.option_value(optname)) | 920 yield (optname, optdict, self.option_value(optname)) |
895 | 921 |
| 922 # configuration ################################################################ |
896 | 923 |
897 class ConfigurationMixIn(OptionsManagerMixIn, OptionsProviderMixIn): | 924 class ConfigurationMixIn(OptionsManagerMixIn, OptionsProviderMixIn): |
898 """basic mixin for simple configurations which don't need the | 925 """basic mixin for simple configurations which don't need the |
899 manager / providers model | 926 manager / providers model |
900 """ | 927 """ |
901 def __init__(self, *args, **kwargs): | 928 def __init__(self, *args, **kwargs): |
902 if not args: | 929 if not args: |
903 kwargs.setdefault('usage', '') | 930 kwargs.setdefault('usage', '') |
904 kwargs.setdefault('quiet', 1) | 931 kwargs.setdefault('quiet', 1) |
905 OptionsManagerMixIn.__init__(self, *args, **kwargs) | 932 OptionsManagerMixIn.__init__(self, *args, **kwargs) |
906 OptionsProviderMixIn.__init__(self) | 933 OptionsProviderMixIn.__init__(self) |
907 if not getattr(self, 'option_groups', None): | 934 if not getattr(self, 'option_groups', None): |
908 self.option_groups = [] | 935 self.option_groups = [] |
909 for option, optdict in self.options: | 936 for option, optdict in self.options: |
910 try: | 937 try: |
911 gdef = (optdict['group'].upper(), '') | 938 gdef = (optdict['group'].upper(), '') |
912 except KeyError: | 939 except KeyError: |
913 continue | 940 continue |
914 if not gdef in self.option_groups: | 941 if not gdef in self.option_groups: |
915 self.option_groups.append(gdef) | 942 self.option_groups.append(gdef) |
916 self.register_options_provider(self, own_group=0) | 943 self.register_options_provider(self, own_group=False) |
917 | 944 |
918 def register_options(self, options): | 945 def register_options(self, options): |
919 """add some options to the configuration""" | 946 """add some options to the configuration""" |
920 options_by_group = {} | 947 options_by_group = {} |
921 for optname, optdict in options: | 948 for optname, optdict in options: |
922 options_by_group.setdefault(optdict.get('group', self.name.upper()),
[]).append((optname, optdict)) | 949 options_by_group.setdefault(optdict.get('group', self.name.upper()),
[]).append((optname, optdict)) |
923 for group, options in options_by_group.items(): | 950 for group, options in options_by_group.items(): |
924 self.add_option_group(group, None, options, self) | 951 self.add_option_group(group, None, options, self) |
925 self.options += tuple(options) | 952 self.options += tuple(options) |
926 | 953 |
927 def load_defaults(self): | 954 def load_defaults(self): |
928 OptionsProviderMixIn.load_defaults(self) | 955 OptionsProviderMixIn.load_defaults(self) |
929 | 956 |
930 def __iter__(self): | 957 def __iter__(self): |
931 return iter(self.config.__dict__.iteritems()) | 958 return iter(self.config.__dict__.iteritems()) |
932 | 959 |
933 def __getitem__(self, key): | 960 def __getitem__(self, key): |
934 try: | 961 try: |
935 return getattr(self.config, self.option_name(key)) | 962 return getattr(self.config, self.option_attrname(key)) |
936 except (optparse.OptionValueError, AttributeError): | 963 except (optik_ext.OptionValueError, AttributeError): |
937 raise KeyError(key) | 964 raise KeyError(key) |
938 | 965 |
939 def __setitem__(self, key, value): | 966 def __setitem__(self, key, value): |
940 self.set_option(key, value) | 967 self.set_option(key, value) |
941 | 968 |
942 def get(self, key, default=None): | 969 def get(self, key, default=None): |
943 try: | 970 try: |
944 return getattr(self.config, self.option_name(key)) | 971 return getattr(self.config, self.option_attrname(key)) |
945 except (OptionError, AttributeError): | 972 except (OptionError, AttributeError): |
946 return default | 973 return default |
947 | 974 |
948 | 975 |
949 class Configuration(ConfigurationMixIn): | 976 class Configuration(ConfigurationMixIn): |
950 """class for simple configurations which don't need the | 977 """class for simple configurations which don't need the |
951 manager / providers model and prefer delegation to inheritance | 978 manager / providers model and prefer delegation to inheritance |
952 | 979 |
953 configuration values are accessible through a dict like interface | 980 configuration values are accessible through a dict like interface |
954 """ | 981 """ |
(...skipping 15 matching lines...) Expand all Loading... |
970 """ | 997 """ |
971 def __init__(self, provider): | 998 def __init__(self, provider): |
972 self.config = provider | 999 self.config = provider |
973 | 1000 |
974 def __getattr__(self, key): | 1001 def __getattr__(self, key): |
975 return getattr(self.config, key) | 1002 return getattr(self.config, key) |
976 | 1003 |
977 def __getitem__(self, key): | 1004 def __getitem__(self, key): |
978 provider = self.config._all_options[key] | 1005 provider = self.config._all_options[key] |
979 try: | 1006 try: |
980 return getattr(provider.config, provider.option_name(key)) | 1007 return getattr(provider.config, provider.option_attrname(key)) |
981 except AttributeError: | 1008 except AttributeError: |
982 raise KeyError(key) | 1009 raise KeyError(key) |
983 | 1010 |
984 def __setitem__(self, key, value): | 1011 def __setitem__(self, key, value): |
985 self.config.global_set_option(self.config.option_name(key), value) | 1012 self.config.global_set_option(self.config.option_attrname(key), value) |
986 | 1013 |
987 def get(self, key, default=None): | 1014 def get(self, key, default=None): |
988 provider = self.config._all_options[key] | 1015 provider = self.config._all_options[key] |
989 try: | 1016 try: |
990 return getattr(provider.config, provider.option_name(key)) | 1017 return getattr(provider.config, provider.option_attrname(key)) |
991 except AttributeError: | 1018 except AttributeError: |
992 return default | 1019 return default |
993 | 1020 |
| 1021 # other functions ############################################################## |
994 | 1022 |
995 def read_old_config(newconfig, changes, configfile): | 1023 def read_old_config(newconfig, changes, configfile): |
996 """initialize newconfig from a deprecated configuration file | 1024 """initialize newconfig from a deprecated configuration file |
997 | 1025 |
998 possible changes: | 1026 possible changes: |
999 * ('renamed', oldname, newname) | 1027 * ('renamed', oldname, newname) |
1000 * ('moved', option, oldgroup, newgroup) | 1028 * ('moved', option, oldgroup, newgroup) |
1001 * ('typechanged', option, oldtype, newvalue) | 1029 * ('typechanged', option, oldtype, newvalue) |
1002 """ | 1030 """ |
1003 # build an index of changes | 1031 # build an index of changes |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1048 done.add(newname) | 1076 done.add(newname) |
1049 elif action[0] == 'typechanged': | 1077 elif action[0] == 'typechanged': |
1050 optname, oldtype, newvalue = action[1:] | 1078 optname, oldtype, newvalue = action[1:] |
1051 newconfig[optname] = newvalue | 1079 newconfig[optname] = newvalue |
1052 done.add(optname) | 1080 done.add(optname) |
1053 for optname, optdef in newconfig.options: | 1081 for optname, optdef in newconfig.options: |
1054 if optdef.get('type') and not optname in done: | 1082 if optdef.get('type') and not optname in done: |
1055 newconfig.set_option(optname, oldconfig[optname], optdict=optdef) | 1083 newconfig.set_option(optname, oldconfig[optname], optdict=optdef) |
1056 | 1084 |
1057 | 1085 |
1058 def merge_options(options): | 1086 def merge_options(options, optgroup=None): |
1059 """preprocess options to remove duplicate""" | 1087 """preprocess a list of options and remove duplicates, returning a new list |
| 1088 (tuple actually) of options. |
| 1089 |
| 1090 Options dictionaries are copied to avoid later side-effect. Also, if |
| 1091 `otpgroup` argument is specified, ensure all options are in the given group. |
| 1092 """ |
1060 alloptions = {} | 1093 alloptions = {} |
1061 options = list(options) | 1094 options = list(options) |
1062 for i in range(len(options)-1, -1, -1): | 1095 for i in range(len(options)-1, -1, -1): |
1063 optname, optdict = options[i] | 1096 optname, optdict = options[i] |
1064 if optname in alloptions: | 1097 if optname in alloptions: |
1065 options.pop(i) | 1098 options.pop(i) |
1066 alloptions[optname].update(optdict) | 1099 alloptions[optname].update(optdict) |
1067 else: | 1100 else: |
| 1101 optdict = optdict.copy() |
| 1102 options[i] = (optname, optdict) |
1068 alloptions[optname] = optdict | 1103 alloptions[optname] = optdict |
| 1104 if optgroup is not None: |
| 1105 alloptions[optname]['group'] = optgroup |
1069 return tuple(options) | 1106 return tuple(options) |
OLD | NEW |