Trash: Cookbook Adding support for ipipe - ShuaiYAN/ipython GitHub Wiki

Automatically invoking an ipipe display for iterables

You can add support for ipipe to your own classes too. Anything that is iterable can be displayed by piping it into an ipipe enabled object, but if you want an ipipe display to automatically display your object, you have to subclass ipipe.Table and implement an __iter__ method. For example an ipipe enabled version of range might look like this:

 class irange(ipipe.Table):
     def __init__(self, *args):
         self.args = args
 
     def __iter__(self):
         return iter(xrange(*self.args))

If you want to implement a "filter" (i.e. something that transforms an input pipe), you have to subclass ipipe.Pipe. This gives you automatic handling of the | operator. In your __iter__ method you can access the input pipe as the input attribute. For example the following pipe will skip every second item:

 class ieven(ipipe.Pipe):
     def __iter__(self):
         for (i, item) in enumerate(self.input):
             if not i % 2:
                 yield item

Now you can user your new classes like this:

In   [1:] irange(100) | ieven

Specifying attributes for the ipipe display

You can specify which attributes should be displayed in an ipipe listing by implementing the __xattrs__ method:

     def __xattrs__(self, mode="default"):
         return ("firstname", "lastname")

(If __xattrs__() isn't defined the ipipe display will simply use the repr() result for the object itself)

The `mode` attribute has two possible values:

  • "default": The default list mode of the ibrowse display;
  • "detail": The detail mode, where each attribute of an object is displayed as a separate row (activated by pressing the `d` key in `ibrowse`).
__xattrs__() must return an iterable with "attribute descriptors". These attribute descriptors can be:
  • None: this will display the object itself;
  • "foo": this will display the attribute named "foo";
  • "foo()": this will call the method foo and will display the return value;
  • "-foo": The attribute named "foo" must be iterable. It's value will not be displayed, but it can be entered;
  • "-foo()": The foo method must return an iterable. The return value will not be displayed, but it can be entered;
  • Instances of the `ipipe.Descriptor` class.
For each of the above variants there's a subclass of ipipe.Descriptor implementing the specific behaviour: SelfDescriptor() is the same as None, AttributeDescriptor("foo") the same as "foo", IterAttributeDescriptor("foo") the same as "-foo", MethodDescriptor("foo") the same as "foo()" and IterMethodDescriptor("foo") the same as "-foo()". Finally there's FunctionDescriptor(foo), where foo must be callable (with the object as an argument) that returns the attribute value.

For example we can add contact information to the above Person class:

     def addcontact(self, type, value):
         self.contacts.append(Contact(type, value))
 
     def __xattrs__(self, mode="default"):
         if mode == "detail":
             return ("firstname", "lastname", "-contacts")
         else:
             return ("firstname", "lastname")
 
 class Contact:
     def __init__(self, type, value):
         self.type = type
         self.value = value
 
     def __xattrs__(self, mode="default"):
         return ("type", "value")
 
 p1 = Person("John", "Doe")
 p1.addcontact("email", "[email protected]")
 p1.addcontact("phone", "555-0123")
 
 p2 = Person("Jane", "Doe")
 p2.addcontact("email", "[email protected]")
 p2.addcontact("phone", "555-0321")
 
 persons = [p1, p2]

With these objects you can then browse them like this:

In  [1]: persons | ibrowse
⚠️ **GitHub.com Fallback** ⚠️