src/extras/pyrepl/completer.py
changeset 0 ca70ae20a155
equal deleted inserted replaced
-1:000000000000 0:ca70ae20a155
       
     1 #   Copyright 2000-2004 Michael Hudson mwh@python.net
       
     2 #
       
     3 #                        All Rights Reserved
       
     4 #
       
     5 #
       
     6 # Permission to use, copy, modify, and distribute this software and
       
     7 # its documentation for any purpose is hereby granted without fee,
       
     8 # provided that the above copyright notice appear in all copies and
       
     9 # that both that copyright notice and this permission notice appear in
       
    10 # supporting documentation.
       
    11 #
       
    12 # THE AUTHOR MICHAEL HUDSON DISCLAIMS ALL WARRANTIES WITH REGARD TO
       
    13 # THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
       
    14 # AND FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
       
    15 # INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
       
    16 # RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
       
    17 # CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
       
    18 # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
       
    19 
       
    20 import __builtin__
       
    21 
       
    22 class Completer:
       
    23     def __init__(self, ns):
       
    24         self.ns = ns
       
    25 
       
    26     def complete(self, text):
       
    27         if "." in text:
       
    28             return self.attr_matches(text)
       
    29         else:
       
    30             return self.global_matches(text)
       
    31 
       
    32     def global_matches(self, text):
       
    33         """Compute matches when text is a simple name.
       
    34 
       
    35         Return a list of all keywords, built-in functions and names
       
    36         currently defines in __main__ that match.
       
    37 
       
    38         """
       
    39         import keyword
       
    40         matches = []
       
    41         n = len(text)
       
    42         for list in [keyword.kwlist,
       
    43                      __builtin__.__dict__.keys(),
       
    44                      self.ns.keys()]:
       
    45             for word in list:
       
    46                 if word[:n] == text and word != "__builtins__":
       
    47                     matches.append(word)
       
    48         return matches
       
    49 
       
    50     def attr_matches(self, text):
       
    51         """Compute matches when text contains a dot.
       
    52 
       
    53         Assuming the text is of the form NAME.NAME....[NAME], and is
       
    54         evaluatable in the globals of __main__, it will be evaluated
       
    55         and its attributes (as revealed by dir()) are used as possible
       
    56         completions.  (For class instances, class members are are also
       
    57         considered.)
       
    58 
       
    59         WARNING: this can still invoke arbitrary C code, if an object
       
    60         with a __getattr__ hook is evaluated.
       
    61 
       
    62         """
       
    63         import re
       
    64         m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text)
       
    65         if not m:
       
    66             return []
       
    67         expr, attr = m.group(1, 3)
       
    68         object = eval(expr, self.ns)
       
    69         words = dir(object)
       
    70         if hasattr(object, '__class__'):
       
    71             words.append('__class__')
       
    72             words = words + get_class_members(object.__class__)
       
    73         matches = []
       
    74         n = len(attr)
       
    75         for word in words:
       
    76             if word[:n] == attr and word != "__builtins__":
       
    77                 matches.append("%s.%s" % (expr, word))
       
    78         return matches
       
    79 
       
    80 def get_class_members(klass):
       
    81     ret = dir(klass)
       
    82     if hasattr(klass, '__bases__'):
       
    83         for base in klass.__bases__:
       
    84             ret = ret + get_class_members(base)
       
    85     return ret
       
    86 
       
    87