diff options
| author | Barry Warsaw | 2015-05-03 16:56:22 -0400 |
|---|---|---|
| committer | Barry Warsaw | 2015-05-03 16:56:22 -0400 |
| commit | a80595acf011b48e5b62410342e67a27deb18e71 (patch) | |
| tree | 83bcef61270b0cfd363468d8c98a7a17c5d0accc /src/mailman/utilities/options.py | |
| parent | 509d47e31847868818cc234a169b3c3f159848eb (diff) | |
| download | mailman-a80595acf011b48e5b62410342e67a27deb18e71.tar.gz mailman-a80595acf011b48e5b62410342e67a27deb18e71.tar.zst mailman-a80595acf011b48e5b62410342e67a27deb18e71.zip | |
Diffstat (limited to 'src/mailman/utilities/options.py')
| -rw-r--r-- | src/mailman/utilities/options.py | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/src/mailman/utilities/options.py b/src/mailman/utilities/options.py new file mode 100644 index 000000000..a9cff3b70 --- /dev/null +++ b/src/mailman/utilities/options.py @@ -0,0 +1,142 @@ +# Copyright (C) 2008-2015 by the Free Software Foundation, Inc. +# +# This file is part of GNU Mailman. +# +# GNU Mailman is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. + +"""Common argument parsing.""" + +__all__ = [ + 'Options', + ] + + +import os +import sys + +from copy import copy +from mailman.config import config +from mailman.core.i18n import _ +from mailman.core.initialize import initialize +from mailman.version import MAILMAN_VERSION +from optparse import Option, OptionParser, OptionValueError + + + +def check_unicode(option, opt, value): + """Check that the value is a unicode string.""" + if not isinstance(value, bytes): + return value + try: + return value.decode(sys.getdefaultencoding()) + except UnicodeDecodeError: + raise OptionValueError( + 'option {0}: Cannot decode: {1}'.format(opt, value)) + + +def check_yesno(option, opt, value): + """Check that the value is 'yes' or 'no'.""" + value = value.lower() + if value not in ('yes', 'no', 'y', 'n'): + raise OptionValueError('option {0}: invalid: {1}'.format(opt, value)) + return value[0] == 'y' + + +class MailmanOption(Option): + """Extension types for unicode options.""" + TYPES = Option.TYPES + ('unicode', 'yesno') + TYPE_CHECKER = copy(Option.TYPE_CHECKER) + TYPE_CHECKER['unicode'] = check_unicode + TYPE_CHECKER['yesno'] = check_yesno + + +class SafeOptionParser(OptionParser): + """A unicode-compatible `OptionParser`. + + Python's standard option parser does not accept unicode options. Rather + than try to fix that, this class wraps the add_option() method and saves + having to wrap the options in str() calls. + """ + def add_option(self, *args, **kwargs): + """See `OptionParser`.""" + # Check to see if the first or first two options are unicodes and turn + # them into 8-bit strings before calling the superclass's method. + if len(args) == 0: + return OptionParser.add_option(self, *args, **kwargs) + old_args = list(args) + new_args = [] + arg0 = old_args.pop(0) + new_args.append(str(arg0)) + if len(old_args) > 0: + arg1 = old_args.pop(0) + new_args.append(str(arg1)) + new_args.extend(old_args) + return OptionParser.add_option(self, *new_args, **kwargs) + + + +class Options: + """Common argument parser.""" + + # Subclasses should override. + usage = None + + def __init__(self): + self.parser = SafeOptionParser( + version=MAILMAN_VERSION, + option_class=MailmanOption, + usage=self.usage) + self.add_common_options() + self.add_options() + options, arguments = self.parser.parse_args() + self.options = options + self.arguments = arguments + # Also, for convenience, place the options in the configuration file + # because occasional global uses are necessary. + config.options = self + + def add_options(self): + """Allow the subclass to add its own specific arguments.""" + pass + + def sanity_check(self): + """Allow subclasses to do sanity checking of arguments.""" + pass + + def add_common_options(self): + """Add options common to all scripts.""" + # Python requires str types here. + self.parser.add_option( + '-C', '--config', + help=_('Alternative configuration file to use')) + + def initialize(self, propagate_logs=None): + """Initialize the configuration system. + + After initialization of the configuration system, perform sanity + checks. We do it in this order because some sanity checks require the + configuration to be initialized. + + :param propagate_logs: Optional flag specifying whether log messages + in sub-loggers should be propagated to the master logger (and + hence to the root logger). If not given, propagation is taken + from the configuration files. + :type propagate_logs: bool or None. + """ + # Fall back to using the environment variable if -C is not given. + config_file = (os.getenv('MAILMAN_CONFIG_FILE') + if self.options.config is None + else self.options.config) + initialize(config_file, propagate_logs=propagate_logs) + self.sanity_check() |
