I don’t know the finished tool, but you can use Traits UI to quickly develop your own
from enthought.traits.api \ import HasTraits, Instance from enthought.traits.ui.api \ import View, VGroup, Item, ValueEditor class DictEditor(HasTraits): Object = Instance( object ) def __init__(self, obj, **traits): super(DictEditor, self).__init__(**traits) self.Object = obj def trait_view(self, name=None, view_elements=None): return View( VGroup( Item( 'Object', label = 'Debug', id = 'debug', editor = ValueEditor(), style = 'custom', dock = 'horizontal', show_label = False ), ), title = 'Dictionary Editor', width = 800, height = 600, resizable = True, ) def build_sample_data(): my_data = dict(zip(range(10),range(10,20))) my_data[11] = dict(zip(range(10),range(10,20))) my_data[11][11] = dict(zip(range(10),range(10,20))) return my_data
What is it. You will have a graphical interface like this:
The user interface with samples uses the Model-View-Controller approach to create a graphical interface without requiring each widget to be programmatically created. Here I use the predefined ValueEditor to display arbitrary types. Now you can expand it to support search, filtering, etc. 
EDIT
Simple extension to support filtering:
# -*- coding: utf-8 -*- """ Created on Fri Feb 22 12:52:28 2013 @author: kranzth """ from enthought.traits.api \ import HasTraits, Instance, Str, on_trait_change from enthought.traits.ui.api \ import View, VGroup, Item, ValueEditor, TextEditor from copy import deepcopy class DictEditor(HasTraits): SearchTerm = Str() Object = Instance( object ) def __init__(self, obj, **traits): super(DictEditor, self).__init__(**traits) self._original_object = obj self.Object = self._filter(obj) def trait_view(self, name=None, view_elements=None): return View( VGroup( Item( 'SearchTerm', label = 'Search:', id = 'search', editor = TextEditor(), #style = 'custom', dock = 'horizontal', show_label = True ), Item( 'Object', label = 'Debug', id = 'debug', editor = ValueEditor(), style = 'custom', dock = 'horizontal', show_label = False ), ), title = 'Dictionary Editor', width = 800, height = 600, resizable = True, ) @on_trait_change("SearchTerm") def search(self): self.Object = self._filter(self._original_object, self.SearchTerm) def _filter(self, object_, search_term=None): def has_matching_leaf(obj): if isinstance(obj, list): return any( map(has_matching_leaf, obj)) if isinstance(obj, dict): return any( map(has_matching_leaf, obj.values())) else: try: if not str(obj) == search_term: return False return True except ValueError: False obj = deepcopy(object_) if search_term is None: return obj if isinstance(obj, dict): for k in obj.keys(): if not has_matching_leaf(obj[k]): del obj[k] for k in obj.keys(): if isinstance(obj, dict): obj[k] = self._filter(obj[k], search_term) elif isinstance(obj, list): filter(has_matching_leaf,obj[k]) return obj def build_sample_data(): def make_one_level_dict(): return dict(zip(range(100), range(100,150) + map(str,range(150,200)))) my_data = make_one_level_dict() my_data[11] = make_one_level_dict() my_data[11][11] = make_one_level_dict() return my_data # Test if __name__ == '__main__': my_data = build_sample_data() b = DictEditor(my_data) b.configure_traits()
will provide you with a text box called "filter-as-you-type". The search is not entirely correct for all cases, but you can understand this idea.
Note that in this example, the data in the dict is partly integer and partly strings, and both types will be found.
