##// END OF EJS Templates
Merge remote-tracking branch 'upstream/master' into mono_cursor_offset
Merge remote-tracking branch 'upstream/master' into mono_cursor_offset

File last commit:

r2558:18cd5de2
r7665:d5ac8853 merge
Show More
ipy_traits_completer.py
219 lines | 6.7 KiB | text/x-python | PythonLexer
/ IPython / deathrow / ipy_traits_completer.py
fperez
- Implement a traits-aware tab-completer. See ipy_traits_completer in...
r742 """Traits-aware tab completion.
This module provides a custom tab-completer that intelligently hides the names
that the enthought.traits library (http://code.enthought.com/traits)
automatically adds to all objects that inherit from its base HasTraits class.
Activation
==========
To use this, put in your ~/.ipython/ipy_user_conf.py file:
from ipy_traits_completer import activate
activate([complete_threshold])
The optional complete_threshold argument is the minimal length of text you need
to type for tab-completion to list names that are automatically generated by
traits. The default value is 3. Note that at runtime, you can change this
value simply by doing:
import ipy_traits_completer
ipy_traits_completer.COMPLETE_THRESHOLD = 4
Usage
=====
The system works as follows. If t is an empty object that HasTraits, then
(assuming the threshold is at the default value of 3):
In [7]: t.ed<TAB>
doesn't show anything at all, but:
In [7]: t.edi<TAB>
t.edit_traits t.editable_traits
shows these two names that come from traits. This allows you to complete on
the traits-specific names by typing at least 3 letters from them (or whatever
you set your threshold to), but to otherwise not see them in normal completion.
Notes
=====
- This requires Python 2.4 to work (I use sets). I don't think anyone is
Robert Kern
Defer Traits import in ipy_traits_completer....
r2558 using traits with 2.3 anyway, so that's OK.
- Imports from enthought.traits are deferred until an object with a class that
looks like it subclasses from HasTraits comes along. This test is done by
looking at the name of the class and its superclasses.
fperez
- Implement a traits-aware tab-completer. See ipy_traits_completer in...
r742 """
#############################################################################
# IPython imports
Brian Granger
Continuing a massive refactor of everything.
r2205 from IPython.core.error import TryNext
from IPython.core.ipapi import get as ipget
Brian Granger
Work to address the review comments on Fernando's branch....
r2498 from IPython.utils.dir2 import dir2
vivainio
check for set (python 2.3 compatibility). Closes #209
r942 try:
set
except:
from sets import Set as set
fperez
- Implement a traits-aware tab-completer. See ipy_traits_completer in...
r742
#############################################################################
# Module constants
# The completion threshold
# This is currently implemented as a module global, since this sytem isn't
# likely to be modified at runtime by multiple instances. If needed in the
# future, we can always make it local to the completer as a function attribute.
COMPLETE_THRESHOLD = 3
# Set of names that Traits automatically adds to ANY traits-inheriting object.
# These are the names we'll filter out.
Robert Kern
Defer Traits import in ipy_traits_completer....
r2558 TRAIT_NAMES = None
def get_trait_names():
global TRAIT_NAMES
from enthought.traits.api import HasTraits
if TRAIT_NAMES is None:
TRAIT_NAMES = set( dir2(HasTraits()) ) - set( dir2(object()) )
else:
return TRAIT_NAMES
fperez
- Implement a traits-aware tab-completer. See ipy_traits_completer in...
r742
#############################################################################
# Code begins
Robert Kern
Defer Traits import in ipy_traits_completer....
r2558 def looks_like_isinstance(obj, classname):
""" Return True if the object has a class or superclass with the given class
name.
Ignores old-style classes.
"""
from types import InstanceType
t = type(obj)
if t is InstanceType:
# Old-style classes.
return False
elif t.__name__ == classname:
return True
for klass in t.__mro__:
if klass.__name__ == classname:
return True
return False
fperez
- Implement a traits-aware tab-completer. See ipy_traits_completer in...
r742 def trait_completer(self,event):
"""A custom IPython tab-completer that is traits-aware.
It tries to hide the internal traits attributes, and reveal them only when
it can reasonably guess that the user really is after one of them.
"""
#print '\nevent is:',event # dbg
symbol_parts = event.symbol.split('.')
base = '.'.join(symbol_parts[:-1])
#print 'base:',base # dbg
oinfo = self._ofind(base)
if not oinfo['found']:
raise TryNext
obj = oinfo['obj']
# OK, we got the object. See if it's traits, else punt
Robert Kern
Defer Traits import in ipy_traits_completer....
r2558 if not looks_like_isinstance(obj, 'HasTraits'):
raise TryNext
# Defer import until here so as not to require Traits until we get something
# that looks like it might be a HasTraits instance.
from enthought.traits.api import HasTraits
if not isinstance(obj, HasTraits):
fperez
- Implement a traits-aware tab-completer. See ipy_traits_completer in...
r742 raise TryNext
# it's a traits object, don't show the tr* attributes unless the completion
# begins with 'tr'
attrs = dir2(obj)
# Now, filter out the attributes that start with the user's request
attr_start = symbol_parts[-1]
if attr_start:
attrs = [a for a in attrs if a.startswith(attr_start)]
darren.dale
traits completer respects readline_omit__names
r891
# Let's also respect the user's readline_omit__names setting:
omit__names = ipget().options.readline_omit__names
if omit__names == 1:
attrs = [a for a in attrs if not a.startswith('__')]
elif omit__names == 2:
attrs = [a for a in attrs if not a.startswith('_')]
fperez
- Implement a traits-aware tab-completer. See ipy_traits_completer in...
r742
#print '\nastart:<%r>' % attr_start # dbg
if len(attr_start)<COMPLETE_THRESHOLD:
Robert Kern
Defer Traits import in ipy_traits_completer....
r2558 attrs = list(set(attrs) - get_trait_names())
fperez
- Implement a traits-aware tab-completer. See ipy_traits_completer in...
r742
# The base of the completion, so we can form the final results list
bdot = base+'.'
tcomp = [bdot+a for a in attrs]
#print 'tcomp:',tcomp
return tcomp
def activate(complete_threshold = COMPLETE_THRESHOLD):
"""Activate the Traits completer.
:Keywords:
complete_threshold : int
The minimum number of letters that a user must type in order to
activate completion of traits-private names."""
if not (isinstance(complete_threshold,int) and
complete_threshold>0):
e='complete_threshold must be a positive integer, not %r' % \
complete_threshold
raise ValueError(e)
# Set the module global
global COMPLETE_THRESHOLD
COMPLETE_THRESHOLD = complete_threshold
# Activate the traits aware completer
ip = ipget()
ip.set_hook('complete_command', trait_completer, re_key = '.*')
#############################################################################
if __name__ == '__main__':
# Testing/debugging
Robert Kern
Defer Traits import in ipy_traits_completer....
r2558 from enthought.traits.api import HasTraits
fperez
- Implement a traits-aware tab-completer. See ipy_traits_completer in...
r742
# A sorted list of the names we'll filter out
Robert Kern
Defer Traits import in ipy_traits_completer....
r2558 TNL = list(get_trait_names())
fperez
- Implement a traits-aware tab-completer. See ipy_traits_completer in...
r742 TNL.sort()
# Make a few objects for testing
Robert Kern
Defer Traits import in ipy_traits_completer....
r2558 class TClean(HasTraits): pass
fperez
- Implement a traits-aware tab-completer. See ipy_traits_completer in...
r742 class Bunch(object): pass
# A clean traits object
t = TClean()
# A nested object containing t
f = Bunch()
f.t = t
# And a naked new-style object
o = object()
ip = ipget().IP
# A few simplistic tests
# Reset the threshold to the default, in case the test is running inside an
# instance of ipython that changed it
import ipy_traits_completer
ipy_traits_completer.COMPLETE_THRESHOLD = 3
assert ip.complete('t.ed') ==[]
# For some bizarre reason, these fail on the first time I run them, but not
# afterwards. Traits does some really weird stuff at object instantiation
# time...
ta = ip.complete('t.edi')
assert ta == ['t.edit_traits', 't.editable_traits']
print 'Tests OK'