tags:

views:

213

answers:

4

I would like to control which methods appear when a user uses tab-completion on a custom object in ipython - in particular, I want to hide functions that I have deprecated. I still want these methods to be callable, but I don't want users to see them and start using them if they are inspecting the object. Is this something that is possible?

A: 

The DeprecationWarning isn't emitted until the method is called, so you'd have to have a separate attribute on the class that stores the names of deprecated methods, then check that before suggesting a completion.

Alternatively, you could walk the AST for the method looking for DeprecationWarning, but that will fail if either the class is defined in C, or if the method may emit a DeprecationWarning based on the type or value of the arguments.

Ignacio Vazquez-Abrams
How does one go about controlling what is displayed for tab completion in the first place?
astrofrog
Not a clue. You'd have to muck around in the IPython source for that. Might have something to do with `rlcompleter`. http://docs.python.org/library/rlcompleter.html
Ignacio Vazquez-Abrams
+3  A: 

Partial answer for you. I'll post the example code and then explain why its only a partial answer.
Code:

class hidden(object): # or whatever its parent class is
    def __init__(self):
        self.value = 4
    def show(self):
        return self.value
    def change(self,n):
        self.value = n
    def __getattr__(self, attrname):
        # put the dep'd method/attribute names here
        deprecateds = ['dep_show','dep_change']
        if attrname in deprecateds:
            print("These aren't the methods you're looking for.")
            def dep_change(n):
                self.value = n
            def dep_show():
                return self.value
            return eval(attrname)
        else:
            raise AttributeError, attrname

So now the caveat: they're not methods (note the lack of self as the first variable). If you need your users (or your code) to be able to call im_class, im_func, or im_self on any of your deprecated methods, then this hack won't work. Also, i'm pretty sure there's going to be a performance hit because you're defining each dep'd function inside __getattr__. This won't affect your other attribute lookups (had I put them in __getattribute__, that would be a different matter), but it will slow down access to those deprecated methods. This can be (largely, but not entirely) negated by putting each function definition inside its own if block, instead of doing a list-membership check, but, depending on how big your function is, that could be really annoying to maintain.

UPDATE:

1) If you want to make the deprecated functions methods (and you do), just use

import types
return types.MethodType(eval(attrname), self)

instead of

return eval(attrname)

in the above snippet, and add self as the first argument to the function defs. It turns them into instancemethods (so you can use im_class, im_func, and im_self to your heart's content).

2) If the __getattr__ hook didn't thrill you, there's another option (that I know of) (albiet, with its own caveats, and we'll get to those): Put the deprecated functions definitions inside __init__, and hide them with a custom __dir__. Here's what the above code would look like done this way:

class hidden(object):
    def __init__(self):
        self.value = 4
        from types import MethodType
        def dep_show(self):
            return self.value
        self.__setattr__('dep_show', MethodType(dep_show, self))
        def dep_change(self, n):
            self.value = n
        self.__setattr__('dep_change', MethodType(dep_change, self))
    def show(self):
        return self.value
    def change(self, n):
        self.value = n
    def __dir__(self):
        heritage = dir(super(self.__class__, self)) # inherited attributes
        hide = ['dep_show', 'dep_change']
        show = [k for k in self.__class__.__dict__.keys() + self.__dict__.keys() if not k in heritage + private]
        return sorted(heritage + show)

The advantage here is that you're not defining the functions anew every lookup, which nets you speed. The disadvantage here is that because you're not defining functions anew each lookup, they have to 'persist' (if you will). So, while the custom __dir__ method hides your deprecateds from dir(hiddenObj) and, therefore, IPython's tab-completion, they still exist in the instance's __dict__ attribute, where users can discover them.

yarmiganosca
A: 

About the completion mechanism in IPython, it is documented here:

http://ipython.scipy.org/doc/manual/html/api/generated/IPython.core.completer.html#ipcompleter

But a really interesting example for you is the traits completer, that does precisely what you want to do: it hides some methods (based on their names) from the autocompletion.

Here is the code:

http://projects.scipy.org/ipython/ipython/browser/ipython/trunk/IPython/Extensions/ipy_traits_completer.py

Olivier
A: 

Seems like there is a special magic method for the introcpection which is called by dir(): __dir__(). Isn't it what you are lookin for?

newtover