Attachment 'lwickjr.Module.Alias.py'

Download

   1 """Extend I.D.L.E. with an Alias facility for the command shell.
   2 
   3 This I.D.L.E. extension provides the following functionality enhancements:
   4 * an Alias facility for I.D.L.E.'s command shell
   5 * an 'alias' command for the Alias facility
   6 * an 'unalias' command for the Alias facility
   7 
   8 The Alias facility, implemented by the function runsource, enhances
   9 the I.D.L.E. command shell by promoting all fully-qualified callable
  10 objects and the string keys of all callable objects stored in the
  11 module-global dictionary "GlobalAliases" into "commands", UNDER
  12 SPECIFIC CIRCUMSTANCES.
  13 
  14 At the command prompt ONLY [i.e., NOT in module source code!], before
  15 a line is submitted to the normal I.D.L.E. execution machinery,
  16 several checks are performed:
  17 
  18 * The first 'word' is split from the rest of the string, and the two
  19   chunks are saved as Command and Args.
  20 * Command is then looked up in the module-global dictionary
  21   GlobalAliases.
  22   If found, the corresponding value becomes the Command, else the
  23   command string is evaluated in the context of the module __main__,
  24   and the result of the execution becomes the Command.
  25 * If the preceeding operation yeilds a callable, Args is also evaluated
  26   in the context of module __main__. If the evaluation succeeds, the
  27   result becomes the Args.
  28 * If Args is not by now a tuple, it is wrapped in one.
  29 
  30   Up to this point, any errors are trapped and silently dealt with,
  31   diverting evaluation of the command to "normal" channels if unable
  32   to proceed.
  33 
  34 ## XXX TO DO: before handing a command off to the "normal" evaluator,
  35 ## attempt to import the presumed module named by the command, and, if
  36 ## successful, update the dictionary of defined Alises from a
  37 ## specially-named dictionary found there, or from the dictionary
  38 ## returned by a specially-named callable found there, then enter the
  39 ## module into the namespace of module __main__.
  40 
  41 * The Command callable is then called, and the Args tuple is used to
  42   supply positional arguments.
  43   If an error occurs, a traceback is printed, else the result of the
  44   call, if non-None, is printed.
  45   In either case, a new command line is solicited.
  46 
  47 If the fully-qualified callable is followed immediately by an open
  48 paren and a space, IN THAT ORDER, the "normal" command processing
  49 takes over. This is useful for situations when you want to prevent the
  50 Alias mechanism from evaluating the result of a function that returns
  51 a callable. Another method is to put a space BEFORE the open paren,
  52 letting Alias evaluate the argstring as a parenthasis-grouped
  53 expression to be passed to the callable. Examples:
  54 
  55  >>> type {}
  56  <type 'dict'>
  57  >>> type({})
  58  {}
  59  >>> type ({})
  60  <type 'dict'>
  61  >>> type( {})
  62  <type 'dict'>
  63  >>> 
  64 
  65 The first three examples are evaluated by the Alias evaluator; the
  66 fourth is evaluated by the "normal" evaluator. The second example is
  67 likely a source for confusion: Note that <type 'dict'> is callable,
  68 and that calling it without arguments yeilds an empty dictionary!
  69 
  70 The alias command, implemented by the function alias, provides four
  71 features:
  72 
  73 * If called with no arguments, or with a first argument equal to an
  74   empty string, the current dictionary of defined GlobalAliases is
  75   displayed nicely formatted.
  76 * If called with a first argument that is [a subclass of] a dictionary,
  77   the dictionary is used to update the dictionary of defined GlobalAliases.
  78 * If called with a non-None second argument, the second argument is
  79   inserted into the dictionary of defined GlobalAliases using the first
  80   argument as the key.
  81 * Otherwise, the first [and presumably only] argument is looked up in
  82   the dictionary of defined GlobalAliases, and the pair is displayed.
  83 
  84 The unalias command, implemented by the function unalias, provides a
  85 single feature: if the only argument matches a key in the
  86 module-global dictionary GlobalAliases, the key:value pair is deleted, else
  87 a simple error message is displayed.
  88 """
  89 
  90 import UT, code, os, sys, types, __builtin__
  91 
  92 class Alias:
  93  def __init__(Self, editwin):
  94   pass
  95 
  96 def runsource(self, source, filename="<input>", symbol="single"):
  97  """Compile and run some source in the interpreter.
  98 
  99  Arguments are as for compile_command().
 100 
 101  One several things can happen:
 102 
 103  1) The input is empty. Nothing happens.
 104 
 105  2) The input matches a registered Alias. The matching callable is
 106  called with the supplied arguments, if any.
 107 
 108  3) The input evaluates to a callable. The callable is called with the
 109  supplied arguments, if any.
 110 
 111  4) The input matches an importable module. The module is imported,
 112  bound in the source context, and checked for any of several
 113  signatures:
 114 
 115  4a) The module defines a mapping named __Aliases__. The dictionary of
 116  registered Aliases is updated from this dictionary.
 117 
 118  4b) The module defines a callable named __Alias__. The callable
 119  becomes the command [and the module is NOT bound].
 120 
 121  Note: 4a and 4b are not mutually exclusive, but the dictionary update
 122  is performed _before_ the function call.
 123 
 124  5) The input is incorrect; compile_command() raised an exception
 125  (SyntaxError or OverflowError).  A syntax traceback will be printed
 126  by calling the showsyntaxerror() method.
 127 
 128  6) The input is incomplete, and more input is required;
 129  compile_command() returned None.  Nothing happens.
 130 
 131  7) The input is complete; compile_command() returned a code object.
 132  The code is executed by calling self.runcode() (which also handles
 133  run-time exceptions, except for SystemExit).
 134 
 135  The return value is True in case 6, False in the other cases (unless
 136  an exception is raised).  The return value can be used to decide
 137  whether to use sys.ps1 or sys.ps2 to prompt the next line.
 138 
 139  """
 140 ## from UT import ThisLine
 141 ## print >> sys.stderr, "Here goes!"
 142 ## print >> sys.stderr, '### %r %r' % (ThisLine(), source)
 143  if not source.strip(): source = 'pass' # Case 1: Empty line; do nothing.
 144 ## print >> sys.stderr, '### %r %r' % (ThisLine(), source.split())
 145 ## print >> sys.stderr, '### %r %r' % (ThisLine(), source.split()[0])
 146  Command, Args = (source.split(' ', 1) + [''])[:2]
 147 ## print >> sys.stderr, '### %r %r %r' % (ThisLine(), Command, Args)
 148  import __main__
 149  # Case 2: Is this a REGISTERED Alias?
 150  if Command in GlobalAliases.keys():
 151   Command = GlobalAliases[Command]
 152  else:
 153   # Case 3: Ok, it isn't registered, so try to evaluate it.
 154   try: Command = eval(Command, self.locals)
 155   except: pass
 156 ## print >> sys.stderr, '### %r %r %r' % (ThisLine(), Command, Args)
 157   
 158  # Case 4: It wasn't a callable, so try to import it as a module.
 159  if isinstance(Command, types.StringType): # and (Args == ''):
 160   try:    exec 'import %s as Command' % Command #; print "Import succeeded."
 161   except: pass
 162  if isinstance(Command, types.ModuleType):
 163 ##  print >> sys.stderr, '### %r import %r' % (ThisLine(), Command.__name__)
 164 
 165   # Case 4a: The module defines a mapping named __Aliases__.
 166   try:    GlobalAliases.update(Command.__Aliases__)
 167   except: pass
 168 
 169   # Case 4b: The module defines a callable named __Alias__.
 170   try:    Command = Command.__Alias__
 171   except: pass
 172 ##  print >> sys.stderr, '### %r %r %r' % (ThisLine(), Command, Args)
 173  if isinstance(Command, types.ModuleType):
 174   source = 'import %s;%s' % (source, source,)
 175 
 176  # If we have a callable, we're going to need to evaluate the
 177  # arguments, if any.
 178  if callable(Command):
 179 
 180   # I know, I know, the code below makes it awkward to pass a
 181   # single empty string to commands; use
 182   # >>> blah '',
 183   # [It's still easier than typing two parenthases.]
 184   if Args == '':
 185    Args = ()
 186   else:
 187    try:    Args = eval(Args, self.locals)
 188    except: pass
 189    if not isinstance(Args, types.TupleType):
 190     Args = (Args,)
 191 ##  print >> sys.stderr, '### %r %r %r' % (ThisLine(), Command, Args)
 192 ##  print >> sys.stderr, '### %r call %r%r' % (ThisLine(), Command, Args)
 193   __builtin__._AliasCommand = Command
 194   __builtin__._AliasArgs = Args
 195   source = '_AliasCommand(*_AliasArgs)'
 196 
 197  try:
 198   code = self.compile(source, filename, symbol)
 199  except (OverflowError, SyntaxError, ValueError):
 200   # Case 5
 201   self.showsyntaxerror(filename)
 202   return False
 203 
 204  if code is None:
 205   # Case 6
 206   return True
 207 
 208  # Case 7
 209  self.runcode(code)
 210  return False
 211 
 212 ##   if Args is not '':
 213 ##    # It's a module and we have Args; try to call its __init__ function.
 214 ##    print >> sys.stderr, '### 181 call %s.__init__%s' % (Command, Args)
 215 ##    try: Command.__init__(*Args)
 216 ##    except: self.showtraceback()
 217 ##    return 0
 218 ##
 219 ##   if 'Aliases' in Command.__dict__.keys() \
 220 ##      and isinstance(Command.Aliases, types.DictType):
 221 ##    # It's a module and we don't have args, but we DO have a dictionary
 222 ##    # named Aliases.
 223 ##    print >> sys.stderr, '### 190 bind', Command
 224 ##    if Module: self.locals[Module] = Command
 225 ##    GlobalAliases.update(Command.Aliases)
 226 ##    return 0
 227 ##
 228 ##   if 'MakeAliases' in Command.__dict__.keys() \
 229 ##      and isinstance(Command.MakeAliases, types.FunctionType):
 230 ##    # It's a module and we don't have args or an Aliases dictionry, but
 231 ##    # we DO have a function named MakeAliases...
 232 ##    Aliases = Command.MakeAliases()
 233 ##    if isinstance(Aliases, types.DictType):
 234 ##     # ...AND it returnes a dictionary.
 235 ##     print >> sys.stderr, '### 202 bind', Command
 236 ##     self.locals[Command] = Module
 237 ##     GlobalAliases.update(Aliases)
 238 ##     return 0
 239 ##
 240 ##  print >> sys.stderr, '### 207', `source`
 241 ##  return PyShell.InteractiveInterpreter.runsource(self, source, filename)
 242 ##  return oldrunsource(self, source)
 243 ## finally:
 244 ##  print >> sys.stderr, "How's that?"
 245 ##  self.tkconsole.endexecuting()
 246 ##  self.tkconsole.resetoutput()
 247 ##  if self.save_warnings_filters is not None:
 248 ##   PyShell.warnings.filters[:] = self.save_warnings_filters
 249 ##   self.save_warnings_filters = None
 250 
 251 def _help(Topic=None):
 252  if Topic in GlobalAliases.keys():
 253   help(GlobalAliases[Topic])
 254  else:
 255   help(Topic)
 256 
 257 _help.__doc__ = help.__doc__
 258 
 259 def alias(Name='', Func=None):
 260  # Don't bother with sanity checks; runsource takes care of that.
 261  print `Name, Func`
 262  if Name == '':
 263   import UT
 264   try:
 265    UT.dump(dict(map(lambda (x, y): (x, '.'.join([y.__module__, y.__name__])),
 266                     GlobalAliases.items())))
 267   except:
 268    UT.dump(GlobalAliases)
 269  elif isinstance(Name, types.DictType):
 270   GlobalAliases.update(Name)
 271  elif Func is None:
 272   print ' %s: %s' % (Name, GlobalAliases.get(Name, "Undefined"))
 273  else:
 274   GlobalAliases[Name] = Func
 275 
 276 def unalias(Name):
 277  try:
 278   del GlobalAliases[Name]
 279  except:
 280   print "Error: %s is not a defined alias." % `Name`
 281 
 282 def usage(Topic):
 283  if Topic in GlobalAliases.keys():
 284   Topic = GlobalAliases[Topic]
 285  try:
 286   if Topic.__doc__: print Topic.__doc__
 287   else: print 'None.'
 288  except: print 'None'
 289 
 290 __Aliases__ = {
 291  'alias':   alias,
 292  'help':    _help,
 293  'unalias': unalias,
 294  'usage':   usage,
 295  }
 296 
 297 GlobalAliases = {}
 298 code.InteractiveInterpreter.runsource = runsource
 299 sys.modules['Alias'] = sys.modules['idlelib.Alias']
 300 print "Alias installed."

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2005-11-19 16:33:10, 10.9 KB) [[attachment:lwickjr.Module.Alias.py]]
  • [get | view] (2005-11-19 16:34:55, 7.0 KB) [[attachment:lwickjr.Module.Edit.py]]
  • [get | view] (2005-11-26 16:46:21, 21.6 KB) [[attachment:lwickjr.Module.UT.py]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.

Unable to edit the page? See the FrontPage for instructions.