Command.py :  » XML » 4Suite » 4Suite-XML-1.0.2 » Ft » Lib » CommandLine » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » XML » 4Suite 
4Suite » 4Suite XML 1.0.2 » Ft » Lib » CommandLine » Command.py
########################################################################
# $Header: /var/local/cvsroot/4Suite/Ft/Lib/CommandLine/Command.py,v 1.13.6.1 2006/10/16 21:52:34 jkloth Exp $
"""
Superclass for a command that can be invoked by a command-line script.

Copyright 2004 Fourthought, Inc. (USA).
Detailed license and copyright information: http://4suite.org/COPYRIGHT
Project home, documentation, distributions: http://4suite.org/
"""

import sys

import CommandLineUtil
import FancyGetOpt

from Ft.Lib.CommandLine import CONSOLE_WIDTH,Options,Arguments
from Ft.Lib.CommandLine.CommandLineUtil import ArgumentError

class Command:
    """
    Superclass for a command that can be invoked by a command-line script.
    Most commands won't need to subclass this.

    A Command object encapsulates, for a particular command, a description,
    usage example, a set of valid options & arguments, methods for
    validating the actual options and arguments entered, a function for
    command invocation, and an association with subordinate Commands.

    A tree of commands can be created by associating each Command instance
    with its subordinates. Typically, only the leaves of the tree will have
    functionality; the branches just provide ways of grouping the leaves
    and will not need to encapsulate the invocation functions themselves.
    """ # -- clear as mud. how about some examples
    def __init__(self,
                 name,
                 description,
                 example,
                 verbose_description,
                 function=None,
                 options=None,
                 arguments=None,
                 subCommands=None,
                 fileName=None,
                 ):

        self.name = name
        self.description = description
        self.function = function
        self.example = example
        self.verbose_description = verbose_description
        self.options = options or Options.Options()
        self.arguments = arguments or []
        self.subCommands = subCommands or {}
        self._fileName = fileName

        if isinstance(self.subCommands, (list, tuple)):
            cmds = {}
            for c in self.subCommands:
                cmds[c.name] = c
            self.subCommands = cmds

        if not isinstance(self.options, Options.Options):
            # Options constructor takes care of validating option values
            self.options = Options.Options(self.options)

        for arg in self.arguments:
            if not isinstance(arg, Arguments.Argument):
                raise ValueError("argument %d is not an instance of Argument"
                                 % self.arguments.index(arg))
        return

    def build_parent_relationship(self):
        for c in self.subCommands.values():
            c.parent = self
            c.build_parent_relationship()

    def break_parent_relationship(self):
        for c in self.subCommands.values():
            if hasattr(c,'parent'):
                delattr(c,'parent')
            c.break_parent_relationship()


    def flatten_command_tree(self,level,previousName=''):
        if previousName:
            fName = previousName + '.' + self.name
        else:
            fName = self.name

        res = [(level,self,fName)]
        names = self.subCommands.keys()
        names.sort()
        for name in names:
            res.extend(self.subCommands[name].flatten_command_tree(
                level+1,previousName = fName))
        return res


    def run(self, options, arguments):
        if not self.function:
            raise CommandLineUtil.ArgumentError(self, "subcommand required")
        return self.function(options, arguments)


    def validate_arguments(self, arglist):
        eatenArgs = {}
        arglist = filter(str.strip, arglist)
        for arg in self.arguments:
            eaten, arglist = arg.validate(self, arglist)
            if eaten is not None:
                eatenArgs[arg.name] = eaten
        if arglist:
            raise ArgumentError(self, "invalid argument %s" % arglist[0])
        return eatenArgs

    def validate_options(self,options):
        if options.get('help'):
            raise ArgumentError(self, '')
        for opt in self.options:
            opt.apply_options(options)
        for opt in self.options:
            opt.validate()
        return 1


    def _gen_usage(self,command_string):
        """
        Generates the usage summary, example command line, and
        descriptions of options and subcommands or arguments
        """
        lines = self.__gen_command_line_help(command_string)

        # saved for use in the example
        command_size = len(command_string)

        # generate the example, if available
        if self.example is not None:
            lines.append('\nExample:')
            text_width = CONSOLE_WIDTH - command_size
            text = CommandLineUtil.wrap_text(self.example, text_width)
            lines.append(command_string + text[0])
            indent = ' ' * command_size
            lines.extend([ indent + s for s in text[1:] ])

        # generate the option descriptions
        option_desc = self.options.generate_help()
        if option_desc:
            lines.append('\nOptions:')
            lines.extend(option_desc)

        # generate the subcommand descriptions
        if self.subCommands:
            max_cmd = 0
            for cmd in self.subCommands.keys():
                if len(cmd) > max_cmd:
                    max_cmd = len(cmd)

            lines.append('\nSubcommands:')
            # column size = indent + longest command + gutter
            indent = ' ' * (2 + max_cmd + 2) + '  '
            text_width = CONSOLE_WIDTH - len(indent)
            names = self.subCommands.keys()
            names.sort()
            for name in names:
                cmd = self.subCommands[name]
                text = CommandLineUtil.wrap_text(cmd.description,
                                                 text_width)
                lines.append('  %-*s  %s' % (max_cmd, name, text[0]))
                lines.extend([ indent + s for s in text[1:] ])

        # generate the argument descriptions
        if self.arguments:
            max_arg = 0
            for arg in self.arguments:
                if len(arg.name) > max_arg:
                    max_arg = len(arg.name)

            lines.append('\nArguments:')
            # column size = indent + longest command + gutter
            indent = ' ' * (2 + max_arg + 2)
            text_width = CONSOLE_WIDTH - len(indent)
            for arg in self.arguments:
                text = CommandLineUtil.wrap_text(arg.description,
                                                 text_width)
                lines.append('  %-*s  %s' % (max_arg, arg.name,
                                             text[0]))
                lines.extend([ indent + s for s in text[1:] ])

        lines.append('')    # add a blank line
        return lines


    def _parse_command_opts(self, arglist):
        options, arglist = FancyGetOpt.FancyGetopt(self, self.options, arglist)
        if not self.validate_options(options):
            return None

        # Args can either be a subcommand, or the start of the argument
        # list. Subcommand takes precedence.
        if self.subCommands:
            try:
                cmd = arglist[0]
            except IndexError:
                msg = "subcommand required"
                raise CommandLineUtil.ArgumentError(self, msg)
            try:
                cmd = self.subCommands[cmd]
            except KeyError:
                msg = "invalid subcommand: %s" % cmd
                raise CommandLineUtil.ArgumentError(self, msg)
            parsed = cmd._parse_command_opts(arglist[1:])
        else:
            parsed = (self, options, self.validate_arguments(arglist))
        return parsed


    def __gen_command_line_help(self, command_string):
        """
        Generates the indented usage summary only.
        """
        # command_string looks like this: '  4ss create user '
        # i.e., it is '4ss create user', indented and ready to
        # have the option & argument syntax appended like so:
        # '  4ss create user (syntax line 1)
        #                    (syntax line 2)
        #                    (syntax line 3)'

        # generate the option/arg syntax string, which looks like this:
        # '[--help] [[--username=<USER>] | [--anonymous]]
        #  [--password=<PASSWORD>] [--port=<PORT>] [--host=<HOST>]
        #  [--container=<PATH>] userName '
        syntax_string = ''
        for opt in self.options:
            syntax_string += opt.gen_command_line() + ' '
        if self.subCommands:
            if len(self.arguments):
                syntax_string += '['
            syntax_string += '<subcommand> '
            if len(self.arguments):
                syntax_string += '['
            syntax_string += '<subcommand> '
            if len(self.arguments):
                syntax_string += '] | ['
        if self.arguments:
            for arg in self.arguments:
                syntax_string += arg.gen_command_line() + ' '
            if self.subCommands:
                syntax_string += ']'

        # wrap the syntax line to a width that won't exceed the console
        # width when appended to command_string
        command_size = len(command_string)
        syntax_string_lines = CommandLineUtil.wrap_text(
            syntax_string, CONSOLE_WIDTH - command_size)

        # append first line of wrapped syntax string to command_string
        # and indent the remaining lines appropriately
        lines = [command_string + syntax_string_lines[0]]
        indent = ' ' * command_size
        lines.extend([ indent + s for s in syntax_string_lines[1:] ])


        return lines
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.