Eclipse + Pydev + PyUNO

OOo の Scripting Framework で言語に Python を選択してマクロを書くとしても統合された IDE がありません。そのせいで利用を躊躇するのがよく見かけられます。

マクロを書く際にはオートメーションとして書きながら実行、完成後に利用する時にはマクロとして実行する方法があります。現在のところヘビーユーザーはこの方法をとっている人が多いようです。

ここでは Eclipse + Pydev を IDE として利用します。導入したあと動くようになるまでは結構大変ですが以下で説明していきます。
Python 関連の設定を行えば Eclipse + Pydev でなくとも同じように動作します。

インタプリタを追加

Window - Preferences - Pydev - Interpreter - Python から OOo に付属の Python を追加します。他の Python インタプリタでも問題ありませんが、pyuno.pyd をインポートできるように 2.6.x を利用します。また、OOo 付属の Python は幾つかの標準モジュールをサポートしていないため同様の環境でテストする必要があるのであれば付属のものを利用した方がよいでしょう。

Pydev プロジェクトを作成

新規プロジェクトを PyDev プロジェクトとして作成します。プロジェクト作成時にファイルを配置する場所を OOo の user/Scripts/python 以下にする方法もありますがここではディレクトリをリンクすることにします。

プロジェクトが作成できたら python フォルダを src 以下に作成します。作成時に Link to folder in the file system を利用して user/Scripts/python にリンクさせます。すでに python 以下にファイルがある場合にはそれらのファイルが表示されます。
次に、pythonpath フォルダを src/python 以下に作成します。同様にリンクしておきます。このディレクトリにはマクロとして実行するときに import したいモジュールなどを入れます(実行前に自動的に PYTHONPATH に追加されます)。

プロジェクトの Properties から PyDev - PYTHONPATH の External Libraries に uno.py や unohelper.py ファイルの置かれているディレクトリを追加しておきます。

unopy.py

次のようなファイルを src 以下に作成します。プロジェクトの Properties - PyDev - PYTHONPATH の Source Folders に src 以下が含まれていることを確認しておきます(他の PYTHONPATH ディレクトリに配置しても構いません)。

#!     # unopy.py
# -*- coding: utf_8 -*-

import uno
import unohelper

from com.sun.star.script.provider import XScriptContext

class ScriptContext(unohelper.Base, XScriptContext):
    def __init__(self, ctx):
        self.ctx = ctx
    def getComponentContext(self):
        return self.ctx
    def getDesktop(self):
        return self.ctx.getServiceManager().createInstanceWithContext(
                "com.sun.star.frame.Desktop", self.ctx)
    def getDocument(self):
        return self.getDesktop().getCurrentComponent()

def connect():
    ctx = None
    try:
        localctx = uno.getComponentContext()
        resolver = localctx.getServiceManager().createInstanceWithContext(
            "com.sun.star.bridge.UnoUrlResolver", localctx)
        ctx = resolver.resolve(
            "uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
        if ctx:
            return ScriptContext(ctx)
    except:
        pass
    return None

上記のコードでは 2002 ポートを利用します。必要に応じて書き換えてください。

OpenOffice.org の起動

Eclipse から実行する時にはオートメーションとしてマクロを実行するため Python から OpenOffice.org に接続する必要があります。このために次のよう起動時にオプションを指定します。

E:\usr\local\OOo\DEV79\OOo-dev 3\program\soffice.exe \
  "-accept=socket,host=localhost,port=2002;urp;StarOffice.ServiceManager"

上記の unopy.py 中の利用ポートと同じポート番号を指定してください。

テストファイル

次のようなファイルを src/python 以下に作成してテストします。

#! # test.py
# -*- coding: utf_8 -*-

def hello():
	desktop = XSCRIPTCONTEXT.getDesktop()
	doc = desktop.loadComponentFromURL("private:factory/swriter", "_blank", 0, ())
	doc.getText().setString("Hello!")


if __name__ == '__main__':
	import unopy
	XSCRIPTCONTEXT = unopy.connect()
 	if not XSCRIPTCONTEXT:
 		print("Failed to connect to OpenOffice.org.")
 	 	import sys
 	 	sys.exit(0)
 	
 	hello()

Eclipse から実行すると __name__ は __main__ ですが OpenOffice.org のマクロとして実行したときには __name__ は ooo_script_framework となるため if の部分は無視されます。
マクロとして実行したときと同様のコードにするために XSCRIPTCONTEXT グローバル変数を定義しています。マクロでは普通この変数から OOo にアクセスします、そこでオートメーションでも同じ変数を介して行うことでコードを変更せずに済ませます。

実行

Run とするとエラーが出るのでテストコードを実行する前に実行用の設定を行わなければいけません。Run - Run Configuration - Python Run に新しく項目を作成して環境変数を設定します。

Linux 系 OS で本家ビルドの開発版を /opt 以下にインストールした場合には次のようになります。
UNIX 環境では次の環境変数を設定します。

  • LD_LIBRARY_PATH: libpyuno.so ファイルサーチ用
    /opt/ooo-dev3/program/../basis-link/program:/opt/ooo-dev3/program/../basis-link/ure-link/lib
  • URE_BOOTSTRAP: 起動も行うには指定が必要です
    vnd.sun.star.pathname:/opt/ooo-dev3/program/fundamentalrc

Windows 環境では PATH に追加します。

  • PATH: libpyuno.so ファイルサーチ用
    C:\Program Files\OpenOffice.org 3\URE\bin;C:\Program Files\OpenOffice.org 3\Basis\program
  • URE_BOOTSTRAP: 起動も行うには指定が必要です
    vnd.sun.star.pathname:C:\Program Files\OpenOffice.org 3/program/fundamental.ini

以下は追加の環境変数です。

  • UNO_PATH: soffice の実行ファイルがあるディレクトリパス
    /opt/ooo-dev3/program

Eclipse から問題なく実行できれば OpenOffice.org 側からも実行してみてください。同じコードがツール - マクロ - マクロの管理 - Python から実行できれば設定は終了です。

デバッグ

実行と同様の設定でデバッグを開始します。必要に応じて事前にブレークポイントを設定しておいてください。

リモートデバッグ

普段はオートメーションとして実行、デバッグで用は足りますが、マクロとして実行してデバッグが必要になった場合にはリモートデバッグを行います。
PyDev でのリモートデバッグ用に src/pythonpath 以下に eclipse/plugins/org.python.pydev.pydev_xxx/pysrc 以下のファイルを pydev などのパッケージとしてコピーしておきます(コピーした後で __init__.py ファイルを入れておきます)。

デバッグを開始する部分のコードに次の行を追加しておきます。ここでは Eclipse 付属の pydevd.py ファイルが置かれたディレクトリを src/pythonpath 以下に pydev パッケージとして配置したので次のように利用しています。

import pydev.pydevd; pydev.pydevd.settrace()

PyDev のリモートデバッグサーバーを開始します。その後にデバッグするマクロを実行します。