Index: third_party/logilab/common/configuration.py |
diff --git a/third_party/logilab/common/configuration.py b/third_party/logilab/common/configuration.py |
index 1371c76d3bb5711a493e40c417200f70d8f49583..0eafa10a07da917e074e49b34630b94545082d8f 100644 |
--- a/third_party/logilab/common/configuration.py |
+++ b/third_party/logilab/common/configuration.py |
@@ -1,4 +1,4 @@ |
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
# |
# This file is part of logilab-common. |
@@ -96,19 +96,8 @@ Quick start: simplest usage |
multiple=4,5,6 |
number=3 |
- |
- Note : starting with Python 2.7 ConfigParser is able to take into |
- account the order of occurrences of the options into a file (by |
- using an OrderedDict). If you have two options changing some common |
- state, like a 'disable-all-stuff' and a 'enable-some-stuff-a', their |
- order of appearance will be significant : the last specified in the |
- file wins. For earlier version of python and logilab.common newer |
- than 0.61 the behaviour is unspecified. |
- |
+ >>> |
""" |
- |
-from __future__ import print_function |
- |
__docformat__ = "restructuredtext en" |
__all__ = ('OptionsManagerMixIn', 'OptionsProviderMixIn', |
@@ -120,17 +109,16 @@ import sys |
import re |
from os.path import exists, expanduser |
from copy import copy |
+from ConfigParser import ConfigParser, NoOptionError, NoSectionError, \ |
+ DuplicateSectionError |
from warnings import warn |
-from six import string_types |
-from six.moves import range, configparser as cp, input |
+from logilab.common.compat import callable, raw_input, str_encode as _encode |
-from logilab.common.compat import str_encode as _encode |
-from logilab.common.deprecation import deprecated |
from logilab.common.textutils import normalize_text, unquote |
-from logilab.common import optik_ext |
+from logilab.common import optik_ext as optparse |
-OptionError = optik_ext.OptionError |
+OptionError = optparse.OptionError |
REQUIRED = [] |
@@ -148,66 +136,63 @@ def _get_encoding(encoding, stream): |
# validation functions ######################################################## |
-# validators will return the validated value or raise optparse.OptionValueError |
-# XXX add to documentation |
- |
def choice_validator(optdict, name, value): |
"""validate and return a converted value for option of type 'choice' |
""" |
if not value in optdict['choices']: |
msg = "option %s: invalid value: %r, should be in %s" |
- raise optik_ext.OptionValueError(msg % (name, value, optdict['choices'])) |
+ raise optparse.OptionValueError(msg % (name, value, optdict['choices'])) |
return value |
def multiple_choice_validator(optdict, name, value): |
"""validate and return a converted value for option of type 'choice' |
""" |
choices = optdict['choices'] |
- values = optik_ext.check_csv(None, name, value) |
+ values = optparse.check_csv(None, name, value) |
for value in values: |
if not value in choices: |
msg = "option %s: invalid value: %r, should be in %s" |
- raise optik_ext.OptionValueError(msg % (name, value, choices)) |
+ raise optparse.OptionValueError(msg % (name, value, choices)) |
return values |
def csv_validator(optdict, name, value): |
"""validate and return a converted value for option of type 'csv' |
""" |
- return optik_ext.check_csv(None, name, value) |
+ return optparse.check_csv(None, name, value) |
def yn_validator(optdict, name, value): |
"""validate and return a converted value for option of type 'yn' |
""" |
- return optik_ext.check_yn(None, name, value) |
+ return optparse.check_yn(None, name, value) |
def named_validator(optdict, name, value): |
"""validate and return a converted value for option of type 'named' |
""" |
- return optik_ext.check_named(None, name, value) |
+ return optparse.check_named(None, name, value) |
def file_validator(optdict, name, value): |
"""validate and return a filepath for option of type 'file'""" |
- return optik_ext.check_file(None, name, value) |
+ return optparse.check_file(None, name, value) |
def color_validator(optdict, name, value): |
"""validate and return a valid color for option of type 'color'""" |
- return optik_ext.check_color(None, name, value) |
+ return optparse.check_color(None, name, value) |
def password_validator(optdict, name, value): |
"""validate and return a string for option of type 'password'""" |
- return optik_ext.check_password(None, name, value) |
+ return optparse.check_password(None, name, value) |
def date_validator(optdict, name, value): |
"""validate and return a mx DateTime object for option of type 'date'""" |
- return optik_ext.check_date(None, name, value) |
+ return optparse.check_date(None, name, value) |
def time_validator(optdict, name, value): |
"""validate and return a time object for option of type 'time'""" |
- return optik_ext.check_time(None, name, value) |
+ return optparse.check_time(None, name, value) |
def bytes_validator(optdict, name, value): |
"""validate and return an integer for option of type 'bytes'""" |
- return optik_ext.check_bytes(None, name, value) |
+ return optparse.check_bytes(None, name, value) |
VALIDATORS = {'string': unquote, |
@@ -237,18 +222,14 @@ def _call_validator(opttype, optdict, option, value): |
except TypeError: |
try: |
return VALIDATORS[opttype](value) |
- except optik_ext.OptionValueError: |
+ except optparse.OptionValueError: |
raise |
except: |
- raise optik_ext.OptionValueError('%s value (%r) should be of type %s' % |
+ raise optparse.OptionValueError('%s value (%r) should be of type %s' % |
(option, value, opttype)) |
# user input functions ######################################################## |
-# user input functions will ask the user for input on stdin then validate |
-# the result and return the validated value or raise optparse.OptionValueError |
-# XXX add to documentation |
- |
def input_password(optdict, question='password:'): |
from getpass import getpass |
while True: |
@@ -256,23 +237,23 @@ def input_password(optdict, question='password:'): |
value2 = getpass('confirm: ') |
if value == value2: |
return value |
- print('password mismatch, try again') |
+ print 'password mismatch, try again' |
def input_string(optdict, question): |
- value = input(question).strip() |
+ value = raw_input(question).strip() |
return value or None |
def _make_input_function(opttype): |
def input_validator(optdict, question): |
while True: |
- value = input(question) |
+ value = raw_input(question) |
if not value.strip(): |
return None |
try: |
return _call_validator(opttype, optdict, None, value) |
- except optik_ext.OptionValueError as ex: |
+ except optparse.OptionValueError, ex: |
msg = str(ex).split(':', 1)[-1].strip() |
- print('bad value: %s' % msg) |
+ print 'bad value: %s' % msg |
return input_validator |
INPUT_FUNCTIONS = { |
@@ -283,8 +264,6 @@ INPUT_FUNCTIONS = { |
for opttype in VALIDATORS.keys(): |
INPUT_FUNCTIONS.setdefault(opttype, _make_input_function(opttype)) |
-# utility functions ############################################################ |
- |
def expand_default(self, option): |
"""monkey patch OptionParser.expand_default since we have a particular |
way to handle defaults to avoid overriding values in the configuration |
@@ -299,15 +278,15 @@ def expand_default(self, option): |
value = None |
else: |
optdict = provider.get_option_def(optname) |
- optname = provider.option_attrname(optname, optdict) |
+ optname = provider.option_name(optname, optdict) |
value = getattr(provider.config, optname, optdict) |
value = format_option_value(optdict, value) |
- if value is optik_ext.NO_DEFAULT or not value: |
+ if value is optparse.NO_DEFAULT or not value: |
value = self.NO_DEFAULT_VALUE |
return option.help.replace(self.default_tag, str(value)) |
-def _validate(value, optdict, name=''): |
+def convert(value, optdict, name=''): |
"""return a validated value for an option according to its type |
optional argument name is only used for error message formatting |
@@ -318,9 +297,6 @@ def _validate(value, optdict, name=''): |
# FIXME |
return value |
return _call_validator(_type, optdict, name, value) |
-convert = deprecated('[0.60] convert() was renamed _validate()')(_validate) |
- |
-# format and output functions ################################################## |
def comment(string): |
"""return string as a comment""" |
@@ -370,7 +346,7 @@ def format_option_value(optdict, value): |
value = value.pattern |
elif optdict.get('type') == 'yn': |
value = value and 'yes' or 'no' |
- elif isinstance(value, string_types) and value.isspace(): |
+ elif isinstance(value, (str, unicode)) and value.isspace(): |
value = "'%s'" % value |
elif optdict.get('type') == 'time' and isinstance(value, (float, int, long)): |
value = format_time(value) |
@@ -382,8 +358,8 @@ def ini_format_section(stream, section, options, encoding=None, doc=None): |
"""format an options section using the INI format""" |
encoding = _get_encoding(encoding, stream) |
if doc: |
- print(_encode(comment(doc), encoding), file=stream) |
- print('[%s]' % section, file=stream) |
+ print >> stream, _encode(comment(doc), encoding) |
+ print >> stream, '[%s]' % section |
ini_format(stream, options, encoding) |
def ini_format(stream, options, encoding): |
@@ -393,20 +369,20 @@ def ini_format(stream, options, encoding): |
help = optdict.get('help') |
if help: |
help = normalize_text(help, line_len=79, indent='# ') |
- print(file=stream) |
- print(_encode(help, encoding), file=stream) |
+ print >> stream |
+ print >> stream, _encode(help, encoding) |
else: |
- print(file=stream) |
+ print >> stream |
if value is None: |
- print('#%s=' % optname, file=stream) |
+ print >> stream, '#%s=' % optname |
else: |
value = _encode(value, encoding).strip() |
- print('%s=%s' % (optname, value), file=stream) |
+ print >> stream, '%s=%s' % (optname, value) |
format_section = ini_format_section |
def rest_format_section(stream, section, options, encoding=None, doc=None): |
- """format an options section using as ReST formatted output""" |
+ """format an options section using the INI format""" |
encoding = _get_encoding(encoding, stream) |
if section: |
print >> stream, '%s\n%s' % (section, "'"*len(section)) |
@@ -425,7 +401,6 @@ def rest_format_section(stream, section, options, encoding=None, doc=None): |
print >> stream, '' |
print >> stream, ' Default: ``%s``' % value.replace("`` ", "```` ``") |
-# Options Manager ############################################################## |
class OptionsManagerMixIn(object): |
"""MixIn to handle a configuration from both a configuration file and |
@@ -448,9 +423,9 @@ class OptionsManagerMixIn(object): |
def reset_parsers(self, usage='', version=None): |
# configuration file parser |
- self.cfgfile_parser = cp.ConfigParser() |
+ self.cfgfile_parser = ConfigParser() |
# command line parser |
- self.cmdline_parser = optik_ext.OptionParser(usage=usage, version=version) |
+ self.cmdline_parser = optparse.OptionParser(usage=usage, version=version) |
self.cmdline_parser.options_manager = self |
self._optik_option_attrs = set(self.cmdline_parser.option_class.ATTRS) |
@@ -486,7 +461,7 @@ class OptionsManagerMixIn(object): |
if group_name in self._mygroups: |
group = self._mygroups[group_name] |
else: |
- group = optik_ext.OptionGroup(self.cmdline_parser, |
+ group = optparse.OptionGroup(self.cmdline_parser, |
title=group_name.capitalize()) |
self.cmdline_parser.add_option_group(group) |
group.level = provider.level |
@@ -522,9 +497,9 @@ class OptionsManagerMixIn(object): |
# default is handled here and *must not* be given to optik if you |
# want the whole machinery to work |
if 'default' in optdict: |
- if ('help' in optdict |
- and optdict.get('default') is not None |
- and not optdict['action'] in ('store_true', 'store_false')): |
+ if (optparse.OPTPARSE_FORMAT_DEFAULT and 'help' in optdict and |
+ optdict.get('default') is not None and |
+ not optdict['action'] in ('store_true', 'store_false')): |
optdict['help'] += ' [current: %default]' |
del optdict['default'] |
args = ['--' + str(opt)] |
@@ -533,7 +508,7 @@ class OptionsManagerMixIn(object): |
args.append('-' + optdict['short']) |
del optdict['short'] |
# cleanup option definition dict before giving it to optik |
- for key in list(optdict.keys()): |
+ for key in optdict.keys(): |
if not key in self._optik_option_attrs: |
optdict.pop(key) |
return args, optdict |
@@ -580,7 +555,7 @@ class OptionsManagerMixIn(object): |
printed = False |
for section in sections: |
if printed: |
- print('\n', file=stream) |
+ print >> stream, '\n' |
format_section(stream, section.upper(), options_by_section[section], |
encoding) |
printed = True |
@@ -591,7 +566,7 @@ class OptionsManagerMixIn(object): |
""" |
self._monkeypatch_expand_default() |
try: |
- optik_ext.generate_manpage(self.cmdline_parser, pkginfo, |
+ optparse.generate_manpage(self.cmdline_parser, pkginfo, |
section, stream=stream or sys.stdout, |
level=self._maxlevel) |
finally: |
@@ -619,7 +594,7 @@ class OptionsManagerMixIn(object): |
if opt in self._all_options: |
break # already processed |
def helpfunc(option, opt, val, p, level=helplevel): |
- print(self.help(level)) |
+ print self.help(level) |
sys.exit(0) |
helpmsg = '%s verbose help.' % ' '.join(['more'] * helplevel) |
optdict = {'action' : 'callback', 'callback' : helpfunc, |
@@ -641,7 +616,7 @@ class OptionsManagerMixIn(object): |
parser._sections[sect.upper()] = values |
elif not self.quiet: |
msg = 'No config file found, using default configuration' |
- print(msg, file=sys.stderr) |
+ print >> sys.stderr, msg |
return |
def input_config(self, onlysection=None, inputlevel=0, stream=None): |
@@ -667,13 +642,13 @@ class OptionsManagerMixIn(object): |
options provider) |
""" |
parser = self.cfgfile_parser |
- for section in parser.sections(): |
- for option, value in parser.items(section): |
- try: |
- self.global_set_option(option, value) |
- except (KeyError, OptionError): |
- # TODO handle here undeclared options appearing in the config file |
- continue |
+ for provider in self.options_providers: |
+ for section, option, optdict in provider.all_options(): |
+ try: |
+ value = parser.get(section, option) |
+ provider.set_option(option, value, optdict=optdict) |
+ except (NoSectionError, NoOptionError), ex: |
+ continue |
def load_configuration(self, **kwargs): |
"""override configuration according to given parameters |
@@ -711,7 +686,7 @@ class OptionsManagerMixIn(object): |
def add_help_section(self, title, description, level=0): |
"""add a dummy option section for help purpose """ |
- group = optik_ext.OptionGroup(self.cmdline_parser, |
+ group = optparse.OptionGroup(self.cmdline_parser, |
title=title.capitalize(), |
description=description) |
group.level = level |
@@ -719,18 +694,18 @@ class OptionsManagerMixIn(object): |
self.cmdline_parser.add_option_group(group) |
def _monkeypatch_expand_default(self): |
- # monkey patch optik_ext to deal with our default values |
+ # monkey patch optparse to deal with our default values |
try: |
- self.__expand_default_backup = optik_ext.HelpFormatter.expand_default |
- optik_ext.HelpFormatter.expand_default = expand_default |
+ self.__expand_default_backup = optparse.HelpFormatter.expand_default |
+ optparse.HelpFormatter.expand_default = expand_default |
except AttributeError: |
# python < 2.4: nothing to be done |
pass |
def _unmonkeypatch_expand_default(self): |
# remove monkey patch |
- if hasattr(optik_ext.HelpFormatter, 'expand_default'): |
- # unpatch optik_ext to avoid side effects |
- optik_ext.HelpFormatter.expand_default = self.__expand_default_backup |
+ if hasattr(optparse.HelpFormatter, 'expand_default'): |
+ # unpatch optparse to avoid side effects |
+ optparse.HelpFormatter.expand_default = self.__expand_default_backup |
def help(self, level=0): |
"""return the usage string for available options """ |
@@ -759,7 +734,6 @@ class Method(object): |
assert self._inst, 'unbound method' |
return getattr(self._inst, self.method)(*args, **kwargs) |
-# Options Provider ############################################################# |
class OptionsProviderMixIn(object): |
"""Mixin to provide options to an OptionsManager""" |
@@ -771,7 +745,7 @@ class OptionsProviderMixIn(object): |
level = 0 |
def __init__(self): |
- self.config = optik_ext.Values() |
+ self.config = optparse.Values() |
for option in self.options: |
try: |
option, optdict = option |
@@ -803,41 +777,41 @@ class OptionsProviderMixIn(object): |
default = default() |
return default |
- def option_attrname(self, opt, optdict=None): |
+ def option_name(self, opt, optdict=None): |
"""get the config attribute corresponding to opt |
""" |
if optdict is None: |
optdict = self.get_option_def(opt) |
return optdict.get('dest', opt.replace('-', '_')) |
- option_name = deprecated('[0.60] OptionsProviderMixIn.option_name() was renamed to option_attrname()')(option_attrname) |
def option_value(self, opt): |
"""get the current value for the given option""" |
- return getattr(self.config, self.option_attrname(opt), None) |
+ return getattr(self.config, self.option_name(opt), None) |
def set_option(self, opt, value, action=None, optdict=None): |
"""method called to set an option (registered in the options list) |
""" |
+ # print "************ setting option", opt," to value", value |
if optdict is None: |
optdict = self.get_option_def(opt) |
if value is not None: |
- value = _validate(value, optdict, opt) |
+ value = convert(value, optdict, opt) |
if action is None: |
action = optdict.get('action', 'store') |
if optdict.get('type') == 'named': # XXX need specific handling |
- optname = self.option_attrname(opt, optdict) |
+ optname = self.option_name(opt, optdict) |
currentvalue = getattr(self.config, optname, None) |
if currentvalue: |
currentvalue.update(value) |
value = currentvalue |
if action == 'store': |
- setattr(self.config, self.option_attrname(opt, optdict), value) |
+ setattr(self.config, self.option_name(opt, optdict), value) |
elif action in ('store_true', 'count'): |
- setattr(self.config, self.option_attrname(opt, optdict), 0) |
+ setattr(self.config, self.option_name(opt, optdict), 0) |
elif action == 'store_false': |
- setattr(self.config, self.option_attrname(opt, optdict), 1) |
+ setattr(self.config, self.option_name(opt, optdict), 1) |
elif action == 'append': |
- opt = self.option_attrname(opt, optdict) |
+ opt = self.option_name(opt, optdict) |
_list = getattr(self.config, opt, None) |
if _list is None: |
if isinstance(value, (list, tuple)): |
@@ -865,12 +839,12 @@ class OptionsProviderMixIn(object): |
defaultstr = ': ' |
else: |
defaultstr = '(default: %s): ' % format_option_value(optdict, default) |
- print(':%s:' % option) |
- print(optdict.get('help') or option) |
+ print ':%s:' % option |
+ print optdict.get('help') or option |
inputfunc = INPUT_FUNCTIONS[optdict['type']] |
value = inputfunc(optdict, defaultstr) |
while default is REQUIRED and not value: |
- print('please specify a value') |
+ print 'please specify a value' |
value = inputfunc(optdict, '%s: ' % option) |
if value is None and default is not None: |
value = default |
@@ -919,7 +893,6 @@ class OptionsProviderMixIn(object): |
for optname, optdict in options: |
yield (optname, optdict, self.option_value(optname)) |
-# configuration ################################################################ |
class ConfigurationMixIn(OptionsManagerMixIn, OptionsProviderMixIn): |
"""basic mixin for simple configurations which don't need the |
@@ -940,7 +913,7 @@ class ConfigurationMixIn(OptionsManagerMixIn, OptionsProviderMixIn): |
continue |
if not gdef in self.option_groups: |
self.option_groups.append(gdef) |
- self.register_options_provider(self, own_group=False) |
+ self.register_options_provider(self, own_group=0) |
def register_options(self, options): |
"""add some options to the configuration""" |
@@ -959,8 +932,8 @@ class ConfigurationMixIn(OptionsManagerMixIn, OptionsProviderMixIn): |
def __getitem__(self, key): |
try: |
- return getattr(self.config, self.option_attrname(key)) |
- except (optik_ext.OptionValueError, AttributeError): |
+ return getattr(self.config, self.option_name(key)) |
+ except (optparse.OptionValueError, AttributeError): |
raise KeyError(key) |
def __setitem__(self, key, value): |
@@ -968,7 +941,7 @@ class ConfigurationMixIn(OptionsManagerMixIn, OptionsProviderMixIn): |
def get(self, key, default=None): |
try: |
- return getattr(self.config, self.option_attrname(key)) |
+ return getattr(self.config, self.option_name(key)) |
except (OptionError, AttributeError): |
return default |
@@ -1004,21 +977,20 @@ class OptionsManager2ConfigurationAdapter(object): |
def __getitem__(self, key): |
provider = self.config._all_options[key] |
try: |
- return getattr(provider.config, provider.option_attrname(key)) |
+ return getattr(provider.config, provider.option_name(key)) |
except AttributeError: |
raise KeyError(key) |
def __setitem__(self, key, value): |
- self.config.global_set_option(self.config.option_attrname(key), value) |
+ self.config.global_set_option(self.config.option_name(key), value) |
def get(self, key, default=None): |
provider = self.config._all_options[key] |
try: |
- return getattr(provider.config, provider.option_attrname(key)) |
+ return getattr(provider.config, provider.option_name(key)) |
except AttributeError: |
return default |
-# other functions ############################################################## |
def read_old_config(newconfig, changes, configfile): |
"""initialize newconfig from a deprecated configuration file |
@@ -1083,13 +1055,8 @@ def read_old_config(newconfig, changes, configfile): |
newconfig.set_option(optname, oldconfig[optname], optdict=optdef) |
-def merge_options(options, optgroup=None): |
- """preprocess a list of options and remove duplicates, returning a new list |
- (tuple actually) of options. |
- |
- Options dictionaries are copied to avoid later side-effect. Also, if |
- `otpgroup` argument is specified, ensure all options are in the given group. |
- """ |
+def merge_options(options): |
+ """preprocess options to remove duplicate""" |
alloptions = {} |
options = list(options) |
for i in range(len(options)-1, -1, -1): |
@@ -1098,9 +1065,5 @@ def merge_options(options, optgroup=None): |
options.pop(i) |
alloptions[optname].update(optdict) |
else: |
- optdict = optdict.copy() |
- options[i] = (optname, optdict) |
alloptions[optname] = optdict |
- if optgroup is not None: |
- alloptions[optname]['group'] = optgroup |
return tuple(options) |