Как я могу вызвать макрос Python в Формуле ячейки в OpenOffice.Org Калк?

чтобы расширить возможности OpenOffice, я определил некоторые макросы Python в файле в каталог пользовательских скриптов (~/Библиотека / Поддержка Приложений / OpenOffice.org/3 / user / Scripts / python/, в моем случае). Макросы отображаются в организаторе макросов Python. Однако использование функций в Формуле ячейки приводит к "#NAME?"(Ошибка OO.org 525).

предположим, я определил следующую функцию:

def pytype(val):
    return str(type(val))

как я могу назвать pytype в a формула клетки (например =PYTYPE("string"))?

фон

я импортирую некоторые данные из Authorize.net в базу данных MySQL для анализа. MySQL не может проанализировать формат даты и времени, используемый Authorize.net в DATETIME или TIMESTAMP поле, поэтому я пытаюсь массировать данные в формате, который MySQL может обрабатывать перед импортом. OpenOffice также не распознает данные как дату и время, и, насколько я смог определить, OO.Org не имеет общей функции анализа даты. Таким образом Я расширяюсь. OO.org возможности.

есть и другие подходы к более широкому вопросу. Например, я мог бы также попытаться исправить данные в MySQL post-import, используя дополнительные столбцы. Фактически, это то, что я сделал в первый раз; однако теперь в таблице есть данные, с которыми нужно бороться. Из-за этого и потому, что есть другие задачи в будущем, которые я надеюсь выполнить с помощью макросов в формулах, сейчас я в основном заинтересован в вызове макросов Python в формулы.

2 ответов


на старом OO.org форумы, (супер)пользователь Villeroy опубликовал иллюстрацию того, как звонить функции Python из OO.org Basic, который затем можно использовать в формулах. Ключ должен использовать com.sun.star.script.provider.MasterScriptProviderFactory обслуживание как мост. Вот адаптация его решения, обобщенная для вызова произвольных функций в произвольных модулях:

REM Keep a global reference to the ScriptProvider, since this stuff may be called many times: 
Global g_MasterScriptProvider as Object
REM Specify location of Python script, providing cell functions: 
Const URL_Main as String = "vnd.sun.star.script:" 
Const URL_Args as String = "?language=Python&location=user" 

Function invokePyFunc(file AS String, func As String, args As Array, outIdxs As Array, outArgs As Array)
   sURL = URL_Main & file & ".py$" & func & URL_Args
   oMSP = getMasterScriptProvider()
   On Local Error GoTo ErrorHandler
      oScript = oMSP.getScript(sURL)
      invokePyFunc = oScript.invoke(args, outIdxs, outArgs)
      Exit Function
   ErrorHandler:
      Dim msg As String, toFix As String
      msg = Error$
      toFix = ""
      If 1 = Err AND InStr(Error$, "an error occurred during file opening") Then
         msg = "Couldn' open the script file."
         toFix = "Make sure the 'python' folder exists in the user's Scripts folder, and that the former contains " & file & ".py."
      End If
      MsgBox msg & chr(13) & toFix, 16, "Error " & Err & " calling " & func
end Function

Function getMasterScriptProvider() 
   if isNull(g_MasterScriptProvider) then 
      oMasterScriptProviderFactory = createUnoService("com.sun.star.script.provider.MasterScriptProviderFactory") 
      g_MasterScriptProvider = oMasterScriptProviderFactory.createScriptProvider("") 
   endif 
   getMasterScriptProvider = g_MasterScriptProvider
End Function

Это можно использовать для создания OO.org базовая функция вызывается в Формуле. Используя пример pytype:

Const libfile as String = "util"    REM functions live in util.py

Function pytype(value)
    pytype = invokePyFunc(libfile, "pytype", Array(value), Array(), Array())
End Function

другой потенциальной реализацией является создание надстройка Python. Однако это гораздо более тяжелый вариант, поскольку он требует установки OpenOffice SDK, и для меня не очевидно, будет ли этот подход работать для бесплатных функций или работает только для классов.


outis - спасибо за ваш удивительный ответ. Если бы не ты, я бы уже сходил с ума, продолжая писать базовые макросы!

у меня есть несколько замечаний, хотя:

последние 2 аргумента для invokePyFunc всегда пусты - просто используйте это:

const filename = "your_file"

Function pyFunc(func as String, args as Array)
    pyFunc = invokePyFunc(filename, func, args, Array(), Array())
End Function

многомерные массивы сложно вернуть. Если вы вернетесь ((1,2,3), (4,5,6)) calc обрабатывает это как 2 ячейки в строке, содержащей неизвестные объекты.

это потому, что basic и python лечить многомерные массивы по-разному.

если вы вернете такую структуру в basic, вы должны получить к ней доступ, как data(row)(col) и calc ожидает data(row, col) для многомерных массивов.

