commandmanager.py :  » Development » Lyntin » lyntin-4.2 » lyntin » 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 » Development » Lyntin 
Lyntin » lyntin 4.2 » lyntin » commandmanager.py
#########################################################################
# This file is part of Lyntin.
#
# Lyntin 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.
#
# Lyntin 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 this program.  If not, see <http://www.gnu.org/licenses/>.
#
# copyright (c) Free Software Foundation 2001-2007
#
# $Id: commandmanager.py,v 1.8 2007/07/24 00:39:03 willhelm Exp $
#########################################################################
"""
Lyntin comes with a series of X{command}s for manipulating aliases, 
actions, highlights, and various other things.  Both the commands and 
the managers that hold the data are all defined in various Lyntin 
modules in the "modules/" subdirectory and are loaded up at Lyntin 
startup.

Lyntin has an extremely powerful argument parser that allows Lyntin
module writers to worry about the functionality of their command without
having to deal with parsing out the arguments, type-checking, 
raising exceptions with command syntax help, and data conversion.

Commands are stored internally in the "CommandManager".  They are
global to Lyntin--there are no commands that only exist in the session
they were declared in.  Commands, however, are executed in a specific
session.  When they are executed, they are given three arguments:
the session object for the session they were executed in, an argument
dictionary from the argument parser, and the exact input the user
typed.

Look at the modules/lyntincmds.py and modules/tintincmds.py modules for 
command examples.  Additionally, check out the Lyntin module repository
on http://lyntin.sourceforge.net/ for more examples.

X{default_resolver_hook}::

   Allows you to fill in values for arguments the user didn't specify 
   on the command line.  

   Arg mapping: {"session": Session, "commandname", string}

   session - the session this command was executed in.

   commandname - the name of the command that was executed

"""
import inspect, re
from lyntin import manager,exported,argparser,utils

class _CommandData:
  """
  Holds data relating to a command.  It's a helper class.
  """
  def __init__(self):
    self._name = ""
    self._func = None
    self._argparser = None
    self._fqn = ""

  def __repr__(self): return self._name
  def __str__(self): return self._name

  def setName(self, name): self._name = name
  def getName(self): return self._name
  def setNameAdjusted(self, name): self._name_adjusted = name
  def getNameAdjusted(self): return self._name_adjusted
  def setFunc(self, func): self._func = func
  def getFunc(self): return self._func
  def setArgParser(self, ap): self._argparser = ap
  def getArgParser(self): return self._argparser
  def setFQN(self, fqn): self._fqn = fqn
  def getFQN(self): return self._fqn

