メモ
Py-UNO を利用していて他の言語 (OOo Basic など) とは違った挙動を示したときなど。 それ以外も。
Python 関連 issue
Python... メニュー
Python スクリプトをマクロとして実行しているときにツール - マクロ - マクロの管理 - Python とたどるのは面倒。BookmarksMenu などで次のような Command URL をメニューに追加する。 .uno:ScriptOrganizer?ScriptOrganizer.Language:string=Python Python の部分は Java など他のものにも変更できます。 普段は pipe などで接続したり Basic から実行したりしていますが、.frame.Desktop から getCurrentComponent などとしているときには時々ドキュメントのフレームから実行することがあるので。 __name__
Python のマクロを scripting framework で実行する際の __name__ = 'ooo_script_framework' DEBUG
OOo 2.4.1 の pythonloader はうるさい。 DEBUG = 0 に書き換えて黙っててもらう。色々吐かれると UNO コンポーネントの出力が分かりにくくなる…。 OOo 2.4 -> OOo 2.4.1 で fileUrlToSystemPath などの修正をしたときに戻されなかったらしい。 Python バージョン
OOo 2.4 現在、OOo に付いてくる Python のバージョンは 2.3.4。
OOo 3.1 以降では Python 2.6.1 Py-UNO がインストールされていない場合のエラー
Py-UNO を利用して作成された拡張機能をインストールするときに、Py-UNO がインストールされていない場合には次のようなエラーが出ます。 ImplementationRegistration::registerImplementation() - The service com.sun.star.loader.Python cannot be instantiated Py-UNO による拡張機能をアップデートするときのエラー
Py-UNO を利用した拡張機能をアップデートするときに、そのまま上書きしようとすると出ることがあるエラー。(2.4 以降では出ないような気がします。) Py-UNO による拡張機能のインストール時の不明なエラー
インストール時に出るらしい不明なエラー。詳細不明。 このエラーが出る場合にはすべての Py-UNO 拡張機能が利用できません。が、なぜか Scripting FrameWork Script の Python スクリプトは動くらしいです。 pythonloader.py が壊れている様子。 Python スクリプトの実行
Python スクリプトが実行される経過。 すべての Scripting 言語に対して LANGUAGE + ScriptProvider がサービスがあり、そのサービスが実行できるファイルや関数などを調べて情報を提供します。Python では com.sun.star.script.provider.PythonScriptProvider サービスがそれに相当します。 このサービスは program/pythonscript.py の PythonScriptProvider クラスで実装されています。
エクスポートオプション
エクスポート時に FilterData を与えることがあるが FilterData の型を指定しないと失敗する。PDF エクスポート 参照。 Any と invoke
uno.Any を使うときには uno.inovoke を利用します。これは Invokation bridge によりメソッドを呼び出します。 これが必要なのは any 型に対して com.sun.star.beans.PropertyValue などの tuple を渡すときです。ブリッジを通 じての値の型問題によるようです。 代表的なのは container モジュールのインターフェースのメソッドです。次のようなコードは失敗します。
これの代わりに次のようにします。
uno.Any と uno.invoke の詳細は uno.py 参照。invoke は Py-UNO ブリッジのソースを見ないと分かりませんが。 .container.XNameAccess
ドキュメントの DialogLibraries から Standard ライブラリを取得、さらにダイアログ名全てを getElementNames で取得しようとしたとき。 ダイアログがあるときには tuple で要素名が戻るが、一つも無いときにはなぜか uno.ByteSequence のインスタンスが戻る。事前に .container.XElementAccess の hasElements で調べておくのが正解。 OOo Basic ではこの場合、空の配列が戻る。一方、introspection から getElementNames メソッドを invoke すると空の tuple か None が戻る (どちらか未確認)。 UNO コンポーネントの initialize
Py-UNO で実装した UNO コンポーネントの初期化が必要な場合に com.sun.star.lang.XInitialization インターフェースを実装する。このインターフェースのメソッドは initialize。 void initialize( [in] []any aArgs ) raise( com.sun.star.uno.Exception ) Java などで実装した UNO コンポーネントはこのメソッドを通じて (ある意味) 初期化される。DispatchProvider や StatusbarController、PopupMenuController などのフレームごとのサービスではそのフレームごとにインスタンスが作成されるため、それに対応してそのフレームへの参照が渡される。 上記のような初期化が行われると IDL リファレンスなどに記載があるが、Py-UNO コンポーネントで XInitialize インターフェースを実装していてもなぜか initialize メソッドは呼ばれない時がある。 Py-UNO コンポーネントの場合、initialize メソッドで初期化時に渡される引数 (上記では aArgs) は __init__ と同時に渡される!。 しかも、
というわけで、Py-UNO コンポーネントで XInitialize インターフェースを通じて初期化される場合には、__init__ メソッドの引数はそれぞれ次のような感じにすると吉。
import
2.4 から独自のモジュールを import しやすくなりましたが、それ以前ではインポートできないというわけではありません。 以下は Python マクロとして作成。ファイル読み込み時に sys.path に Script/python へのパスを追加しています。 また、このとき import しているファイルが変更されても変更が適用されないようです。reload してやる必要があります。import したライブラリを修正した後で reload が必要なのは 2.4 以降でも変わりません。
import 問題
2.4 から容易にインポート出来るようになりました。これは、sys.path に実行されるスクリプトと同じディレクトリにある pythonpath ディレクトリまたは pythonpath.zip ファイルのパスが追加されるためです。 この path への追加は実行時に行われるため、拡張機能内にあるスクリプトが実行されると新しくエントリが追加されることになります。 別の拡張機能でも同じように追加されます。ここで、前のエントリに含まれるモジュールと同じ名前のモジュールがあると衝突して先に見つかった方がインポートされてしまいます。 パッケージに入れたりして解決しましょう。 これが起きる原因は OOo のプロセス内に存在する Python のインスタンスが一つだけなため。 import 問題2
python では先に見つかったものが利用されます。 二つの拡張機能パッケージに、次のような python のパッケージがあったとき競合が起きて後で sys.path に追加された方はインポートに失敗します。 A を先に実行した場合、mytools パッケージにある modA からインポートする。その後で B を実行すると検索されるのが A に含まれるパッケージの後なので modB が見つからないことになります。
これは普通の Python の挙動です。が、普通は別々に置いたりしません。一方で OOo の拡張機能は別々のディレクトリに配置されてしまうため、パッケージ名が衝突する可能性が出てきます。 要約すると、以下参照。multiple_source_files Python スクリプトの URI (URL)
Python スクリプトを実行する時の URL は次のような感じになります。 vnd.sun.star.script:FILE_NAME.py$FUNCTION_NAME?language=Python&location=user ここで、FILE_NAME は user/Script/python ディレクトリからの相対パスになります。(./ や ../ などは不可(?)。) A.py ファイルが python/test ディレクトリにあるときには次のように指定します。 vnd.sun.star.script:test|A.py$py_test?language=Python&location=user URL を記述するのは面倒ですが、BookmarksMenu 拡張機能の mytools_BookmarksMenu scriptbrowser モジュールの ScriptBrowsing を実行すると簡単に URL を取得できます (単独で利用可)。 Python スクリプトの URI 2 (拡張機能)
拡張機能に Scripting Framework Script として Python スクリプトを入れた場合の URL。 拡張機能に SFS として入れる場合には manifest.xml は次の様になります。 <manifest:file-entry manifest:full-path="python/" manifest:media-type="application/vnd.sun.star.framework-script"/> python ディレクトリに NAME.py などのファイルを入れておきます。 拡張機能パッケージの名前が NAME_VERSION.oxt などの場合 URI は次の様になります。 vnd.sun.star.script:NAME_VERSION|python|NAME.py$FUNCTION?language=Python&location=user:uno_packages URI に拡張機能パッケージ名が入るためバージョンなどが変わると一々書き換えなければいけなくなります。 また、Base URI に ../ などの相対パスが含まれていると実行に失敗します。 Python マクロの実行
Scripting Framwork Script として Python マクロを書いているときに実行を一々、ツール - マクロ - マクロの管理 - Python... とするのは面倒。 大抵 Basic IDE が開いているので次のような OOo Basic のコードを書いておいて Basic プログラムの実行ボタンを押してやり Python スクリプトを実行する。 sURI を書き換えるだけで実行するスクリプトを変更できます。
現在のロケールを取得
現在のロケールをコンフィグレーションから取得して .lang.Locale にして戻す。
拡張機能ディレクトリ URL の取得
拡張機能 ID を設定しておく必要があります。拡張機能のターゲットが 2.3 以降であれば if 文の前半までしか必要ありません。else 以降は 2.0.4-2.2 もターゲットにする場合には必要。
[]
[] は Python だと空のリスト。UNO で []long などと表記する時には UNO の Sequence で中身が long であることを示す。Py-UNO の UNO 側で Sequence のときには Python 側では tuple。 この [] を使った表記は内部で利用されているもので、IDL ガイドなどでは sequence<long> などのようになっている。IDL ファイルを書くときや Reflection、TypeDetection などを利用する時には []long などの表記を使う。 [][]long だと Sequence の Sequence で内容が long 型。 ( (1,2,3), (4,5,6) ) また、UNO の Sequence は内容が単一の型のみ許容。Any も一つの決まった型なので com.sun.star.beans.PropertyValue など様々な値を保持する場合には Any が使われている。 IDL に定義された型以外の値を渡そうとすると (メソッドや要素などに) そのときに例外が送出される。 UNO の TypeClass に Array の定義があるがこれは使われない。 UNO の型定義は com.sun.star.uno.TypeClass enum にある。 XTransferable
Python のユニコード文字を XTransferable インターフェースを利用してコピーできるようにしようとしたが、 text/plain;charset=utf-8 ではうまく行かない。そもそも Basic IDE では ...=utf-16 しか要求がこない。といっても、エディタに貼り付けも失敗する。 ascii 文字しかなかったので、次のようにしておいた。 df = MimeType() df.MimeType = u'text/plain;charset=utf-16' data = text.encode('ascii') fileUrlToSystemPath
OOo では file:/// 形式でファイルパスを取り扱うが、システムパスに変換したいときには fileUrlToSystemPath メソッドを利用することがある。しかし、このメソッドは日本語などの文字があると失敗する。 urllib で変換しようとすると、次のようにする必要があるらしい。OOo 側から Py-UNO ブリッジを通じて来る文字列はいつも Python のユニコード文字。 import urllib st = u'mojimoji' en = urllib.unquote(st.encode('ascii')) print unicode(en,'utf8') 2.4.1 で修正予定。i86251 修正済みのバイナリを試してみたが、変わりなし。URL エンコードされた "file:///(略)%E3%83%87%E3%82%B9%E3%82%AF%E3%83%88%E3%83%83%E3%83%97" (デスクトップ)をファイルパスに変換しようとしてみたがエラー。 UnicodeEncodeError: 'ascii' codec can't encode characters in position 35-40: ordinal not in range(128) UNO コンポーネント作成
UNO コンポーネントを作成する場合、登録が必要なコンポーネント以外では外部からオートメーションとして接続して作成するほうが手間が少なくて済む。 次のようなもので行うと楽。Windows での OOo インストールでは python23.dll が program に配置されているが、実行する Python は program/python-2.3.4/bin/python.exe なので、program にパスを通しておかないと失敗する。もちろん、tcp コネクトでもよいが Win 環境の OOo 2.4 では tcp コネクトでバグがあるので注意。
stream への保存
storeAsURL メソッドなどでエクスポートするときに private:stream へ保存することができる。OutputStream で指定されたストリームへデータが渡されてディスク上に書き込まれない。 com.sun.star.io.Pipe などを使用してもよいが、com.sun.star.io.XOutputStream インターフェースを備えたクラスを代わりに使用できる。必要に応じて XInputStream も継承する。
wxPython
OOo の GUI ツールキットである awt ツールキットはいろいろなコントロールを提供してくれない。また、TKinter は動かない?ので他の GUI ツールキットとして wxPython を OOo の Python から利用してみよう。 Windows XP、OOo 2.4 で試してみた。簡単に追加、削除およびインポートできるように拡張機能パッケージ化して入れてみることに。
インストールは特に登録するファイルがないため解凍されるだけです。 wx モジュールをインポートするには次のように拡張機能 ID を指定して PackageInformationProvider サービスを使ってディレクトリパスを取得、sys.path のインクルードパスに追加します。 Scripting Framework Script として実行する場合は次のような形になる。
linux だとなんかエラーが出るので不明。 ツールバーのボタンに Python マクロを割り当てる
ツールバーのボタンに Python で記述したマクロを割り当てる場合には、実行時に引数が与えられることを考慮する必要があります。
特に必要な引数ではありませんが、不要な引数でも受け取るようにしておかなければ exceptions.TypeError になります。 ssl
3.3 からは ssl モジュールが利用できます (Windows 上のみ)。winpdb デバッガなども容易に利用できるようになります。 |