PING: [RFC] Optparse option handling

Aaron Bentley aaron.bentley at utoronto.ca
Tue Aug 8 18:29:22 BST 2006


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

I've had no feedback on this.  Does anyone want to comment?

Aaron

Aaron Bentley wrote:
> Hi all,
> 
> I've updated the optparse branch, added unit tests and the like.  The
> branch now
> 
> * uses optparse to parse options, and to generate help
> 
> * auto-supplies negations of all booleans.  That is, --strict implies
>   --no-strict, and --no-recurse implies --recurse.
> 
> * provides enumerated options.  These are options where several switches
>  affect the same variable.  These replace options like --merge-type and
> --short.  The last value is always used.
> 
> * updates log, merge, remerge, init-repo, init, upgrade to use EnumOptions
> 
> * Uses polymorphism to provide different behavior for Option and EnumOption
> 
> * Groups enumerations in the help output, provides textual descriptions
> of all options.
> 
> The downside is that the old parameters have been removed, instead of
> being deprecated.  Supporting looks looks like pain, but if it's felt
> that we must support e.g. --merge-type as a deprecated option for 0.10,
> then I will figure out how to support it.
> 
> So can I get some comments on where to go from here?
> 
> Aaron
> p.s. Here's the help output of init-repository, for an example:
> 
> help:usage: bzr init-repository LOCATION
> aliases: init-repo
> 
> Create a shared repository to hold branches.
> 
> New branches created under the repository directory will store their
> revisions
> in the repository, not in the branch directory, if the branch format
> supports
> shared storage.
> 
> example:
>     bzr init-repo repo
>     bzr init repo/trunk
>     bzr checkout --lightweight repo/trunk trunk-checkout
>     cd trunk-checkout
>     (add files here)
> 
> options:
>   -h, --help     show help message
>   --trees        Allows branches in repository to have a working tree
> 
>   Repository Format:
>     --default    The current best format (knit)
>     --knit       0.8+ append-only format
>     --metaweave  0.8 transitional format

- ------------------------------------------------------------------------

=== modified file 'bzrlib/builtins.py'
- --- bzrlib/builtins.py	2006-08-01 19:09:18 +0000
+++ bzrlib/builtins.py	2006-08-04 02:49:18 +0000
@@ -48,7 +48,7 @@
                            NoSuchFile, NoWorkingTree, FileInWrongBranch,
                            NotVersionedError, NotABundle)
 from bzrlib.merge import Merge3Merger
- -from bzrlib.option import Option
+from bzrlib.option import Option, EnumOption
 from bzrlib.progress import DummyProgress, ProgressPhase
 from bzrlib.revision import common_ancestor
 from bzrlib.revisionspec import RevisionSpec
@@ -993,6 +993,20 @@
         for revision_id in revision_ids:
             self.outf.write(revision_id + '\n')