из-за этого вам нужно использовать функцию конвертера для возвращаемых значений:

' Converts python multidimensional arrays to basic arrays.
function convPy2Basic(pyvalue)
    if isarray(pyvalue) then
        dim lastRow as integer 
        lastRow = ubound(pyvalue)
        if lastRow = -1 then
            ' empty array
            convPy2Basic = ""
        else
            if isarray(pyvalue(0)) then
                ' Multi-dimensional array
                dim maxCols as integer, lastCol as integer
                maxCols = ubound(pyvalue(0))

                dim res(lastRow, maxCols)
                for rowIndex = 0 to lastRow
                    lastCol = ubound(pyvalue(rowIndex))

                    ' Expand array if needed.
                    if lastCol > maxCols then
                        maxCols = lastCol
                        redim preserve res(lastRow, maxCols)
                    end if

                    for colIndex = 0 to lastCol
                        res(rowIndex, colIndex) = pyvalue(rowIndex)(colIndex)
                    next colIndex
                next rowIndex

                convPy2Basic = res
            else
                ' Single-dimensional array - this is supported by libreoffice
                convPy2Basic = pyvalue
            end if
        end if
    else
        convPy2Basic = pyvalue
    end if
end function

Function invokeScriptFunc(file AS String, lang, ext, func As String, args As Array, outIdxs As Array, outArgs As Array)
   sURL = URL_Main & file & "." & ext & "$" & func & "?language=" & lang & "&location=user" 
   oMSP = getMasterScriptProvider()
   oScript = oMSP.getScript(sURL)
   invokeScriptFunc = oScript.invoke(args, outIdxs, outArgs)
end Function

Function invokePyFunc(file AS String, func As String, args As Array, outIdxs As Array, outArgs As Array)
   res = invokeScriptFunc(file, "Python", "py", func, args, outIdxs, outArgs)
   invokePyFunc = convPy2Basic(res)
end Function

Итак, мой мост макросов python-basic выглядит следующим образом:

' Keep a global reference to the ScriptProvider, since this stuff may be called many times: 
Global g_MasterScriptProvider as Object
' Specify location of Python script, providing cell functions: 
Const URL_Main as String = "vnd.sun.star.script:"

' Converts python multidimensional arrays to basic arrays.
function convPy2Basic(pyvalue)
    if isarray(pyvalue) then
        dim lastRow as integer 
        lastRow = ubound(pyvalue)
        if lastRow = -1 then
            ' empty array
            convPy2Basic = ""
        else
            if isarray(pyvalue(0)) then
                ' Multi-dimensional array
                dim maxCols as integer, lastCol as integer
                maxCols = ubound(pyvalue(0))

                dim res(lastRow, maxCols)
                for rowIndex = 0 to lastRow
                    lastCol = ubound(pyvalue(rowIndex))

                    ' Expand array if needed.
                    if lastCol > maxCols then
                        maxCols = lastCol
                        redim preserve res(lastRow, maxCols)
                    end if

                    for colIndex = 0 to lastCol
                        res(rowIndex, colIndex) = pyvalue(rowIndex)(colIndex)
                    next colIndex
                next rowIndex

                convPy2Basic = res
            else
                ' Single-dimensional array - this is supported by libreoffice
                convPy2Basic = pyvalue
            end if
        end if
    else
        convPy2Basic = pyvalue
    end if
end function

Function invokeScriptFunc(file AS String, lang, ext, func As String, args As Array, outIdxs As Array, outArgs As Array)
   sURL = URL_Main & file & "." & ext & "$" & func & "?language=" & lang & "&location=user" 
   oMSP = getMasterScriptProvider()
   oScript = oMSP.getScript(sURL)
   invokeScriptFunc = oScript.invoke(args, outIdxs, outArgs)
end Function

Function invokePyFunc(file AS String, func As String, args As Array, outIdxs As Array, outArgs As Array)
   res = invokeScriptFunc(file, "Python", "py", func, args, outIdxs, outArgs)
   invokePyFunc = convPy2Basic(res)
end Function

Function getMasterScriptProvider() 
   if isNull(g_MasterScriptProvider) then 
      oMasterScriptProviderFactory = createUnoService("com.sun.star.script.provider.MasterScriptProviderFactory") 
      g_MasterScriptProvider = oMasterScriptProviderFactory.createScriptProvider("") 
   endif 
   getMasterScriptProvider = g_MasterScriptProvider
End Function

const filename = "skaiciuokle"

Function pyFunc(func as String, args as Array)
    pyFunc = invokePyFunc(filename, func, args, Array(), Array())
End Function

и используется следующим образом:

function DamageToArmor(data, damageType as String, armorType as String, dmgPerGun as Integer, guns as Integer)
    DamageToArmor = pyFunc("dmg2armor", Array(data, damageType, armorType, dmgPerGun, guns))
end function