Автоматический запуск 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()
    
    Метки:
    Поделиться публикацией
    Похожие публикации
    Комментарии 0

    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.