Top > OOoPython > Automation

オートメーション Edit

Python スクリプトを OOo 内部で動作させるのではなく外部に置いたスクリプトから OOo に接続して OOo を操作します。

OOo 2.4 を Windows で利用しているときにソケットを通じた接続に失敗します。パイプは使えます。i87894

一応、

import socket

とすると接続できるようです。

環境変数 Edit

OOo 付属の Python ではなく外部の Python を利用するときには幾つかの環境変数を設定しておく必要があります。

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

ソケット接続 Edit

Py-UNO では OOo へ TCP/IP 接続して OOo を制御できます。

OOo を次のようなオプションを付けて起動しておかなければいけません。

"-accept=socket,host=localhost,port=2002;urp;StarOffice.ServiceManager"

port=2002 は接続に利用する TCP/IP ポート番号です。

  0
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
import uno
 
def connect():
	try:
		localctx = uno.getComponentContext()
		resolver = localctx.ServiceManager.createInstanceWithContext(
			"com.sun.star.bridge.UnoUrlResolver",localctx)
		ctx = resolver.resolve(
			"uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
	except:
		return None
	return ctx
 
 
if __name__=="__main__":
	ctx = connect()
	if ctx == None:
		print "Failed to connect."
		import sys
		sys.exit()
	smgr = ctx.ServiceManager
	desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop",ctx)
	model = desktop.loadComponentFromURL("private:factory/scalc","_default",0,())
	
	ctx.ServiceManager

パイプ接続 Edit

メモリ共有による OOo との接続。OOo を次のようなオプションを付けて起動しておきます。

"-accept=pipe,name=pypipe;urp;StarOffice.ServiceManager"

name=pypipe は使用するパイプ名です。接続時にも同じ名前を使用します。

  0
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
import uno
 
def connect():
	try:
		localctx = uno.getComponentContext()
		resolver = localctx.ServiceManager.createInstanceWithContext(
			"com.sun.star.bridge.UnoUrlResolver",localctx)
		ctx = resolver.resolve(
			"uno:pipe,name=pypipe;urp;StarOffice.ComponentContext")
	except:
		return None
	return ctx
 
 
if __name__=="__main__":
	ctx = connect()
	if ctx == None:
		print "Failed to connect."
		import sys
		sys.exit()
	smgr = ctx.ServiceManager
	desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop",ctx)
	model = desktop.loadComponentFromURL("private:factory/scalc","_default",0,())
	
	ctx.ServiceManager

接続方法による違い Edit

ソケットとパイプ、二つの接続方法の詳細は DevGuide UNO Concepts を参照してください。

パイプ接続のほうがわずかに早いと書かれています。

次のようなコードで比較してみます。

  0
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
	model = desktop.loadComponentFromURL("private:factory/scalc","_default",0,())
	model.lockControllers()
	model.enableAutomaticCalculation(False)
	
	sheets = model.getSheets()
	sheet = sheets.getByIndex(0)
	
	t1 = time.time()
	nCols = 100
	nRows = 1000
	
	for i in range(nCols):
		for j in range(nRows):
			sheet.getCellByPosition(i,j).setValue(1.0)
	
	t2 = time.time()
	
	print "Iteration: %s" % (nCols * nRows)
	print "Total time: %.3f" % (t2 - t1)
	print "An iteration : %.3f" % ((t2 - t1) / (nCols * nRows))
	
	model.unlockControllers()

セル 100000 ヶに数値を書き込む処理の結果です。結果は参考程度まで。

接続合計 (秒)一回 (ミリ秒)
ソケット265.1265
パイプ187.9188

bootstrap と connection Edit

起動と接続用。

  0
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
from time import sleep
from subprocess import Popen
 
import uno
import unohelper
 
from com.sun.star.script.provider import XScriptContext
from com.sun.star.connection import NoConnectException
 
 
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 construct_url(connectionType, keys):
    if connectionType == "socket":
        tcpDelay = keys.get("tcpNoDelay", "0")
        host = keys.get("host", "localhost")
        port = keys.get("port", "2002")
        args = "-accept=socket,host=%s,port=%s,tcpNoDelay=%s;urp;StarOffice.ServiceManager" % (host, port, tcpDelay)
        url = "uno:socket,host=%s,port=%s,tcpNoDelay=%s;urp;StarOffice.ComponentContext" % (host, port, tcpDelay)
    elif connectionType == "pipe":
        pipeName = keys.get("name", "pythonpipe")
        args = "-accept=pipe,name=%s;urp;StarOffice.ServiceManager" % pipeName
        url = "uno:pipe,name=%s;urp;StarOffice.ComponentContext" % pipeName
    else:
        print(connectionType)
        raise ValueError("unknown connection type: " + connectionType)
    return (url, args)
 
 
def bootstrap(officePath="soffice", connectionType="socket", **keys):
    """ Bootstrapping OpenOffice.org and connect to it. """
    if "url" in keys:
        url = keys["url"]
    else:
        url, args = construct_url(connectionType, keys)
    
    ctx = None
    for i in range(20):
        try:
            ctx = connect(url=url)
        except NoConnectException:
            try:
                Popen([officePath, args])
            except OSError:
                raise Exception("no office executable found: " + officePath)
            sleep(1)
        if ctx:
            break
    return ctx
 
 
def connect(connectionType="socket", **keys):
    """ connect to living OpenOffice.org. """
    if "url" in keys:
        url = keys["url"]
    else:
        url, args = construct_url(connectionType, keys)
    
    localctx = uno.getComponentContext()
    resolver = localctx.getServiceManager().createInstanceWithContext(
        "com.sun.star.bridge.UnoUrlResolver", localctx)
    return resolver.resolve(url)

Reload   New Lower page making Edit Freeze Diff Upload Copy Rename   Front page List of pages Search Recent changes Backup   Help   RSS of recent changes