# basic module browser. # usage: # >>> import browser # >>> browser.Browse() # or # >>> browser.Browse(your_module) import sys import types import __main__ import win32ui from pywin.mfc import dialog from . import hierlist special_names = [ '__doc__', '__name__', '__self__' ] # # HierList items class HLIPythonObject(hierlist.HierListItem): def __init__(self, myobject=None, name=None ): hierlist.HierListItem.__init__(self) self.myobject = myobject self.knownExpandable = None if name: self.name=name else: try: self.name=myobject.__name__ except (AttributeError, TypeError): try: r = repr(myobject) if len(r)>20: r = r[:20] + "..." self.name=r except (AttributeError, TypeError): self.name="???" def __lt__(self, other): return self.name < other.name def __eq__(self, other): return self.name == other.name def __repr__(self): try: type = self.GetHLIType() except: type = "Generic" return "HLIPythonObject("+type+") - name: "+ self.name + " object: " + repr(self.myobject) def GetText(self): try: return str(self.name) + ' (' + self.GetHLIType() + ')' except AttributeError: return str(self.name) + ' = ' + repr(self.myobject) def InsertDocString(self, lst): ob = None try: ob = self.myobject.__doc__ except (AttributeError, TypeError): pass # I don't quite grok descriptors enough to know how to # best hook them up. Eg: # >>> object.__getattribute__.__class__.__doc__ # if ob and isinstance(ob, str): lst.insert(0, HLIDocString( ob, "Doc" )) def GetSubList(self): ret = [] try: for (key, ob) in self.myobject.__dict__.items(): if key not in special_names: ret.append(MakeHLI( ob, key ) ) except (AttributeError, TypeError): pass try: for name in self.myobject.__methods__: ret.append(HLIMethod( name )) # no MakeHLI, as cant auto detect except (AttributeError, TypeError): pass try: for member in self.myobject.__members__: if not member in special_names: ret.append(MakeHLI(getattr(self.myobject, member), member)) except (AttributeError, TypeError): pass ret.sort() self.InsertDocString(ret) return ret # if the has a dict, it is expandable. def IsExpandable(self): if self.knownExpandable is None: self.knownExpandable = self.CalculateIsExpandable() return self.knownExpandable def CalculateIsExpandable(self): if hasattr(self.myobject, '__doc__'): return 1 try: for key in self.myobject.__dict__.keys(): if key not in special_names: return 1 except (AttributeError, TypeError): pass try: self.myobject.__methods__ return 1 except (AttributeError, TypeError): pass try: for item in self.myobject.__members__: if item not in special_names: return 1 except (AttributeError, TypeError): pass return 0 def GetBitmapColumn(self): if self.IsExpandable(): return 0 else: return 4 def TakeDefaultAction(self): ShowObject(self.myobject, self.name) class HLIDocString(HLIPythonObject): def GetHLIType(self): return "DocString" def GetText(self): return self.myobject.strip() def IsExpandable(self): return 0 def GetBitmapColumn(self): return 6 class HLIModule(HLIPythonObject): def GetHLIType(self): return "Module" class HLIFrame(HLIPythonObject): def GetHLIType(self): return "Stack Frame" class HLITraceback(HLIPythonObject): def GetHLIType(self): return "Traceback" class HLIClass(HLIPythonObject): def GetHLIType(self): return "Class" def GetSubList(self): ret = [] for base in self.myobject.__bases__: ret.append( MakeHLI(base, 'Base class: ' + base.__name__ ) ) ret = ret + HLIPythonObject.GetSubList(self) return ret class HLIMethod(HLIPythonObject): # myobject is just a string for methods. def GetHLIType(self): return "Method" def GetText(self): return "Method: " + self.myobject + '()' class HLICode(HLIPythonObject): def GetHLIType(self): return "Code" def IsExpandable(self): return self.myobject def GetSubList(self): ret = [] ret.append( MakeHLI( self.myobject.co_consts, "Constants (co_consts)" )) ret.append( MakeHLI( self.myobject.co_names, "Names (co_names)" )) ret.append( MakeHLI( self.myobject.co_filename, "Filename (co_filename)" )) ret.append( MakeHLI( self.myobject.co_argcount, "Number of args (co_argcount)")) ret.append( MakeHLI( self.myobject.co_varnames, "Param names (co_varnames)")) return ret class HLIInstance(HLIPythonObject): def GetHLIType(self): return "Instance" def GetText(self): return str(self.name) + ' (Instance of class ' + str(self.myobject.__class__.__name__) + ')' def IsExpandable(self): return 1 def GetSubList(self): ret = [] ret.append( MakeHLI( self.myobject.__class__) ) ret = ret + HLIPythonObject.GetSubList(self) return ret class HLIBuiltinFunction(HLIPythonObject): def GetHLIType(self): return "Builtin Function" class HLIFunction(HLIPythonObject): def GetHLIType(self): return "Function" def IsExpandable(self): return 1 def GetSubList(self): ret = [] # ret.append( MakeHLI( self.myobject.func_argcount, "Arg Count" )) try: ret.append( MakeHLI( self.myobject.func_argdefs, "Arg Defs" )) except AttributeError: pass try: code = self.myobject.__code__ globs = self.myobject.__globals__ except AttributeError: # must be py2.5 or earlier... code = self.myobject.func_code globs = self.myobject.func_globals ret.append(MakeHLI(code, "Code" )) ret.append(MakeHLI(globs, "Globals" )) self.InsertDocString(ret) return ret class HLISeq(HLIPythonObject): def GetHLIType(self): return "Sequence (abstract!)" def IsExpandable(self): return len(self.myobject)>0 def GetSubList(self): ret = [] pos=0 for item in self.myobject: ret.append(MakeHLI( item, '['+str(pos)+']' ) ) pos=pos+1 self.InsertDocString(ret) return ret class HLIList(HLISeq): def GetHLIType(self): return "List" class HLITuple(HLISeq): def GetHLIType(self): return "Tuple" class HLIDict(HLIPythonObject): def GetHLIType(self): return "Dict" def IsExpandable(self): try: self.myobject.__doc__ return 1 except (AttributeError, TypeError): return len(self.myobject) > 0 def GetSubList(self): ret = [] keys = list(self.myobject.keys()) keys.sort() for key in keys: ob = self.myobject[key] ret.append(MakeHLI( ob, str(key) ) ) self.InsertDocString(ret) return ret # In Python 1.6, strings and Unicode have builtin methods, but we dont really want to see these class HLIString(HLIPythonObject): def IsExpandable(self): return 0 TypeMap = { type : HLIClass, types.FunctionType: HLIFunction, tuple: HLITuple, dict: HLIDict, list: HLIList, types.ModuleType: HLIModule, types.CodeType : HLICode, types.BuiltinFunctionType : HLIBuiltinFunction, types.FrameType : HLIFrame, types.TracebackType : HLITraceback, str : HLIString, str : HLIString, int: HLIPythonObject, int: HLIPythonObject, bool: HLIPythonObject, float: HLIPythonObject, } def MakeHLI( ob, name=None ): try: cls = TypeMap[type(ob)] except KeyError: # hrmph - this check gets more and more bogus as Python # improves. Its possible we should just *always* use # HLIInstance? if hasattr(ob, '__class__'): # 'new style' class cls = HLIInstance else: cls = HLIPythonObject return cls( ob, name ) ######################################### # # Dialog related. class DialogShowObject(dialog.Dialog): def __init__(self, object, title): self.object = object self.title = title dialog.Dialog.__init__(self, win32ui.IDD_LARGE_EDIT) def OnInitDialog(self): import re self.SetWindowText(self.title) self.edit = self.GetDlgItem(win32ui.IDC_EDIT1) try: strval = str(self.object) except: t, v, tb = sys.exc_info() strval = "Exception getting object value\n\n%s:%s" % (t, v) tb = None strval = re.sub('\n','\r\n', strval) self.edit.ReplaceSel(strval) def ShowObject(object, title): dlg = DialogShowObject(object, title) dlg.DoModal() # And some mods for a sizable dialog from Sam Rushing! import win32con import win32api import commctrl class dynamic_browser (dialog.Dialog): style = win32con.WS_OVERLAPPEDWINDOW | win32con.WS_VISIBLE cs = ( win32con.WS_CHILD | win32con.WS_VISIBLE | commctrl.TVS_HASLINES | commctrl.TVS_LINESATROOT | commctrl.TVS_HASBUTTONS ) dt = [ ["Python Object Browser", (0, 0, 200, 200), style, None, (8, "MS Sans Serif")], ["SysTreeView32", None, win32ui.IDC_LIST1, (0, 0, 200, 200), cs] ] def __init__ (self, hli_root): dialog.Dialog.__init__ (self, self.dt) self.hier_list = hierlist.HierListWithItems ( hli_root, win32ui.IDB_BROWSER_HIER ) self.HookMessage (self.on_size, win32con.WM_SIZE) def OnInitDialog (self): self.hier_list.HierInit (self) return dialog.Dialog.OnInitDialog (self) def OnOK(self): self.hier_list.HierTerm() self.hier_list = None return self._obj_.OnOK() def OnCancel(self): self.hier_list.HierTerm() self.hier_list = None return self._obj_.OnCancel() def on_size (self, params): lparam = params[3] w = win32api.LOWORD(lparam) h = win32api.HIWORD(lparam) self.GetDlgItem (win32ui.IDC_LIST1).MoveWindow((0,0,w,h)) def Browse (ob=__main__): " Browse the argument, or the main dictionary " root = MakeHLI (ob, 'root') if not root.IsExpandable(): raise TypeError("Browse() argument must have __dict__ attribute, or be a Browser supported type") dlg = dynamic_browser (root) dlg.CreateWindow() # # # Classes for using the browser in an MDI window, rather than a dialog # from pywin.mfc import docview class BrowserTemplate(docview.DocTemplate): def __init__(self): docview.DocTemplate.__init__(self, win32ui.IDR_PYTHONTYPE, BrowserDocument, None, BrowserView) def OpenObject(self, root): # Use this instead of OpenDocumentFile. # Look for existing open document for doc in self.GetDocumentList(): if doc.root==root: doc.GetFirstView().ActivateFrame() return doc # not found - new one. doc = BrowserDocument(self, root) frame = self.CreateNewFrame(doc) doc.OnNewDocument() self.InitialUpdateFrame(frame, doc, 1) return doc class BrowserDocument (docview.Document): def __init__(self, template, root): docview.Document.__init__(self, template) self.root = root self.SetTitle("Browser: " + root.name) def OnOpenDocument (self, name): raise TypeError("This template can not open files") return 0 class BrowserView(docview.TreeView): def OnInitialUpdate(self): import commctrl rc = self._obj_.OnInitialUpdate() list=hierlist.HierListWithItems( self.GetDocument().root, win32ui.IDB_BROWSER_HIER, win32ui.AFX_IDW_PANE_FIRST) list.HierInit(self.GetParent()) list.SetStyle(commctrl.TVS_HASLINES | commctrl.TVS_LINESATROOT | commctrl.TVS_HASBUTTONS) return rc template = None def MakeTemplate(): global template if template is None: template = BrowserTemplate() #win32ui.IDR_PYTHONTYPE, BrowserDocument, None, BrowserView) def BrowseMDI(ob=__main__): """Browse an object using an MDI window. """ MakeTemplate() root = MakeHLI(ob, repr(ob)) if not root.IsExpandable(): raise TypeError("Browse() argument must have __dict__ attribute, or be a Browser supported type") template.OpenObject(root)