Автоматичний запуск Libre/OpenOffice в режимі прослуховування з Python

Libre/Open Office надають можливість роботи з офісом через UNO API. Для того, щоб можна було звернутися до офісу необхідно запустити його в режимі прослуховування.

Наприклад:
soffice --accept="socket,host=localhost port=2002;urp;"

Даний підхід цілком логічний і зрозумілий з точки зору розробників офісу, але несе ряд незручностей. Зокрема, потрібно самостійно запускати Libre/Open Office у режимі прослуховування. Особисто мені не зрозуміло, чому розробники полінувалися і не надали функції запуску офісу. Ну да ладно, було б все зроблено, були б не потрібні програмісти. Тому будемо вирішувати завдання своїми силами.

Найпростіший спосіб вирішити дану задачу — помістити рядок запуску офісу в скриптова файл. У ньому запускати спершу офіс, а потім свій додаток. Але якщо це, наприклад, бібліотека і немає можливості звернутися до неї через скриптова файл. До того ж треба не просто дочекатися запуску офісу, але ще і дочекатися, поки він буде у режимі прослуховування. Загалом цей підхід годиться лише для тестових завдань, не більше.
Я зупинився на наступній реалізації:
1. Форк процесу, який запускає офіс в режимі прослуховування.
2. З певною періодичністю намагатися звертатися до офісу, поки спроба не виявиться успішною.
3. Якщо через певний час спроба підключення до офісу не буде успішною, то генерувати виключення com.sun.star.connection.NoConnectException.

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

import os
import subprocess
import sys
import time
import uno

NoConnectException = uno.getClass(
"com.sun.star.connection.NoConnectException")

###############################################################################
def init_office():
"""
Test Libre/Open Office to be launched in the listening mode
"""
connection_string = "uno:socket,host=localhost port=2002;urp;\
StarOffice.ComponentContext"
oLocal = uno.getComponentContext()
oResolver = \
oLocal.ServiceManager.createInstanceWithContext(
"com.sun.star.bridge.UnoUrlResolver", oLocal)
if oResolver:
oContext = oResolver.resolve(connection_string)
oDesktop = oContext.ServiceManager.\
createInstanceWithContext("com.sun.star.frame.Desktop",
oContext)

###############################################################################
def start_office(timeout=30, attempt_period=0.1, office='soffice --accept="socket,host=localhost port=2002;urp;"'):
"""
Starts Libre/Open Office with a listening socket.

@type timeout: int
@param timeout: Timeout for starting Libre/Open Office in seconds

@type attempt_period: int
@param attempt_period: Timeout between attempts in seconds

@type office: string
@param office: Libre/Open Office startup string
"""
###########################################################################
def start_office_instance(office):
"""
Starts Libre/Open Office with a listening socket.

@type office: string
@param office: Libre/Open Office startup string
"""
# Fork to execute Office
if os.fork():
return

# Start OpenOffice.org and report any errors that occur.
try:
retcode = subprocess.call(office, shell=True)
if retcode < 0:
print (sys.stderr,
"Office was terminated by signal",
-retcode)
elif retcode > 0:
print (sys.stderr,
"Office returned",
retcode)
except OSError as e:
print (sys.stderr, "Execution failed:", e)

# Terminate this process when Office has closed.
raise SystemExit()

###########################################################################
waiting = False
try:
init_office()
except NoConnectException as e:
waiting = True
start_office_instance(office)

if waiting:
steps = int(timeout/attempt_period)
exception = None
for i in range(steps + 1):
try:
init_office()
break
except NoConnectException as e:
exception = e
time.sleep(attempt_period)
else:
if exception:
raise NoConnectException(exception)
else:
raise NoConnectException()

###############################################################################

start_office()


Даний приклад буде намагатися запустити Libre/Open Office з періодичністю 0.1 секунда на протязі 30 секунд.
В якості тесту на наявність запущеного в режимі прослуховування офісу використовується функція init_office(). Замість неї може бути використана будь-яка інша з Вашої бібліотеки.

Раніше, у статті "PyOOCalc — Бібліотека для генерації звітів, рахунків Libre/Open Office Calc на Python", я описав як простіше працювати з Libre/OpenOffice для певної категорії завдань. Але бібліотека PyOOCalc мала можливості автоматичного запуску офісу в режимі прослуховування, і вищенаведений код можна переписати наступним чином.
Замість функції init_office() можна написати:
import pyoocalc
pyoocalc.Document()

Це так само може бути будь-яка інша бібліотека. Необхідно викликати метод, який буде намагатися підключитися до Libre/Open Office.

Так само я додав можливість автоматичного запуску офісу в бібліотеку PyOOCalc.
Приклад використання:
import pyoocalc
doc = pyoocalc.Document(autostart=True)
doc.new_document()


Джерело: Хабрахабр
  • avatar
  • 0

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.