class CommandManager(manager.Manager):
  """ 
  The CommandManager holds a series of _CommandData objects
  and methods to manipulate and use them.  Lyntin developers
  can add their own commands to Lyntin.

  There should be one instance of the CommandManager and
  the engine should have it.  All CommandManager interaction
  should be done through the exported module.
  """
  def __init__(self, e):
    self._commands = {}
    self._engine = e

  def getCommands(self):
    """
    Returns a list of the commands we have registered.

    @return: all the commands that have been registered
    @rtype:  list of strings
    """
    return self._commands.keys()

  def addCommand(self, name, func, arguments=None, argoptions=None, helptext=""):
    """
    Registers a command.

    @param name: the name of the command to add
    @type  name: string

    @param func: the function that handles the command
    @type  func: function

    @param arguments: the argument spec to create the argparser
    @type  arguments: string

    @param argoptions: options for how the argument spec should be parsed
    @type  argoptions: string

    @param helptext: the help text for this command for the user
    @type  helptext: string

    @raise ValueError: if the function is uncallable
    @raise Exception: if the argument spec for the command is unparseable
    """
    if not callable(func):
      raise ValueError, "%s is uncallable." % name

    cd = _CommandData()

    syntaxline = ""

    # try to figure out the arguments and syntax line stuff
    if arguments != None:
      try:
        cd.setName(name)
        cd.setArgParser(argparser.ArgumentParser(arguments, argoptions))
        syntaxline = utils.wrap_text(cd.getArgParser().syntaxline, 60, 6)
      except Exception, e:
        raise Exception, "Error with arguments for command %s, (%s)" % (name,e)

    cd.setFunc(func)

    # removeCommand tests to see if the command exists already and will
    # remove it if it does.
    self.removeCommand(name)

    # toss the command thing in the dict
    self._commands[name] = cd

    # deal with the help text
    if not helptext:
      if func.__doc__:
        helptext = inspect.getdoc(func)
      else:
        helptext = "\nThis command has no help."

    if name.startswith("^"):
      cd.setNameAdjusted(name[1:])
    else:
      cd.setNameAdjusted(name)

    if syntaxline:
      commandchar = self._engine.getConfigManager().get("commandchar")
      helptext = ("syntax: %s%s %s\n" % 
             (commandchar, cd.getNameAdjusted(), syntaxline) + helptext)

    fqn = exported.add_help(cd.getNameAdjusted(), helptext)
    cd.setFQN(fqn)
        
  def removeCommand(self, name):
    """
    Removes a command (and the help text) for whatever reasons.

    @param name: the name of the command to remove
    @type  name: string

    @return: 0 if no command was found, 1 if the command was removed
        succesfully.
    @rtype: boolean
    """
    if self._commands.has_key(name):
      cd = self._commands[name]
      del self._commands[name]
      try:
        exported.remove_help(cd.getFQN())
      except:
        pass
      return 1
    return 0

  def getCommand(self, name):
    """
    Returns the function for a given command name.

    @param name: the name of the command to retrieve
    @type  name: string

    @return: the function in question or None
    @rtype:  function
    """
    if self._commands.has_key(name):
      return self._commands[name].getFunc()

    if self._commands.has_key("^" + name):
      return self._commands["^" + name].getFunc()

    # this is kind of a kluge to handle the #@ arbitrary
    # python stuff so that it can be in its own module.
    if name.startswith("@") and self._commands.has_key("@"):
      return self._commands["@"].getFunc()

    return None

  def getArgParser(self, name):
    """
    Returns the arguments parser for a given command name.

    @param name: the name of the command whose arguments should be
        retrieved
    @type  name: string

    @return: argument parsing object to convert incoming arguments
        into a dictionary to pass to the command function
    @rtype: ArgParser instance
    """
    if self._commands.has_key(name):
      return self._commands[name].getArgParser()

    return None

  def filter(self, args):
    """
    Takes in user command lines and handles commands that start
    with a Lyntin command character.

    @param args: (session, internal boolean, ..., current input text)
    @type  args: tuple

    @return: None if we handled the input, or the current input text if 
        we didn't
    @rtype:  None or string
    """
    ses = args["session"]
    internal = args["internal"]
    input = args["dataadj"]

    commandchar = self._engine.getConfigManager().get("commandchar")
    if len(input) > 1 and input.startswith(commandchar):
      input = input[1:]

      # splits out the command name from the rest of the command line
      words = input.split(" ",1)

      # We want an empty argument list if there was one, don't want
      # array out-of-bounds issues       
      if len(words) < 2: words.append("")

      # this checks to see if it's a special #@ command.
      if input.startswith("@"):
        self.getCommand("@")(ses, input.split(" "), input)
        if internal==0: ses.prompt()
        return

      # this finds the first matching command and ends there.
      commands = self.getCommands()
      commands.sort()
      for mem in commands:
        command = None
        if mem.startswith("^"):
          if re.compile(mem).search(words[0]):
            command = self.getCommand(mem)
        else:
          if mem.startswith(words[0]):
            command = self.getCommand(mem)

        if command:
          argumentparser = self.getArgParser(mem)
          if argumentparser == None:
            command(ses, input.split(" "), input)
          else:
            # for printing out the error message, we remove the ^
            # from the command name if it's there.
            fixedmem = mem
            if len(fixedmem) > 0 and fixedmem.startswith("^"):
              fixedmem = fixedmem[1:]

            resolver = exported.hook_spam("default_resolver_hook", 
                                {"session": ses, "commandname": mem}, 
                                mappingfunc=exported.query_mapper, 
                                donefunc=exported.query_done)

            try:
              argdict = argumentparser.parse(words[1], resolver)
              argdict["command"]=mem
              command(ses, argdict, input)
            except ValueError, e:
              exported.write_error("%s: %s\nsyntax: %s%s %s" % 
                                   (fixedmem, e, commandchar, fixedmem,
                                    argumentparser.syntaxline))
            except argparser.ParserException, e:
              exported.write_error("%s: %s\nsyntax: %s%s %s" % 
                                   (fixedmem, e, commandchar, fixedmem,
                                    argumentparser.syntaxline))
          if internal == 0:
            ses.prompt()
          break

      else:
        if internal == 0:
          ses.prompt()
        exported.write_error("Not a valid command: %s" % (words[0]))
      return
    return args["dataadj"]

# Local variables:
# mode:python
# py-indent-offset:2
# tab-width:2
# End:
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.