+branch_format_option = EnumOption('Branch Format', get_format_type,
+                                  [('default',
+                                    'The current best format (knit)'),
+                                   ('knit', '0.8+ append-only format'),
+                                   ('metaweave', '0.8 transitional
format'),
+                                   ('weave', '0.1+ format')
+                                  ])
+
+repo_format_option = EnumOption('Repository Format', get_format_type,
+                                [('default',
+                                  'The current best format (knit)'),
+                                 ('knit', '0.8+ append-only format'),
+                                 ('metaweave', '0.8 transitional format'),
+                                ])

 class cmd_init(Command):
     """Make a directory into a versioned branch.
@@ -1016,17 +1030,10 @@
         bzr commit -m 'imported project'
     """
     takes_args = ['location?']
- -    takes_options = [
- -                     Option('format',
- -                            help='Specify a format for this branch.
Current'
- -                                 ' formats are: default, knit,
metaweave and'
- -                                 ' weave. Default is knit; metaweave and'
- -                                 ' weave are deprecated',
- -                            type=get_format_type),
- -                     ]
- -    def run(self, location=None, format=None):
- -        if format is None:
- -            format = get_format_type('default')
+    takes_options = [branch_format_option]
+    def run(self, location=None, branch_format=None):
+        if branch_format is None:
+            branch_format = get_format_type('default')
         if location is None:
             location = u'.'

@@ -1047,7 +1054,8 @@
             existing_bzrdir = bzrdir.BzrDir.open(location)
         except NotBranchError:
             # really a NotBzrDir error...
- -            bzrdir.BzrDir.create_branch_convenience(location,
format=format)
+            bzrdir.BzrDir.create_branch_convenience(location,
+                                                    format=branch_format)
         else:
             if existing_bzrdir.has_branch():
                 if (isinstance(to_transport, LocalTransport)
@@ -1074,30 +1082,21 @@
         (add files here)
     """
     takes_args = ["location"]
- -    takes_options = [Option('format',
- -                            help='Specify a format for this repository.'
- -                                 ' Current formats are: default, knit,'
- -                                 ' metaweave and weave. Default is knit;'
- -                                 ' metaweave and weave are deprecated',
- -                            type=get_format_type),
+    takes_options = [repo_format_option,
                      Option('trees',
                              help='Allows branches in repository to have'
                              ' a working tree')]
     aliases = ["init-repo"]
- -    def run(self, location, format=None, trees=False):
- -        if format is None:
- -            format = get_format_type('default')
- -
- -        if location is None:
- -            location = '.'
- -
+    def run(self, location, repository_format=None, trees=False):
+        if repository_format is None:
+            repository_format = get_format_type('default')
         to_transport = transport.get_transport(location)
         try:
             to_transport.mkdir('.')
         except errors.FileExists:
             pass

- -        newdir = format.initialize_on_transport(to_transport)
+        newdir = repository_format.initialize_on_transport(to_transport)
         repo = newdir.create_repository(shared=True)
         repo.set_make_working_trees(trees)

@@ -1296,11 +1295,9 @@
                              help='show files changed in each revision'),
                      'show-ids', 'revision',
                      'log-format',
- -                     'line', 'long',
                      Option('message',
                             help='show revisions whose message matches
this regexp',
                             type=str),
- -                     'short',
                      ]
     encoding_type = 'replace'

@@ -1311,10 +1308,7 @@
             forward=False,
             revision=None,
             log_format=None,
- -            message=None,
- -            long=False,
- -            short=False,
- -            line=False):
+            message=None):
         from bzrlib.log import log_formatter, show_log
         assert message is None or isinstance(message, basestring), \
             "invalid message argument %r" % message
@@ -1368,9 +1362,7 @@
             (rev2, rev1) = (rev1, rev2)

         if (log_format == None):
- -            default = b.get_config().log_format()
- -            log_format = get_log_format(long=long, short=short,
line=line,
- -                                        default=default)
+            log_format = b.get_config().log_format()
         lf = log_formatter(log_format,
                            show_ids=show_ids,
                            to_file=self.outf,
@@ -1386,17 +1378,6 @@
                  search=message)


- -def get_log_format(long=False, short=False, line=False, default='long'):
- -    log_format = default
- -    if long:
- -        log_format = 'long'
- -    if short:
- -        log_format = 'short'
- -    if line:
- -        log_format = 'line'
- -    return log_format
- -
- -
 class cmd_touching_revisions(Command):
     """Return revision-ids which affected a particular file.

@@ -1810,21 +1791,13 @@
     during other operations to upgrade.
     """
     takes_args = ['url?']
- -    takes_options = [
- -                     Option('format',
- -                            help='Upgrade to a specific format. Current
formats'
- -                                 ' are: default, knit, metaweave and
weave.'
- -                                 ' Default is knit; metaweave and weave
are'
- -                                 ' deprecated',
- -                            type=get_format_type),
- -                    ]
- -
- -
- -    def run(self, url='.', format=None):
+    takes_options = [ branch_format_option ]
+
+    def run(self, url='.', branch_format=None):
         from bzrlib.upgrade import upgrade
- -        if format is None:
- -            format = get_format_type('default')
- -        upgrade(url, format)
+        if branch_format is None:
+            branch_format = get_format_type('default')
+        upgrade(url, branch_format)


 class cmd_whoami(Command):
@@ -2406,9 +2379,6 @@
                      Option('theirs-only',
                             'Display changes in the remote branch only'),
                      'log-format',
- -                     'line',
- -                     'long',
- -                     'short',
                      'show-ids',
                      'verbose'
                      ]
@@ -2416,7 +2386,7 @@

     @display_command
     def run(self, other_branch=None, reverse=False, mine_only=False,
- -            theirs_only=False, log_format=None, long=False,
short=False, line=False,
+            theirs_only=False, log_format=None,
             show_ids=False, verbose=False):
         from bzrlib.missing import find_unmerged, iter_log_data
         from bzrlib.log import log_formatter
@@ -2435,10 +2405,8 @@
             remote_branch.lock_read()
             try:
                 local_extra, remote_extra = find_unmerged(local_branch,
remote_branch)
- -                if (log_format == None):
- -                    default = local_branch.get_config().log_format()
- -                    log_format = get_log_format(long=long, short=short,
- -                                                line=line,
default=default)
+                if (log_format is None):
+                    log_format = local_branch.get_config().log_format()
                 lf = log_formatter(log_format,
                                    to_file=self.outf,
                                    show_ids=show_ids,
@@ -2503,7 +2471,8 @@

 class cmd_testament(Command):
     """Show testament (signing-form) of a revision."""
- -    takes_options = ['revision', 'long',
+    takes_options = ['revision',
+                     Option('long', help='Produce long-format testament'),
                      Option('strict', help='Produce a strict-format'
                             ' testament')]
     takes_args = ['branch?']

=== modified file 'bzrlib/commands.py'
- --- bzrlib/commands.py	2006-07-15 14:29:03 +0000
+++ bzrlib/commands.py	2006-08-03 05:21:02 +0000
@@ -28,18 +28,18 @@
 # TODO: "--profile=cum", to change sort order.  Is there any value in
leaving
 # the profile output behind so it can be interactively examined?

- -import sys
+import codecs
+import errno
 import os
 from warnings import warn
- -import errno
- -import codecs
+import sys

 import bzrlib
 import bzrlib.errors as errors
 from bzrlib.errors import (BzrError,
- -                           BzrCommandError,
- -                           BzrCheckError,
+                           BzrCommandError, BzrCheckError,
                            NotBranchError)
+from bzrlib import option
 from bzrlib.option import Option
 import bzrlib.osutils
 from bzrlib.revisionspec import RevisionSpec
@@ -221,7 +221,7 @@
         r = dict()
         r['help'] = Option.OPTIONS['help']
         for o in self.takes_options:
- -            if not isinstance(o, Option):
+            if isinstance(o, basestring):
                 o = Option.OPTIONS[o]
             r[o.name] = o
         return r
@@ -261,12 +261,6 @@
             from bzrlib.help import help_on_command
             help_on_command(self.name())
             return 0
- -        # XXX: This should be handled by the parser
- -        allowed_names = self.options().keys()
- -        for oname in opts:
- -            if oname not in allowed_names:
- -                raise BzrOptionError("option '--%s' is not allowed for"
- -                                " command %r" % (oname, self.name()))
         # mix arguments and options into one dictionary
         cmdargs = _match_argform(self.name(), self.takes_args, args)
         cmdopts = {}
@@ -346,6 +340,7 @@
         parsed = [spec, None]
     return parsed

+
 def parse_args(command, argv, alias_argv=None):
     """Parse command line.

@@ -354,106 +349,16 @@
     lookup table, something about the available options, what optargs
     they take, and which commands will accept them.
     """
- -    # TODO: chop up this beast; make it a method of the Command
- -    args = []
- -    opts = {}
- -    alias_opts = {}
- -
- -    cmd_options = command.options()
- -    argsover = False
- -    proc_aliasarg = True # Are we processing alias_argv now?
- -    for proc_argv in alias_argv, argv:
- -        while proc_argv:
- -            a = proc_argv.pop(0)
- -            if argsover:
- -                args.append(a)
- -                continue
- -            elif a == '-':
- -                args.append(a)
- -                continue
- -            elif a == '--':
- -                # We've received a standalone -- No more flags
- -                argsover = True
- -                continue
- -            if a[0] == '-':
- -                # option names must not be unicode
- -                a = str(a)
- -                optarg = None
- -                if a[1] == '-':
- -                    mutter("  got option %r", a)
- -                    if '=' in a:
- -                        optname, optarg = a[2:].split('=', 1)
- -                    else:
- -                        optname = a[2:]
- -                    if optname not in cmd_options:
- -                        raise BzrCommandError('unknown option "%s"' % a)
- -                else:
- -                    shortopt = a[1:]
- -                    if shortopt in Option.SHORT_OPTIONS:
- -                        # Multi-character options must have a space to
delimit
- -                        # their value
- -                        # ^^^ what does this mean? mbp 20051014
- -                        optname = Option.SHORT_OPTIONS[shortopt].name
- -                    else:
- -                        # Single character short options, can be chained,
- -                        # and have their value appended to their name
- -                        shortopt = a[1:2]
- -                        if shortopt not in Option.SHORT_OPTIONS:
- -                            # We didn't find the multi-character name,
and we
- -                            # didn't find the single char name
- -                            raise BzrCommandError('unknown option "%s"'
% a)
- -                        optname = Option.SHORT_OPTIONS[shortopt].name
- -
- -                        if a[2:]:
- -                            # There are extra things on this option
- -                            # see if it is the value, or if it is another
- -                            # short option
- -                            optargfn = Option.OPTIONS[optname].type
- -                            if optargfn is None:
- -                                # This option does not take an
argument, so the
- -                                # next entry is another short option,
pack it
- -                                # back into the list
- -                                proc_argv.insert(0, '-' + a[2:])
- -                            else:
- -                                # This option takes an argument, so
pack it
- -                                # into the array
- -                                optarg = a[2:]
- -                    if optname not in cmd_options:
- -                        raise BzrCommandError('unknown option "%s"' %
shortopt)
- -                if optname in opts:
- -                    # XXX: Do we ever want to support this, e.g. for -r?
- -                    if proc_aliasarg:
- -                        raise BzrCommandError('repeated option %r' % a)
- -                    elif optname in alias_opts:
- -                        # Replace what's in the alias with what's in
the real
- -                        # argument
- -                        del alias_opts[optname]
- -                        del opts[optname]
- -                        proc_argv.insert(0, a)
- -                        continue
- -                    else:
- -                        raise BzrCommandError('repeated option %r' % a)
- -
- -                option_obj = cmd_options[optname]
- -                optargfn = option_obj.type
- -                if optargfn:
- -                    if optarg == None:
- -                        if not proc_argv:
- -                            raise BzrCommandError('option %r needs an
argument' % a)
- -                        else:
- -                            optarg = proc_argv.pop(0)
- -                    opts[optname] = optargfn(optarg)
- -                    if proc_aliasarg:
- -                        alias_opts[optname] = optargfn(optarg)
- -                else:
- -                    if optarg != None:
- -                        raise BzrCommandError('option %r takes no
argument' % optname)
- -                    opts[optname] = True
- -                    if proc_aliasarg:
- -                        alias_opts[optname] = True
- -            else:
- -                args.append(a)
- -        proc_aliasarg = False # Done with alias argv
+    # TODO: make it a method of the Command?
+    parser = option.get_optparser(command.options())
+    if alias_argv is not None:
+        args = alias_argv + argv
+    else:
+        args = argv
+
+    options, args = parser.parse_args(args)
+    opts = dict([(k, v) for k, v in options.__dict__.iteritems() if
+                 v is not option.OptionParser.DEFAULT_VALUE])
     return args, opts



=== modified file 'bzrlib/help.py'
- --- bzrlib/help.py	2006-07-30 07:02:22 +0000
+++ bzrlib/help.py	2006-08-03 05:21:02 +0000
@@ -128,26 +128,12 @@


 def help_on_command_options(cmd, outfile=None):
- -    from bzrlib.option import Option
+    from bzrlib.option import Option, get_optparser
+    if outfile is None:
+        outfile = sys.stdout
     options = cmd.options()
- -    if not options:
- -        return
- -    if outfile == None:
- -        outfile = sys.stdout
- -    outfile.write('\noptions:\n')
- -    for option_name, option in sorted(options.items()):
- -        l = '    --' + option_name
- -        if option.type is not None:
- -            l += ' ' + option.argname.upper()
- -        short_name = option.short_name()
- -        if short_name:
- -            assert len(short_name) == 1
- -            l += ', -' + short_name
- -        l += (30 - len(l)) * ' ' + option.help
- -        # TODO: split help over multiple lines with correct indenting and
- -        # wrapping
- -        wrapped = textwrap.fill(l, initial_indent='',
subsequent_indent=30*' ')
- -        outfile.write(wrapped + '\n')
+    outfile.write('\n')
+    outfile.write(get_optparser(options).format_option_help())


 def help_commands(outfile=None):

=== modified file 'bzrlib/option.py'
- --- bzrlib/option.py	2006-07-28 16:05:23 +0000
+++ bzrlib/option.py	2006-08-04 02:30:29 +0000
@@ -17,6 +17,7 @@
 # TODO: For things like --diff-prefix, we want a way to customize the
display
 # of the option argument.

+import optparse
 import re

 from bzrlib.trace import warning
@@ -112,6 +113,44 @@
             (typestring, type_list)
         raise BzrCommandError(msg)

+class EnumOption(object):
+
+    def __init__(self, name, factory, choices):
+        self.name = name
+        self.factory = factory
+        self.choices = choices
+        self.default = None
+
+    def python_name(self):
+        """Conver a name with spaces and caps to a python variable name"""
+        return self.name.lower().replace(' ', '_')
+
+    def add_option(self, parser, short_name):
+        """Add this option to an Optparse parser"""
+        group = optparse.OptionGroup(parser, self.name)
+        for name, help in self.choices:
+            option_strings = ['--%s' % name]
+            group.add_option(action='callback',
+                              callback=self._optparse_callback,
+                              callback_args=(name,),
+                              metavar=self.name,
+                              help=help,
+                              default=OptionParser.DEFAULT_VALUE,
+                              dest=self.python_name(),
+                              *option_strings)
+        parser.add_option_group(group)
+
+    def _optparse_callback(self, option, opt, value, parser, evalue):
+        setattr(parser.values, option.dest, self.factory(evalue))
+
+    def iter_switches(self):
+        """Iterate through the list of switches provided by the option
+
+        :return: an iterator of (name, short_name, argname, help)
+        """
+        return ((n, None, None, h) for n, h in self.choices)
+
+
 class Option(object):
     """Description of a command line option"""
     # TODO: Some way to show in help a description of the option argument
@@ -153,11 +192,85 @@
             if option is self:
                 return short

+    def get_negation_name(self):
+        if self.name.startswith('no-'):
+            return self.name[3:]
+        else:
+            return 'no-' + self.name
+
+    def add_option(self, parser, short_name):
+        """Add this option to an Optparse parser"""
+        option_strings = ['--%s' % self.name]
+        if short_name is not None:
+            option_strings.append('-%s' % short_name)
+        optargfn = self.type
+        if optargfn is None:
+            parser.add_option(action='store_true', dest=self.name,
+                              help=self.help,
+                              default=OptionParser.DEFAULT_VALUE,
+                              *option_strings)
+            negation_strings = ['--%s' % self.get_negation_name()]
+            parser.add_option(action='store_const', dest=self.name,
+                              help=optparse.SUPPRESS_HELP,
+                              const=OptionParser.DEFAULT_VALUE,
+                              *negation_strings)
+        else:
+            parser.add_option(action='callback',
+                              callback=self._optparse_callback,
+                              type='string', metavar=self.argname.upper(),
+                              help=self.help,
+                              default=OptionParser.DEFAULT_VALUE,
+                              *option_strings)
+
+    def _optparse_callback(self, option, opt, value, parser):
+        setattr(parser.values, self.name, self.type(value))
+
+    def iter_switches(self):
+        """Iterate through the list of switches provided by the option
+
+        :return: an iterator of (name, short_name, argname, help)
+        """
+        argname =  self.argname
+        if argname is not None:
+            argname = argname.upper()
+        yield self.name, self.short_name(), argname, self.help
+
+
+class OptionParser(optparse.OptionParser):
+    """OptionParser that raises exceptions instead of exiting"""
+
+    DEFAULT_VALUE = object()
+
+    def error(self, message):
+        raise BzrCommandError(message)
+
+
+def get_optparser(options):
+    """Generate an optparse parser for bzrlib-style options"""
+
+    parser = OptionParser()
+    parser.remove_option('--help')
+    short_options = dict((k.name, v) for v, k in
+                         Option.SHORT_OPTIONS.iteritems())
+    for option in options.itervalues():
+        option.add_option(parser, short_options.get(option.name))
+    return parser
+

 def _global_option(name, **kwargs):
     """Register o as a global option."""
     Option.OPTIONS[name] = Option(name, **kwargs)

+Option.OPTIONS['merge-type']=EnumOption('Merge type', get_merge_type, [
+                            ('merge3', 'Use built-in diff3-style merge'),
+                            ('diff3', 'Use external diff3 merge'),
+                            ('weave', 'Use knit merge')])
+
+Option.OPTIONS['log-format']=EnumOption('Log format', str, [
+                            ('long', 'Multi-line logs with merges shown'),
+                            ('short', 'Two-line logs'),
+                            ('line', 'One-line logs')])
+
 _global_option('all')
 _global_option('overwrite', help='Ignore differences between branches and '
                'overwrite unconditionally')
@@ -189,14 +302,8 @@
 _global_option('version')
 _global_option('email')
 _global_option('update')
- -_global_option('log-format', type=str, help="Use this log format")
- -_global_option('long', help='Use detailed log format. Same as
- --log-format long')
- -_global_option('short', help='Use moderately short log format. Same as
- --log-format short')
- -_global_option('line', help='Use log format with one line per revision.
Same as --log-format line')
 _global_option('root', type=str)
 _global_option('no-backup')
- -_global_option('merge-type', type=_parse_merge_type,
- -               help='Select a particular merge algorithm')
 _global_option('pattern', type=str)
 _global_option('quiet')
 _global_option('remember', help='Remember the specified location as a'
@@ -217,6 +324,5 @@
 Option.SHORT_OPTIONS['m'] = Option.OPTIONS['message']
 Option.SHORT_OPTIONS['r'] = Option.OPTIONS['revision']
 Option.SHORT_OPTIONS['v'] = Option.OPTIONS['verbose']
- -Option.SHORT_OPTIONS['l'] = Option.OPTIONS['long']
 Option.SHORT_OPTIONS['q'] = Option.OPTIONS['quiet']
 Option.SHORT_OPTIONS['p'] = Option.OPTIONS['prefix']

=== modified file 'bzrlib/tests/blackbox/test_bound_branches.py'
- --- bzrlib/tests/blackbox/test_bound_branches.py	2006-07-28 16:05:23 +0000
+++ bzrlib/tests/blackbox/test_bound_branches.py	2006-08-03 22:53:19 +0000
@@ -35,7 +35,7 @@
         super(TestLegacyFormats, self).setUp()
         self.build_tree(['master/', 'child/'])
         self.run_bzr('init', 'master')
- -        self.run_bzr('init', '--format=weave', 'child')
+        self.run_bzr('init', '--weave', 'child')
         os.chdir('child')

     def test_bind_format_6_bzrdir(self):

=== modified file 'bzrlib/tests/blackbox/test_init.py'
- --- bzrlib/tests/blackbox/test_init.py	2006-07-28 16:05:23 +0000
+++ bzrlib/tests/blackbox/test_init.py	2006-08-03 22:53:19 +0000
@@ -31,15 +31,15 @@
     def test_init_with_format(self):
         # Verify bzr init --format constructs something plausible
         t = self.get_transport()
- -        self.runbzr('init --format default')
+        self.runbzr('init --default')
         self.assertIsDirectory('.bzr', t)
         self.assertIsDirectory('.bzr/checkout', t)
         self.assertIsDirectory('.bzr/checkout/lock', t)

     def test_init_weave(self):
- -        # --format=weave should be accepted to allow interoperation with
+        # --weave should be accepted to allow interoperation with
         # old releases when desired.
- -        out, err = self.run_bzr('init', '--format=weave')
+        out, err = self.run_bzr('init', '--weave')
         self.assertEqual('', out)
         self.assertEqual('', err)


=== modified file 'bzrlib/tests/blackbox/test_logformats.py'
- --- bzrlib/tests/blackbox/test_logformats.py	2006-06-20 03:57:11 +0000
+++ bzrlib/tests/blackbox/test_logformats.py	2006-08-03 22:53:19 +0000
@@ -39,7 +39,7 @@
         self.bzr('commit', '-m', '2')

         # only the lines formatter is this short
- -        self.assertEquals(7, len(self.bzr('log', '--log-format',
'short').split('\n')))
+        self.assertEquals(7, len(self.bzr('log', '--short').split('\n')))

     def test_missing_default_format(self):
         self.setup_config()
@@ -91,7 +91,7 @@

         os.chdir('../b')

- -        self.assertEquals(9, len(self.bzr('missing', '--log-format',
'short', retcode=1).split('\n')))
+        self.assertEquals(9, len(self.bzr('missing', '--short',
retcode=1).split('\n')))

         os.chdir('..')


=== modified file 'bzrlib/tests/blackbox/test_merge.py'
- --- bzrlib/tests/blackbox/test_merge.py	2006-07-26 07:11:35 +0000
+++ bzrlib/tests/blackbox/test_merge.py	2006-08-03 22:53:19 +0000
@@ -44,7 +44,7 @@
     def test_merge_reprocess(self):
         d = BzrDir.create_standalone_workingtree('.')
         d.commit('h')
- -        self.run_bzr('merge', '.', '--reprocess', '--merge-type',
'weave')
+        self.run_bzr('merge', '.', '--reprocess', '--weave')

     def test_merge(self):
         from bzrlib.branch import Branch
@@ -63,11 +63,11 @@
         # We can't merge when there are in-tree changes
         self.runbzr('merge ../b', retcode=3)
         self.runbzr(['commit', '-m', "Like an epidemic of u's"])
- -        self.runbzr('merge ../b -r last:1..last:1 --merge-type blooof',
+        self.runbzr('merge ../b -r last:1..last:1 --blooof',
                     retcode=3)
- -        self.runbzr('merge ../b -r last:1..last:1 --merge-type merge3')
+        self.runbzr('merge ../b -r last:1..last:1 --merge3')
         self.runbzr('revert --no-backup')
- -        self.runbzr('merge ../b -r last:1..last:1 --merge-type weave')
+        self.runbzr('merge ../b -r last:1..last:1 --weave')
         self.runbzr('revert --no-backup')
         self.runbzr('merge ../b -r last:1..last:1 --reprocess')
         self.runbzr('revert --no-backup')

=== modified file 'bzrlib/tests/blackbox/test_remerge.py'
- --- bzrlib/tests/blackbox/test_remerge.py	2006-07-02 19:31:42 +0000
+++ bzrlib/tests/blackbox/test_remerge.py	2006-08-03 22:53:19 +0000
@@ -69,9 +69,9 @@
         os.unlink('question.OTHER')

         self.run_bzr_error(['jello is not versioned'],
- -                     'remerge', 'jello', '--merge-type', 'weave')
+                     'remerge', 'jello', '--weave')
         self.run_bzr_error(['conflicts encountered'],
- -                           'remerge', 'hello', '--merge-type', 'weave',
+                           'remerge', 'hello', '--weave',
                            retcode=1)

         self.failUnlessExists('hello.OTHER')
@@ -82,7 +82,7 @@
                            'file-id', 'hello.THIS')

         self.run_bzr_error(['conflicts encountered'],
- -                           'remerge', '--merge-type', 'weave', retcode=1)
+                           'remerge', '--weave', retcode=1)

         self.failUnlessExists('hello.OTHER')
         self.failIfExists('hello.BASE')
@@ -90,11 +90,11 @@
         self.assertFalse('hi world' in conflict_text)

         self.run_bzr_error(['Showing base is not supported.*Weave'],
- -                           'remerge', '.', '--merge-type', 'weave',
'--show-base')
+                           'remerge', '.', '--weave', '--show-base')
         self.run_bzr_error(['Can\'t reprocess and show base'],
                            'remerge', '.', '--show-base', '--reprocess')
         self.run_bzr_error(['conflicts encountered'],
- -                           'remerge', '.', '--merge-type', 'weave',
'--reprocess',
+                           'remerge', '.', '--weave', '--reprocess',
                            retcode=1)
         self.run_bzr_error(['conflicts encountered'],
                            'remerge', 'hello', '--show-base',

=== modified file 'bzrlib/tests/blackbox/test_selftest.py'
- --- bzrlib/tests/blackbox/test_selftest.py	2006-07-20 04:04:58 +0000
+++ bzrlib/tests/blackbox/test_selftest.py	2006-08-03 23:20:04 +0000
@@ -152,9 +152,8 @@
         result = self.run_bzr_subprocess('--versionn', retcode=3)
         result = self.run_bzr_subprocess('--versionn', retcode=None)
         self.assertContainsRe(result[1], 'unknown command')
- -        err = self.run_bzr_subprocess('merge', '--merge-type', 'magic
merge',
- -                                      retcode=3)[1]
- -        self.assertContainsRe(err, 'No known merge type magic merge')
+        err = self.run_bzr_subprocess('merge', '--magic-merge',
retcode=3)[1]
+        self.assertContainsRe(err, 'no such option: --magic-merge')


 class TestRunBzrError(ExternalBase):

=== modified file 'bzrlib/tests/blackbox/test_shared_repository.py'
- --- bzrlib/tests/blackbox/test_shared_repository.py	2006-05-05 01:29:34
+0000
+++ bzrlib/tests/blackbox/test_shared_repository.py	2006-08-03 22:53:19
+0000
@@ -45,7 +45,7 @@

     def test_init(self):
         self.run_bzr("init-repo", "a")
- -        self.run_bzr("init", "--format=default", "a/b")
+        self.run_bzr("init", "--default", "a/b")
         dir = bzrlib.bzrdir.BzrDir.open('a')
         self.assertIs(dir.open_repository().is_shared(), True)
         self.assertRaises(errors.NotBranchError, dir.open_branch)
@@ -57,7 +57,7 @@

     def test_branch(self):
         self.run_bzr("init-repo", "a")
- -        self.run_bzr("init", "--format=default", "a/b")
+        self.run_bzr("init", "--default", "a/b")
         self.run_bzr('branch', 'a/b', 'a/c')
         cdir = bzrlib.bzrdir.BzrDir.open('a/c')
         cdir.open_branch()
@@ -66,7 +66,7 @@

     def test_branch_tree(self):
         self.run_bzr("init-repo", "--trees", "a")
- -        self.run_bzr("init", "--format=default", "b")
+        self.run_bzr("init", "--default", "b")
         file('b/hello', 'wt').write('bar')
         self.run_bzr("add", "b/hello")
         self.run_bzr("commit", "-m", "bar", "b/hello")

=== modified file 'bzrlib/tests/blackbox/test_upgrade.py'
- --- bzrlib/tests/blackbox/test_upgrade.py	2006-07-28 16:05:23 +0000
+++ bzrlib/tests/blackbox/test_upgrade.py	2006-08-04 02:46:55 +0000
@@ -110,10 +110,10 @@
     def test_upgrade_explicit_metaformat(self):
         # users can force an upgrade to metadir format.
         url = get_transport(self.get_url('format_5_branch')).base
- -        # check --format takes effect
+        # check --metaweave takes effect
         bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirFormat5())
         (out, err) = self.run_bzr_captured(
- -            ['upgrade', '--format=metaweave', url])
+            ['upgrade', '--metaweave', url])
         self.assertEqualDiff("""starting upgrade of %s
 making backup of tree history
 %s.bzr has been backed up to %s.bzr.backup
@@ -134,10 +134,10 @@
         # users can force an upgrade to knit format from a metadir weave
         # branch
         url = get_transport(self.get_url('metadir_weave_branch')).base
- -        # check --format takes effect
+        # check --knit takes effect
         bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirFormat5())
         (out, err) = self.run_bzr_captured(
- -            ['upgrade', '--format=knit', url])
+            ['upgrade', '--knit', url])
         self.assertEqualDiff("""starting upgrade of %s
 making backup of tree history
 %s.bzr has been backed up to %s.bzr.backup
@@ -155,8 +155,8 @@
                                    repository.RepositoryFormatKnit1))

     def test_upgrade_repo(self):
- -        self.run_bzr('init-repository', '--format=metaweave', 'repo')
- -        self.run_bzr('upgrade', '--format=knit', 'repo')
+        self.run_bzr('init-repository', '--metaweave', 'repo')
+        self.run_bzr('upgrade', '--knit', 'repo')


 class SFTPTests(TestCaseWithSFTPServer):
@@ -173,10 +173,10 @@
         ui.ui_factory = self.old_ui_factory

     def test_upgrade_url(self):
- -        self.run_bzr('init', '--format=weave')
+        self.run_bzr('init', '--weave')
         t = get_transport(self.get_url())
         url = t.base
- -        out, err = self.run_bzr('upgrade', '--format=knit', url)
+        out, err = self.run_bzr('upgrade', '--knit', url)
         self.assertEqualDiff("""starting upgrade of %s
 making backup of tree history
 %s.bzr has been backed up to %s.bzr.backup

=== modified file 'bzrlib/tests/test_options.py'
- --- bzrlib/tests/test_options.py	2006-07-11 21:46:11 +0000
+++ bzrlib/tests/test_options.py	2006-08-04 02:25:40 +0000
@@ -1,8 +1,10 @@
 # Copyright (C) 2005, 2006 Canonical Ltd

+from bzrlib.builtins import cmd_commit, cmd_log, cmd_status
+from bzrlib.commands import Command, parse_args
+from bzrlib import errors
+from bzrlib import option
 from bzrlib.tests import TestCase
- -from bzrlib.commands import Command, parse_args
- -from bzrlib.builtins import cmd_commit, cmd_log, cmd_status

 # TODO: might be nice to just parse them into a structured form and test
 # against that, rather than running the whole command.
@@ -28,8 +30,9 @@
     def test_option_help(self):
         """Options have help strings."""
         out, err = self.run_bzr_captured(['commit', '--help'])
- -        self.assertContainsRe(out, r'--file.*file containing commit
message')
- -        self.assertContainsRe(out, r'--help.*-h')
+        self.assertContainsRe(out, r'--file(.|\n)*file containing commit'
+                                   ' message')
+        self.assertContainsRe(out, r'-h.*--help')

     def test_option_help_global(self):
         """Global options have help strings."""
@@ -44,12 +47,55 @@

     def test_unknown_short_opt(self):
         out, err = self.run_bzr_captured(['help', '-r'], retcode=3)
- -        self.assertContainsRe(err, r'unknown option')
+        self.assertContainsRe(err, r'no such option')

     def test_allow_dash(self):
         """Test that we can pass a plain '-' as an argument."""
         self.assertEqual((['-'], {}), parse_args(cmd_commit(), ['-']))

+    def test_conversion(self):
+        def parse(options, args):
+            parser = option.get_optparser(dict((o.name, o) for o in
options))
+            return parser.parse_args(args)
+        options = [option.EnumOption('Lawn mower', str,
+                   [('fast', 'mow quickly'), ('careful', 'mow
carefully')])]
+        opts, args = parse(options, ['--fast', '--careful'])
+        self.assertEqual('careful', opts.lawn_mower)
+        options = [option.EnumOption('Number', int, [('11', 'one'),
+                                                     ('22', 'two')])]
+        opts, args = parse(options, ['--22'])
+        self.assertEqual(22, opts.number)
+
+        options = [option.Option('hello')]
+        opts, args = parse(options, ['--no-hello', '--hello'])
+        self.assertEqual(True, opts.hello)
+        opts, args = parse(options, [])
+        self.assertEqual(option.OptionParser.DEFAULT_VALUE, opts.hello)
+        opts, args = parse(options, ['--hello', '--no-hello'])
+        self.assertEqual(option.OptionParser.DEFAULT_VALUE, opts.hello)
+        options = [option.Option('number', type=int)]
+        opts, args = parse(options, ['--number', '6'])
+        self.assertEqual(6, opts.number)
+        self.assertRaises(errors.BzrCommandError, parse, options,
['--number'])
+        self.assertRaises(errors.BzrCommandError, parse, options,
+                          ['--no-number'])
+
+    def test_iter_switches(self):
+        opt = option.EnumOption('Lawn mower', str,
+                                [('fast', 'mow quickly'),
+                                 ('careful', 'mow carefully')])
+        self.assertEqual(list(opt.iter_switches()),
+                         [('fast', None, None, 'mow quickly'),
+                          ('careful', None, None, 'mow carefully')])
+        opt = option.Option('hello', help='fg')
+        self.assertEqual(list(opt.iter_switches()),
+                         [('hello', None, None, 'fg')])
+        opt = option.Option('hello', help='fg', type=int)
+        self.assertEqual(list(opt.iter_switches()),
+                         [('hello', None, 'ARG', 'fg')])
+        opt = option.Option('hello', help='fg', type=int, argname='gar')
+        self.assertEqual(list(opt.iter_switches()),
+                         [('hello', None, 'GAR', 'fg')])

 #     >>> parse_args('log -r 500'.split())
 #     (['log'], {'revision': [<RevisionSpec_int 500>]})

=== modified file 'tools/doc_generate/autodoc_man.py'
- --- tools/doc_generate/autodoc_man.py	2006-07-31 06:13:23 +0000
+++ tools/doc_generate/autodoc_man.py	2006-08-03 23:45:50 +0000
@@ -110,19 +110,19 @@
     if options:
         option_str = "\nOptions:\n"
         for option_name, option in sorted(options.items()):
- -            l = '    --' + option_name
- -            if option.type is not None:
- -                l += ' ' + option.argname.upper()
- -            short_name = option.short_name()
- -            if short_name:
- -                assert len(short_name) == 1
- -                l += ', -' + short_name
- -            l += (30 - len(l)) * ' ' + option.help
- -            # TODO: Split help over multiple lines with
- -            # correct indenting and wrapping.
- -            wrapped = textwrap.fill(l, initial_indent='',
- -                                    subsequent_indent=30*' ')
- -            option_str = option_str + wrapped + '\n'
+            for name, short_name, argname, help in option.iter_switches():
+                l = '    --' + name
+                if argname is not None:
+                    l += ' ' + argname
+                if short_name:
+                    assert len(short_name) == 1
+                    l += ', -' + short_name
+                l += (30 - len(l)) * ' ' + help
+                # TODO: Split help over multiple lines with
+                # correct indenting and wrapping.
+                wrapped = textwrap.fill(l, initial_indent='',
+                                        subsequent_indent=30*' ')
+                option_str = option_str + wrapped + '\n'

     aliases_str = ""
     if cmd.aliases:


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iD8DBQFE2Mnx0F+nu1YWqI0RAgsoAJ9or16IQdFWUo/HiYBuvBaTMYaDAgCdGveG
5gO/eRJDpWTXwzkVcXBg9hs=
=IRwh
-----END PGP SIGNATURE-----




More information about the bazaar mailing list