srcanamdw/codescanner/pyinstaller/optik/help.py
changeset 1 22878952f6e2
equal deleted inserted replaced
0:509e4801c378 1:22878952f6e2
       
     1 """optik.help
       
     2 
       
     3 Provides HelpFormatter and subclasses -- used by OptionParser
       
     4 to generate formatted help text.
       
     5 """
       
     6 
       
     7 # Copyright (c) 2001-2004 Gregory P. Ward.  All rights reserved.
       
     8 # See the README.txt distributed with Optik for licensing terms.
       
     9 
       
    10 import os
       
    11 import string
       
    12 import textwrap
       
    13 from optik.option import NO_DEFAULT
       
    14 from optik.errors import gettext
       
    15 _ = gettext
       
    16 
       
    17 __revision__ = "$Id: help.py,v 1.1 2009/02/05 23:03:30 stechong Exp $"
       
    18 
       
    19 __all__ = ['HelpFormatter', 'IndentedHelpFormatter', 'TitledHelpFormatter']
       
    20 
       
    21 class HelpFormatter:
       
    22 
       
    23     """
       
    24     Abstract base class for formatting option help.  OptionParser
       
    25     instances should use one of the HelpFormatter subclasses for
       
    26     formatting help; by default IndentedHelpFormatter is used.
       
    27 
       
    28     Instance attributes:
       
    29       parser : OptionParser
       
    30         the controlling OptionParser instance
       
    31       indent_increment : int
       
    32         the number of columns to indent per nesting level
       
    33       max_help_position : int
       
    34         the maximum starting column for option help text
       
    35       help_position : int
       
    36         the calculated starting column for option help text;
       
    37         initially the same as the maximum
       
    38       width : int
       
    39         total number of columns for output (pass None to constructor for
       
    40         this value to be taken from the $COLUMNS environment variable)
       
    41       level : int
       
    42         current indentation level
       
    43       current_indent : int
       
    44         current indentation level (in columns)
       
    45       help_width : int
       
    46         number of columns available for option help text (calculated)
       
    47       default_tag : str
       
    48         text to replace with each option's default value, "%default"
       
    49         by default.  Set to false value to disable default value expansion.
       
    50       option_strings : { Option : str }
       
    51         maps Option instances to the snippet of help text explaining
       
    52         the syntax of that option, e.g. "-h, --help" or
       
    53         "-fFILE, --file=FILE"
       
    54       _short_opt_fmt : str
       
    55         format string controlling how short options with values are
       
    56         printed in help text.  Must be either "%s%s" ("-fFILE") or
       
    57         "%s %s" ("-f FILE"), because those are the two syntaxes that
       
    58         Optik supports.
       
    59       _long_opt_fmt : str
       
    60         similar but for long options; must be either "%s %s" ("--file FILE")
       
    61         or "%s=%s" ("--file=FILE").
       
    62     """
       
    63 
       
    64     NO_DEFAULT_VALUE = "none"
       
    65 
       
    66     def __init__(self,
       
    67                  indent_increment,
       
    68                  max_help_position,
       
    69                  width,
       
    70                  short_first):
       
    71         self.parser = None
       
    72         self.indent_increment = indent_increment
       
    73         self.help_position = self.max_help_position = max_help_position
       
    74         if width is None:
       
    75             try:
       
    76                 width = int(os.environ['COLUMNS'])
       
    77             except (KeyError, ValueError):
       
    78                 width = 80
       
    79             width = width - 2
       
    80         self.width = width
       
    81         self.current_indent = 0
       
    82         self.level = 0
       
    83         self.help_width = None          # computed later
       
    84         self.short_first = short_first
       
    85         self.default_tag = "%default"
       
    86         self.option_strings = {}
       
    87         self._short_opt_fmt = "%s %s"
       
    88         self._long_opt_fmt = "%s=%s"
       
    89 
       
    90     def set_parser(self, parser):
       
    91         self.parser = parser
       
    92 
       
    93     def set_short_opt_delimiter(self, delim):
       
    94         if delim not in ("", " "):
       
    95             raise ValueError(
       
    96                 "invalid metavar delimiter for short options: %r" % delim)
       
    97         self._short_opt_fmt = "%s" + delim + "%s"
       
    98 
       
    99     def set_long_opt_delimiter(self, delim):
       
   100         if delim not in ("=", " "):
       
   101             raise ValueError(
       
   102                 "invalid metavar delimiter for long options: %r" % delim)
       
   103         self._long_opt_fmt = "%s" + delim + "%s"
       
   104 
       
   105     def indent(self):
       
   106         self.current_indent = self.current_indent + self.indent_increment
       
   107         self.level = self.level + 1
       
   108 
       
   109     def dedent(self):
       
   110         self.current_indent = self.current_indent - self.indent_increment
       
   111         assert self.current_indent >= 0, "Indent decreased below 0."
       
   112         self.level = self.level - 1
       
   113 
       
   114     def format_usage(self, usage):
       
   115         raise NotImplementedError, "subclasses must implement"
       
   116 
       
   117     def format_heading(self, heading):
       
   118         raise NotImplementedError, "subclasses must implement"
       
   119 
       
   120     def format_description(self, description):
       
   121         if not description:
       
   122             return ""
       
   123         desc_width = self.width - self.current_indent
       
   124         indent = " "*self.current_indent
       
   125         return textwrap.fill(description,
       
   126                              desc_width,
       
   127                              initial_indent=indent,
       
   128                              subsequent_indent=indent) + "\n"
       
   129 
       
   130     def expand_default(self, option):
       
   131         if self.parser is None or not self.default_tag:
       
   132             return option.help
       
   133 
       
   134         default_value = self.parser.defaults.get(option.dest)
       
   135         if default_value is NO_DEFAULT or default_value is None:
       
   136             default_value = self.NO_DEFAULT_VALUE
       
   137 
       
   138         return string.replace(option.help, self.default_tag, str(default_value))
       
   139 
       
   140     def format_option(self, option):
       
   141         # The help for each option consists of two parts:
       
   142         #   * the opt strings and metavars
       
   143         #     eg. ("-x", or "-fFILENAME, --file=FILENAME")
       
   144         #   * the user-supplied help string
       
   145         #     eg. ("turn on expert mode", "read data from FILENAME")
       
   146         #
       
   147         # If possible, we write both of these on the same line:
       
   148         #   -x      turn on expert mode
       
   149         #
       
   150         # But if the opt string list is too long, we put the help
       
   151         # string on a second line, indented to the same column it would
       
   152         # start in if it fit on the first line.
       
   153         #   -fFILENAME, --file=FILENAME
       
   154         #           read data from FILENAME
       
   155         result = []
       
   156         opts = self.option_strings[option]
       
   157         opt_width = self.help_position - self.current_indent - 2
       
   158         if len(opts) > opt_width:
       
   159             opts = "%*s%s\n" % (self.current_indent, "", opts)
       
   160             indent_first = self.help_position
       
   161         else:                       # start help on same line as opts
       
   162             opts = "%*s%-*s  " % (self.current_indent, "", opt_width, opts)
       
   163             indent_first = 0
       
   164         result.append(opts)
       
   165         if option.help:
       
   166             help_text = self.expand_default(option)
       
   167             help_lines = textwrap.wrap(help_text, self.help_width)
       
   168             result.append("%*s%s\n" % (indent_first, "", help_lines[0]))
       
   169             for line in help_lines[1:]:
       
   170                 result.append("%*s%s\n" % (self.help_position, "", line))
       
   171         elif opts[-1] != "\n":
       
   172             result.append("\n")
       
   173         return string.join(result, "")
       
   174 
       
   175     def store_option_strings(self, parser):
       
   176         self.indent()
       
   177         max_len = 0
       
   178         for opt in parser.option_list:
       
   179             strings = self.format_option_strings(opt)
       
   180             self.option_strings[opt] = strings
       
   181             max_len = max(max_len, len(strings) + self.current_indent)
       
   182         self.indent()
       
   183         for group in parser.option_groups:
       
   184             for opt in group.option_list:
       
   185                 strings = self.format_option_strings(opt)
       
   186                 self.option_strings[opt] = strings
       
   187                 max_len = max(max_len, len(strings) + self.current_indent)
       
   188         self.dedent()
       
   189         self.dedent()
       
   190         self.help_position = min(max_len + 2, self.max_help_position)
       
   191         self.help_width = self.width - self.help_position
       
   192 
       
   193     def format_option_strings(self, option):
       
   194         """Return a comma-separated list of option strings & metavariables."""
       
   195         if option.takes_value():
       
   196             metavar = option.metavar or string.upper(option.dest)
       
   197             short_opts = []
       
   198             for sopt in option._short_opts:
       
   199                 short_opts.append(self._short_opt_fmt % (sopt, metavar))
       
   200             long_opts = []
       
   201             for lopt in option._long_opts:
       
   202                 long_opts.append(self._long_opt_fmt % (lopt, metavar))
       
   203         else:
       
   204             short_opts = option._short_opts
       
   205             long_opts = option._long_opts
       
   206 
       
   207         if self.short_first:
       
   208             opts = short_opts + long_opts
       
   209         else:
       
   210             opts = long_opts + short_opts
       
   211 
       
   212         return string.join(opts, ", ")
       
   213 
       
   214 class IndentedHelpFormatter (HelpFormatter):
       
   215     """Format help with indented section bodies.
       
   216     """
       
   217 
       
   218     def __init__(self,
       
   219                  indent_increment=2,
       
   220                  max_help_position=24,
       
   221                  width=None,
       
   222                  short_first=1):
       
   223         HelpFormatter.__init__(
       
   224             self, indent_increment, max_help_position, width, short_first)
       
   225 
       
   226     def format_usage(self, usage):
       
   227         return _("usage: %s\n") % usage
       
   228 
       
   229     def format_heading(self, heading):
       
   230         return "%*s%s:\n" % (self.current_indent, "", heading)
       
   231 
       
   232 
       
   233 class TitledHelpFormatter (HelpFormatter):
       
   234     """Format help with underlined section headers.
       
   235     """
       
   236 
       
   237     def __init__(self,
       
   238                  indent_increment=0,
       
   239                  max_help_position=24,
       
   240                  width=None,
       
   241                  short_first=0):
       
   242         HelpFormatter.__init__ (
       
   243             self, indent_increment, max_help_position, width, short_first)
       
   244 
       
   245     def format_usage(self, usage):
       
   246         return "%s  %s\n" % (self.format_heading(_("Usage")), usage)
       
   247 
       
   248     def format_heading(self, heading):
       
   249         return "%s\n%s\n" % (heading, "=-"[self.level] * len(heading))