Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1215)

Unified Diff: third_party/logilab/common/configuration.py

Issue 739393004: Revert "Revert "pylint: upgrade to 1.3.1"" (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools/
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/logilab/common/compat.py ('k') | third_party/logilab/common/corbautils.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/logilab/common/configuration.py
===================================================================
--- third_party/logilab/common/configuration.py (revision 293047)
+++ third_party/logilab/common/configuration.py (working copy)
@@ -1,4 +1,4 @@
-# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2012 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,8 +96,19 @@
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',
@@ -109,16 +120,17 @@
import re
from os.path import exists, expanduser
from copy import copy
-from ConfigParser import ConfigParser, NoOptionError, NoSectionError, \
- DuplicateSectionError
from warnings import warn
-from logilab.common.compat import callable, raw_input, str_encode as _encode
+from six import string_types
+from six.moves import range, configparser as cp, input
+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 as optparse
+from logilab.common import optik_ext
-OptionError = optparse.OptionError
+OptionError = optik_ext.OptionError
REQUIRED = []
@@ -136,12 +148,15 @@
# 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 optparse.OptionValueError(msg % (name, value, optdict['choices']))
+ raise optik_ext.OptionValueError(msg % (name, value, optdict['choices']))
return value
def multiple_choice_validator(optdict, name, value):
@@ -148,51 +163,51 @@
"""validate and return a converted value for option of type 'choice'
"""
choices = optdict['choices']
- values = optparse.check_csv(None, name, value)
+ values = optik_ext.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 optparse.OptionValueError(msg % (name, value, choices))
+ raise optik_ext.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 optparse.check_csv(None, name, value)
+ return optik_ext.check_csv(None, name, value)
def yn_validator(optdict, name, value):
"""validate and return a converted value for option of type 'yn'
"""
- return optparse.check_yn(None, name, value)
+ return optik_ext.check_yn(None, name, value)
def named_validator(optdict, name, value):
"""validate and return a converted value for option of type 'named'
"""
- return optparse.check_named(None, name, value)
+ return optik_ext.check_named(None, name, value)
def file_validator(optdict, name, value):
"""validate and return a filepath for option of type 'file'"""
- return optparse.check_file(None, name, value)
+ return optik_ext.check_file(None, name, value)
def color_validator(optdict, name, value):
"""validate and return a valid color for option of type 'color'"""
- return optparse.check_color(None, name, value)
+ return optik_ext.check_color(None, name, value)
def password_validator(optdict, name, value):
"""validate and return a string for option of type 'password'"""
- return optparse.check_password(None, name, value)
+ return optik_ext.check_password(None, name, value)
def date_validator(optdict, name, value):
"""validate and return a mx DateTime object for option of type 'date'"""
- return optparse.check_date(None, name, value)
+ return optik_ext.check_date(None, name, value)
def time_validator(optdict, name, value):
"""validate and return a time object for option of type 'time'"""
- return optparse.check_time(None, name, value)
+ return optik_ext.check_time(None, name, value)
def bytes_validator(optdict, name, value):
"""validate and return an integer for option of type 'bytes'"""
- return optparse.check_bytes(None, name, value)
+ return optik_ext.check_bytes(None, name, value)
VALIDATORS = {'string': unquote,
@@ -222,14 +237,18 @@
except TypeError:
try:
return VALIDATORS[opttype](value)
- except optparse.OptionValueError:
+ except optik_ext.OptionValueError:
raise
except:
- raise optparse.OptionValueError('%s value (%r) should be of type %s' %
+ raise optik_ext.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:
@@ -237,23 +256,23 @@
value2 = getpass('confirm: ')
if value == value2:
return value
- print 'password mismatch, try again'
+ print('password mismatch, try again')
def input_string(optdict, question):
- value = raw_input(question).strip()
+ value = input(question).strip()
return value or None
def _make_input_function(opttype):
def input_validator(optdict, question):
while True:
- value = raw_input(question)
+ value = input(question)
if not value.strip():
return None
try:
return _call_validator(opttype, optdict, None, value)
- except optparse.OptionValueError, ex:
+ except optik_ext.OptionValueError as ex:
msg = str(ex).split(':', 1)[-1].strip()
- print 'bad value: %s' % msg
+ print('bad value: %s' % msg)
return input_validator
INPUT_FUNCTIONS = {
@@ -264,6 +283,8 @@
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
@@ -278,15 +299,15 @@
value = None
else:
optdict = provider.get_option_def(optname)
- optname = provider.option_name(optname, optdict)
+ optname = provider.option_attrname(optname, optdict)
value = getattr(provider.config, optname, optdict)
value = format_option_value(optdict, value)
- if value is optparse.NO_DEFAULT or not value:
+ if value is optik_ext.NO_DEFAULT or not value:
value = self.NO_DEFAULT_VALUE
return option.help.replace(self.default_tag, str(value))
-def convert(value, optdict, name=''):
+def _validate(value, optdict, name=''):
"""return a validated value for an option according to its type
optional argument name is only used for error message formatting
@@ -297,7 +318,10 @@
# 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"""
lines = [line.strip() for line in string.splitlines()]
@@ -346,7 +370,7 @@
value = value.pattern
elif optdict.get('type') == 'yn':
value = value and 'yes' or 'no'
- elif isinstance(value, (str, unicode)) and value.isspace():
+ elif isinstance(value, string_types) and value.isspace():
value = "'%s'" % value
elif optdict.get('type') == 'time' and isinstance(value, (float, int, long)):
value = format_time(value)
@@ -358,8 +382,8 @@
"""format an options section using the INI format"""
encoding = _get_encoding(encoding, stream)
if doc:
- print >> stream, _encode(comment(doc), encoding)
- print >> stream, '[%s]' % section
+ print(_encode(comment(doc), encoding), file=stream)
+ print('[%s]' % section, file=stream)
ini_format(stream, options, encoding)
def ini_format(stream, options, encoding):
@@ -369,20 +393,20 @@
help = optdict.get('help')
if help:
help = normalize_text(help, line_len=79, indent='# ')
- print >> stream
- print >> stream, _encode(help, encoding)
+ print(file=stream)
+ print(_encode(help, encoding), file=stream)
else:
- print >> stream
+ print(file=stream)
if value is None:
- print >> stream, '#%s=' % optname
+ print('#%s=' % optname, file=stream)
else:
value = _encode(value, encoding).strip()
- print >> stream, '%s=%s' % (optname, value)
+ print('%s=%s' % (optname, value), file=stream)
format_section = ini_format_section
def rest_format_section(stream, section, options, encoding=None, doc=None):
- """format an options section using the INI format"""
+ """format an options section using as ReST formatted output"""
encoding = _get_encoding(encoding, stream)
if section:
print >> stream, '%s\n%s' % (section, "'"*len(section))
@@ -401,6 +425,7 @@
print >> stream, ''
print >> stream, ' Default: ``%s``' % value.replace("`` ", "```` ``")
+# Options Manager ##############################################################
class OptionsManagerMixIn(object):
"""MixIn to handle a configuration from both a configuration file and
@@ -423,9 +448,9 @@
def reset_parsers(self, usage='', version=None):
# configuration file parser
- self.cfgfile_parser = ConfigParser()
+ self.cfgfile_parser = cp.ConfigParser()
# command line parser
- self.cmdline_parser = optparse.OptionParser(usage=usage, version=version)
+ self.cmdline_parser = optik_ext.OptionParser(usage=usage, version=version)
self.cmdline_parser.options_manager = self
self._optik_option_attrs = set(self.cmdline_parser.option_class.ATTRS)
@@ -461,7 +486,7 @@
if group_name in self._mygroups:
group = self._mygroups[group_name]
else:
- group = optparse.OptionGroup(self.cmdline_parser,
+ group = optik_ext.OptionGroup(self.cmdline_parser,
title=group_name.capitalize())
self.cmdline_parser.add_option_group(group)
group.level = provider.level
@@ -497,9 +522,9 @@
# default is handled here and *must not* be given to optik if you
# want the whole machinery to work
if 'default' in optdict:
- 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')):
+ if ('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)]
@@ -508,7 +533,7 @@
args.append('-' + optdict['short'])
del optdict['short']
# cleanup option definition dict before giving it to optik
- for key in optdict.keys():
+ for key in list(optdict.keys()):
if not key in self._optik_option_attrs:
optdict.pop(key)
return args, optdict
@@ -555,7 +580,7 @@
printed = False
for section in sections:
if printed:
- print >> stream, '\n'
+ print('\n', file=stream)
format_section(stream, section.upper(), options_by_section[section],
encoding)
printed = True
@@ -566,7 +591,7 @@
"""
self._monkeypatch_expand_default()
try:
- optparse.generate_manpage(self.cmdline_parser, pkginfo,
+ optik_ext.generate_manpage(self.cmdline_parser, pkginfo,
section, stream=stream or sys.stdout,
level=self._maxlevel)
finally:
@@ -594,7 +619,7 @@
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,
@@ -616,7 +641,7 @@
parser._sections[sect.upper()] = values
elif not self.quiet:
msg = 'No config file found, using default configuration'
- print >> sys.stderr, msg
+ print(msg, file=sys.stderr)
return
def input_config(self, onlysection=None, inputlevel=0, stream=None):
@@ -642,13 +667,13 @@
options provider)
"""
parser = self.cfgfile_parser
- 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
+ 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
def load_configuration(self, **kwargs):
"""override configuration according to given parameters
@@ -686,7 +711,7 @@
def add_help_section(self, title, description, level=0):
"""add a dummy option section for help purpose """
- group = optparse.OptionGroup(self.cmdline_parser,
+ group = optik_ext.OptionGroup(self.cmdline_parser,
title=title.capitalize(),
description=description)
group.level = level
@@ -694,18 +719,18 @@
self.cmdline_parser.add_option_group(group)
def _monkeypatch_expand_default(self):
- # monkey patch optparse to deal with our default values
+ # monkey patch optik_ext to deal with our default values
try:
- self.__expand_default_backup = optparse.HelpFormatter.expand_default
- optparse.HelpFormatter.expand_default = expand_default
+ self.__expand_default_backup = optik_ext.HelpFormatter.expand_default
+ optik_ext.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(optparse.HelpFormatter, 'expand_default'):
- # unpatch optparse to avoid side effects
- optparse.HelpFormatter.expand_default = self.__expand_default_backup
+ if hasattr(optik_ext.HelpFormatter, 'expand_default'):
+ # unpatch optik_ext to avoid side effects
+ optik_ext.HelpFormatter.expand_default = self.__expand_default_backup
def help(self, level=0):
"""return the usage string for available options """
@@ -734,6 +759,7 @@
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"""
@@ -745,7 +771,7 @@
level = 0
def __init__(self):
- self.config = optparse.Values()
+ self.config = optik_ext.Values()
for option in self.options:
try:
option, optdict = option
@@ -777,41 +803,41 @@
default = default()
return default
- def option_name(self, opt, optdict=None):
+ def option_attrname(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_name(opt), None)
+ return getattr(self.config, self.option_attrname(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 = convert(value, optdict, opt)
+ value = _validate(value, optdict, opt)
if action is None:
action = optdict.get('action', 'store')
if optdict.get('type') == 'named': # XXX need specific handling
- optname = self.option_name(opt, optdict)
+ optname = self.option_attrname(opt, optdict)
currentvalue = getattr(self.config, optname, None)
if currentvalue:
currentvalue.update(value)
value = currentvalue
if action == 'store':
- setattr(self.config, self.option_name(opt, optdict), value)
+ setattr(self.config, self.option_attrname(opt, optdict), value)
elif action in ('store_true', 'count'):
- setattr(self.config, self.option_name(opt, optdict), 0)
+ setattr(self.config, self.option_attrname(opt, optdict), 0)
elif action == 'store_false':
- setattr(self.config, self.option_name(opt, optdict), 1)
+ setattr(self.config, self.option_attrname(opt, optdict), 1)
elif action == 'append':
- opt = self.option_name(opt, optdict)
+ opt = self.option_attrname(opt, optdict)
_list = getattr(self.config, opt, None)
if _list is None:
if isinstance(value, (list, tuple)):
@@ -839,12 +865,12 @@
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
@@ -893,6 +919,7 @@
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
@@ -913,7 +940,7 @@
continue
if not gdef in self.option_groups:
self.option_groups.append(gdef)
- self.register_options_provider(self, own_group=0)
+ self.register_options_provider(self, own_group=False)
def register_options(self, options):
"""add some options to the configuration"""
@@ -932,8 +959,8 @@
def __getitem__(self, key):
try:
- return getattr(self.config, self.option_name(key))
- except (optparse.OptionValueError, AttributeError):
+ return getattr(self.config, self.option_attrname(key))
+ except (optik_ext.OptionValueError, AttributeError):
raise KeyError(key)
def __setitem__(self, key, value):
@@ -941,7 +968,7 @@
def get(self, key, default=None):
try:
- return getattr(self.config, self.option_name(key))
+ return getattr(self.config, self.option_attrname(key))
except (OptionError, AttributeError):
return default
@@ -977,20 +1004,21 @@
def __getitem__(self, key):
provider = self.config._all_options[key]
try:
- return getattr(provider.config, provider.option_name(key))
+ return getattr(provider.config, provider.option_attrname(key))
except AttributeError:
raise KeyError(key)
def __setitem__(self, key, value):
- self.config.global_set_option(self.config.option_name(key), value)
+ self.config.global_set_option(self.config.option_attrname(key), value)
def get(self, key, default=None):
provider = self.config._all_options[key]
try:
- return getattr(provider.config, provider.option_name(key))
+ return getattr(provider.config, provider.option_attrname(key))
except AttributeError:
return default
+# other functions ##############################################################
def read_old_config(newconfig, changes, configfile):
"""initialize newconfig from a deprecated configuration file
@@ -1055,8 +1083,13 @@
newconfig.set_option(optname, oldconfig[optname], optdict=optdef)
-def merge_options(options):
- """preprocess options to remove duplicate"""
+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.
+ """
alloptions = {}
options = list(options)
for i in range(len(options)-1, -1, -1):
@@ -1065,5 +1098,9 @@
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)
« no previous file with comments | « third_party/logilab/common/compat.py ('k') | third_party/logilab/common/corbautils.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698