wxPyDoc

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