pygtkでpydocを使ったツールを作りました。

今日は、pydocでモジュールのドキュメントHTMLを出力するツールを作ってみました。
特にGTKでUIを使う必要もなかったんですけど、ついつい。(笑
慣れた人だったら、Pythonインタプリタ起動して、ちょこちょこっと終わらせてしまうとはおもいますが、何ごとも経験ということで。

今回作ったツールを起動するとこんな感じです。

"..."というボタンをクリックして、

・処理対象のモジュールのフォルダ
・HTML出力先のフォルダ

を選択します。

上記の両方を選択すると、Startボタンが押せるようになるので、ポチッとクリックすると、
出力先フォルダにHTMLが出力されます。
今のところは、進捗状況の表示までは作ってないので、ターミナルとかで実行すると処理が終わったかどうかがわかると思います。(汗

また、上記でフォルダを選択した後に、フォルダを削除したり、名前変更したり。。。とかいう使い方へのケアは省略してます。(出力先が書き込み禁止かどうかもチェックしてません)

まあ、でもpydocの使い方の練習としてはいい感じかな。。と。

ソースコードはこんな感じになりました。
ソースコード中の赤文字の部分がpydocを使った部分です。
それ以外の部分はUIを作っている部分です。

# -*- coding: utf-8 -*-

import sys
import os
import pydoc

import pygtk
if sys.platform != 'win32':
    pygtk.require('2.0')
import gtk

gtk.gdk.threads_init()


#
#
class MainWindow:
    def __init__(self):
        '''
        初期化
        '''
        self.wind = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.wind.set_border_width(6)
        
        self.wind.connect('delete_event', self.on_delete_event)

        widgets = self.get_widgets()
        if widgets:
            self.wind.add(widgets)

        self.update_start_button()        
        self.wind.show_all()

    def get_path_select_widget(self, frameLabel, handler):
        '''
        パス選択用のウィジェットを生成して返す。
        '''        
        frame = gtk.Frame(frameLabel)
        
        hbox = gtk.HBox()
        hbox.set_border_width(4)
        label = gtk.Label('')
        label.set_size_request(200, 18)
        hbox.pack_start(label, True, True, 4)

        bt = gtk.Button('...')
        if handler:
            bt.connect('clicked', handler)
            
        hbox.pack_end(bt, False, False, 4)
        frame.add(hbox)

        return frame, label
        
    def get_widgets(self):
        '''
        '''
        vbox = gtk.VBox()

        # モジュールディレクトリ選択用ウィジェットの生成
        frame, label = self.get_path_select_widget('Module directory',
                                                   self.on_button_modules_path)
        self.modulePath = label
        vbox.pack_start(frame, False, False, 4)

        # ドキュメント出力ディレクトリ選択用ウィジェットの生成
        frame, label = self.get_path_select_widget('Output directory',
                                                   self.on_button_output_path)
        self.outputPath = label
        vbox.pack_start(frame, False, False, 4)

        # 開始ボタン
        self.startButton = gtk.Button('Start')
        self.startButton.connect('clicked', self.on_button_start)
        vbox.pack_start(self.startButton, False, False, 4)
        
        return vbox
    
    def on_delete_event(self, widget, event=None):
        '''
        ウインドウが閉じられた場合の処理
        '''
        print '-- quit --'
        gtk.main_quit()

    def show_dir_chooser(self, title, parent):
        '''
        ディレクトリ選択ダイアログを表示
        '''
        chooser = gtk.FileChooserDialog(title=title,
                                        parent=parent,
                                        action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
                                        buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
                                                 gtk.STOCK_OK, gtk.RESPONSE_OK))
        chooser.set_default_response(gtk.RESPONSE_OK)

        response = chooser.run()
        
        dirPath = None
        if response == gtk.RESPONSE_OK:
            dirPath = chooser.get_filename()
            
        chooser.destroy()
        return dirPath

    def update_start_button(self):
        '''
        モジュールディレクトリと出力ディレクトリの両方が
        選択されていたら、スタートボタンを有効に。
        '''
        flag = (len(self.modulePath.get_text()) > 0 and
                len(self.outputPath.get_text()) > 0)
        self.startButton.set_sensitive(flag)
            
    def on_button_modules_path(self, widget, event=None):
        '''
        モジュールディレクトリ選択ボタンが押された場合の処理
        '''
        folder = self.show_dir_chooser('Select module directory', self.wind)
        if folder:
            self.modulePath.set_text(folder)
        self.update_start_button()

    def on_button_output_path(self, widget, event=None):
        '''
        出力ディレクトリ選択ボタンが押された場合の処理
        '''
        folder = self.show_dir_chooser('Select output directory', self.wind)
        if folder:
            self.outputPath.set_text(folder)
        self.update_start_button()

    def on_button_start(self, widget, event=None):
        '''
        Startボタンが押された場合の処理
        pydocでモジュールのHTMLを作成し、出力ディレクトリに
        保存。
        '''
        # ワーキングディレクトリの退避
        saveCwd = os.getcwd()

        # 出力ディレクトリをカレントワーキングディレクトリに。
        os.chdir(self.outputPath.get_text())

        # 処理対象のモジュールディレクトリが、Pythonパスに
        # 含まれていない場合には、追加
        modPath = self.modulePath.get_text()
        if modPath not in sys.path:
            sys.path.append(modPath)

        # HTMLを作成して保存
        pydoc.writedocs(modPath)

        # ワーキングディレクトリを復帰
        os.chdir(saveCwd)        
           
#
#
if __name__ == '__main__':
    wind = MainWindow()
    
    gtk.gdk.threads_enter()
    gtk.main()
    gtk.gdk.threads_leave()    

いやはや、今日も楽しめました。
さて、new-style class関連の資料を読んで、実験実験〜(笑