I have made a little panel which emulates the tkinter pydoc gui so I can
embed it in one of my applications.
Here is my feeble attempt if anyone is interested. Comments are appreciated
wxPyDoc.py (8.67 KB)
···
===========================================================================
#!/bin/python
import sys, os
from wxPython.wx import *
import getopt
import pydoc
import threading
import webbrowser
APP_TITLE = 'wxPyDoc'
KEY_PYDOCS = 'PATH_TO_PYTHON_DOCS'
KEY_WXDOCS = 'PATH_TO_WXWINDOWS_DOCS'
KEY_WXDEMO = 'PATH_TO_WXPYTHON_DEMO'
def MsgBox (window, string):
dlg=wxMessageDialog(window, string, APP_TITLE, wxOK)
dlg.ShowModal()
dlg.Destroy()
class PyDocPanel(wxPanel):
PROMPTS = { KEY_PYDOCS : 'Please locate the directory containing your
Python Docs',
KEY_WXDOCS : 'Please locate the directory containing
your wxWindows Docs',
KEY_WXDEMO : 'Please locate the directory containing
your wxPython Demo'}
def __init__(self, parent, id, pos=wxDefaultPosition,
size=wxDefaultSize, style=wxTAB_TRAVERSAL, name='panel', port=7464,
pyDocsPath=None, wxWinDocsPath=None, wxPythonDemoPath=None):
# init the parent class
wxPanel.__init__(self, parent, id, pos, size, style, name)
# stash the paths to docs/demo
self.paths = { KEY_PYDOCS : pyDocsPath,
KEY_WXDOCS : wxWinDocsPath,
KEY_WXDEMO : wxPythonDemoPath}
# stash the port
self.port = port
# create the panel sizer
panelSizer = wxBoxSizer(wxVERTICAL)
self.SetSizer(panelSizer)
# create the status text
txtStatus = wxStaticText(self, -1, 'DocServer not started')
panelSizer.Add(txtStatus, 0, wxEXPAND | wxALL, 3)
self.txtStatus = txtStatus
# create search input
ID_TXT_SEARCH = wxNewId()
txtSearch = wxTextCtrl(self, ID_TXT_SEARCH,
style=wxTE_PROCESS_ENTER)
panelSizer.Add(txtSearch, 0, wxEXPAND | wxALL, 3)
self.txtSearch = txtSearch
# create search buttons
btnBox = wxBoxSizer(wxHORIZONTAL)
ID_BTN_START = wxNewId()
btnStart = wxButton(self, ID_BTN_START, 'Start Search')
self.btnStart = btnStart
btnBox.Add(btnStart, 1, wxALL | wxALIGN_CENTER | wxEXPAND, 2)
ID_BTN_STOP = wxNewId()
btnStop = wxButton(self, ID_BTN_STOP, 'Stop Search')
self.btnStop = btnStop
self.btnStop.Enable(False)
btnBox.Add(btnStop, 1, wxALL | wxALIGN_CENTER | wxEXPAND, 2)
panelSizer.Add(btnBox, 0, wxEXPAND)
# create search results list box
ID_LST_SEARCH = wxNewId()
panelSizer.Add(wxStaticText(self, -1, 'Search Results ...'), 0,
wxTOP, 3)
lstSearch = wxListBox(self, ID_LST_SEARCH, size=(-1,125),
style=wxLB_HSCROLL )
panelSizer.Add(lstSearch, 1, wxEXPAND)
self.lstSearch = lstSearch
# create the go to topic btn
ID_BTN_TOPIC = wxNewId()
btnTopic = wxButton(self, ID_BTN_TOPIC, 'View Topic')
panelSizer.Add(btnTopic, 0, wxEXPAND | wxALL, 3)
# create launch doc buttons
# Python Docs
ID_BTN_PYTHON = wxNewId()
btnPython = wxButton(self, ID_BTN_PYTHON, 'Python Docs')
panelSizer.Add(btnPython, 0, wxEXPAND | wxALL, 1)
# wxWindow Docs
ID_BTN_WXWINDOWS = wxNewId()
btnWxWindows = wxButton(self, ID_BTN_WXWINDOWS, 'wxWindows Docs')
panelSizer.Add(btnWxWindows, 0, wxEXPAND | wxALL, 1)
# wxPython Demo
ID_BTN_WXPYTHON = wxNewId()
btnWxPython = wxButton(self, ID_BTN_WXPYTHON, 'wxPython Demo')
panelSizer.Add(btnWxPython, 0, wxEXPAND | wxALL, 1)
self.Layout()
# placeholders for pydoc webserver and topic scanner objects
self.server = None
self.scanner = None
# set up the configuration
self.config = wxConfig(APP_TITLE, style=wxCONFIG_USE_LOCAL_FILE)
# Set up the EVENTS table
EVT_BUTTON(self, ID_BTN_START, self.OnSearchStart)
EVT_BUTTON(self, ID_BTN_STOP, self.OnSearchStop)
EVT_TEXT_ENTER(self, ID_TXT_SEARCH, self.OnSearchStart)
EVT_LISTBOX_DCLICK(self, ID_LST_SEARCH, self.OnViewTopic)
EVT_BUTTON(self, ID_BTN_TOPIC, self.OnViewTopic)
EVT_BUTTON(self, ID_BTN_PYTHON, self.OnPythonDocs)
EVT_BUTTON(self, ID_BTN_WXWINDOWS, self.OnWxWindowsDocs)
EVT_BUTTON(self, ID_BTN_WXPYTHON, self.OnWxPythonDemo)
def FindLocation(self, key, title='Choose directory ... '):
# check if path was passed in when we were constructed
path = self.paths[key]
# if path is unspecified then check the wxConfig
if path == None:
path = self.config.Read(key)
# if still no path, then query the user
if path == None or path=='':
dlg = wxDirDialog(self, title, style=wxDD_DEFAULT_STYLE)
path = None
if dlg.ShowModal() == wxID_OK:
path = dlg.GetPath()
self.config.Write(key, path)
self.paths[key]=path
return path
def OnPythonDocs(self, event = None):
# do we know where the python docs are ?
location = self.FindLocation(KEY_PYDOCS)
if location == None: return
webbrowser.open('file://' + location + '/index.html')
def OnWxWindowsDocs(self, event=None):
# do we know where the python docs are ?
location = self.FindLocation(KEY_WXDOCS)
if location == None: return
# are we on Windows ?
if wxPlatform == '__WXMSW__':
cmd = 'start ' + location + os.sep + 'wx.chm'
else:
cmd = 'sh ' + location + os.sep + ' &'
print 'trying to spawn ' + cmd
os.system(cmd)
def OnWxPythonDemo(self, event=None):
# do we know where the python demo is ?
location = self.FindLocation(KEY_WXDEMO)
if location == None: return
# add the directory to sys.path
# are we on Windows ?
if wxPlatform == '__WXMSW__':
cmd = 'start pythonw.exe ' + location + os.sep + 'demo.py'
else:
cmd = 'python ' + location + os.sep + 'demo.py &'
print 'trying to spawn ' + cmd
os.system(cmd)
def StartServer(self):
if self.server == None:
threading.Thread(target=pydoc.serve, args=(self.port, self.
_ready, None)).start()
def StopServer(self):
print 'stopping doc server'
if self.server:
self.server.quit = True
self.server = None
def _ready(self, server):
self.server = server
self.txtStatus.SetLabel(server.url)
def OnSearchStart(self, event=None):
key = self.txtSearch.GetValue()
if len(key) < 1:
MsgBox(self, 'Please enter a search term')
return
self.lstSearch.Clear()
if self.scanner:
self.scanner.quit = True
self.scanner = pydoc.ModuleScanner()
threading.Thread(target=self.scanner.run, args=(self._update, key,
self._done)).start()
self.btnStart.Enable(False)
self.btnStop.Enable(True)
def OnSearchStop(self, event=None):
self._done()
def _update(self, path, modname, desc):
if modname[-9:] == '.__init__':
modname = modname[:-9] + ' (package)'
self.lstSearch.Append(modname + ' - ' + (desc or '(no
description)'))
def _done(self):
if self.scanner:
self.scanner.quit = True
self.scanner = None
self.btnStart.Enable(True)
self.btnStop.Enable(False)
def OnViewTopic(self, event=None):
topic = self.lstSearch.GetStringSelection().split('-')[0]
print 'viewing topic: ' + topic
webbrowser.open(self.server.url + topic.rstrip() + '.html')
class PyDocWindow(wxFrame):
def __init__(self, parent, id, title):
wxFrame.__init__(self, parent, -1, title, size=(225,400))
self.panel = PyDocPanel(self, -1)
self.panel.StartServer()
EVT_CLOSE(self, self.OnCloseWindow)
def OnCloseWindow(self, event):
self.panel.StopServer()
self.Destroy()
if __name__=='__main__':
# Process the command line.
# We pass all options other than -g onto the pydoc module
# for the -g option we intercept it and start the wxPython gui instead
of Tkinter
optlist, args = getopt.getopt(sys.argv, 'gk:p:w:')
if ('-g','') not in optlist:
app = wxPySimpleApp()
win = PyDocWindow(None, -1, 'wxPyDoc')
win.Show(1)
app.MainLoop()
else:
print 'delegate to pydoc'
pydoc.cli()
(See attached file: wxPyDoc.py)
Richard Lawson
Lead Developer
CoLinx, LLC
richard.lawson@colinx.com