wizards/source/scriptforge/SF_Session.xba | 4 wizards/source/scriptforge/python/scriptforge.py | 136 ++++++++++++++++++++--- 2 files changed, 126 insertions(+), 14 deletions(-)
New commits: commit c1f5d07f359a33bb45c27d3fb703c2ba841cebfc Author: Jean-Pierre Ledure <j...@ledure.be> AuthorDate: Fri Mar 26 12:03:53 2021 +0100 Commit: Jean-Pierre Ledure <j...@ledure.be> CommitDate: Fri Mar 26 17:31:39 2021 +0100 ScriptForge - (scriptforge.py) Session class Full support of the session class methods from Python The InvokeSimpleScript() python method has been extended to support broader scopes (extensions and user documents) and ParamArray arguments in Basic. Indeed the SF_Session.ExecuteBasicScript() and SF_Session.ExecuteCalcFunction() require a varying number of arguments. No regression found in unit tests Change-Id: I0899bc6535b00340ed82b46336d60a7bb23b2098 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/113154 Tested-by: Jean-Pierre Ledure <j...@ledure.be> Tested-by: Jenkins Reviewed-by: Jean-Pierre Ledure <j...@ledure.be> diff --git a/wizards/source/scriptforge/SF_Session.xba b/wizards/source/scriptforge/SF_Session.xba index 2a56e91f1a55..182fe1049f0b 100644 --- a/wizards/source/scriptforge/SF_Session.xba +++ b/wizards/source/scriptforge/SF_Session.xba @@ -216,6 +216,10 @@ Check: Try: ' Execute function Set oCalc = SF_Utils._GetUNOService("FunctionAccess") + ' Intercept calls from Python when no arguments. Example NOW() + If UBound(pvArgs) = 0 Then + If IsEmpty(pvArgs(0)) Then pvArgs = Array() + End If On Local Error GoTo CatchCall vReturn = oCalc.callFunction(UCase(CalcFunction), pvArgs()) diff --git a/wizards/source/scriptforge/python/scriptforge.py b/wizards/source/scriptforge/python/scriptforge.py index 92f214c34e52..c90264ad09bb 100644 --- a/wizards/source/scriptforge/python/scriptforge.py +++ b/wizards/source/scriptforge/python/scriptforge.py @@ -104,7 +104,7 @@ class ScriptForge(object, metaclass = _Singleton): Version = '7.2' # Actual version number # # Basic dispatcher for Python scripts - basicdispatcher = 'ScriptForge.SF_PythonHelper._PythonDispatcher' + basicdispatcher = '@application:ScriptForge.SF_PythonHelper._PythonDispatcher' # Python helper functions module pythonhelpermodule = 'ScriptForgeHelper.py' # @@ -187,27 +187,45 @@ class ScriptForge(object, metaclass = _Singleton): """ Create a UNO object corresponding with the given Python or Basic script The execution is done with the invoke() method applied on the created object - Implicit scope: Extensions and documents are excluded. Either + Implicit scope: Either "application" a shared library (BASIC) "share" a library of LibreOffice Macros (PYTHON) :param script: Either - [library.]module.method - Must not be a class module or method - [directory/]module.py$method - :return: the script object as a com.sun.star.script.provider.XScript UNO object + [@][scope:][library.]module.method - Must not be a class module or method + [@] means that the targeted method accepts ParamArray arguments (Basic only) + [scope:][directory/]module.py$method - Must be a method defined at module level + :return: the value returned by the invoked script, or an error if the script was not found """ - # Compute the URI specification described in - # https://wiki.openoffice.org/wiki/Documentation/DevGuide/Scripting/Scripting_Framework_URI_Specification + + # The frequently called PythonDispatcher in the ScriptForge Basic library is buffered to privilege performance if cls.servicesdispatcher is not None and script == ScriptForge.basicdispatcher: xscript = cls.servicesdispatcher + fullscript = script + paramarray = True + # Build the URI specification described in + # https://wiki.openoffice.org/wiki/Documentation/DevGuide/Scripting/Scripting_Framework_URI_Specification elif len(script) > 0: + # Check ParamArray arguments + paramarray = False + if script[0] == '@': + script = script[1:] + paramarray = True + scope = '' + if ':' in script: + scope, script = script.split(':') if '.py$' in script.lower(): # Python - uri = 'vnd.sun.star.script:' + script + '?language=Python&location=share' + if len(scope) == 0: + scope = 'share' # Default for Python + uri = 'vnd.sun.star.script:' + script + '?language=Python&location=' + scope else: # Basic + if len(scope) == 0: + scope = 'application' # Default for Basic lib = '' if len(script.split('.')) < 3: - lib = cls.library + '.' - uri = 'vnd.sun.star.script:' + lib + script + '?language=Basic&location=application' + lib = cls.library + '.' # Default library = ScriptForge + uri = 'vnd.sun.star.script:' + lib + script + '?language=Basic&location=' + scope # Get the script object + fullscript = ('@' if paramarray else '') + scope + ':' + script try: xscript = cls.scriptprovider.getScript(uri) except Exception: @@ -215,15 +233,18 @@ class ScriptForge(object, metaclass = _Singleton): + ' could not be located in your LibreOffice installation') else: # Should not happen return None + + # At 1st execution of the common Basic dispatcher, buffer xscript + if fullscript == ScriptForge.basicdispatcher and cls.servicesdispatcher is None: + cls.servicesdispatcher = xscript + # Execute the script with the given arguments # Packaging for script provider depends on presence of ParamArray arguments in the called Basic script - if script == ScriptForge.basicdispatcher: - # At 1st execution, buffer xscript - if cls.servicesdispatcher is None: - cls.servicesdispatcher = xscript + if paramarray: scriptreturn = xscript.invoke(args[0], (), ()) else: scriptreturn = xscript.invoke(args, (), ()) + # return scriptreturn[0] # Updatable arguments passed by reference are ignored @@ -1057,6 +1078,93 @@ class SFScriptForge: return self.SIMPLEEXEC(self.py, 'Processor') processor = Processor + # ######################################################################### + # SF_Session CLASS + # ######################################################################### + class SF_Session(SFServices, metaclass = _Singleton): + """ + The Session service gathers various general-purpose methods about: + - UNO introspection + - the invocation of external scripts or programs + """ + # Mandatory class properties for service registration + serviceimplementation = 'basic' + servicename = 'ScriptForge.Session' + servicesynonyms = ('session', 'scriptforge.session') + serviceproperties = dict() + propertysynonyms = SFServices._getAttributeSynonyms(serviceproperties) + + # Class constants Where to find an invoked library ? + SCRIPTISEMBEDDED = 'document' # in the document + SCRIPTISAPPLICATION = 'application' # in any shared library (Basic) + SCRIPTISPERSONAL = 'user' # in My Macros (Python) + SCRIPTISPERSOXT = 'user:uno_packages' # in an extension installed for the current user (Python) + SCRIPTISSHARED = 'share' # in LibreOffice macros (Python) + SCRIPTISSHAROXT = 'share:uno_packages' # in an extension installed for all users (Python) + SCRIPTISOXT = 'uno_packages' # in an extension but the installation parameters are unknown (Python) + + def ExecuteBasicScript(self, scope = '', script = '', *args): + if scope is None or scope == '': + scope = self.SCRIPTISAPPLICATION + if len(args) == 0: + args = (scope,) + (script,) + (None,) + else: + args = (scope,) + (script,) + args + # ExecuteBasicScript method has a ParamArray parameter in Basic + return self.SIMPLEEXEC('@SF_Session.ExecuteBasicScript', args) + executeBasicScript, executebasicscript = ExecuteBasicScript, ExecuteBasicScript + + def ExecuteCalcFunction(self, calcfunction, *args): + if len(args) == 0: + # Arguments of Calc functions are strings or numbers. None == Empty is a good alias for no argument + args = (calcfunction,) + (None,) + else: + args = (calcfunction,) + args + # ExecuteCalcFunction method has a ParamArray parameter in Basic + return self.SIMPLEEXEC('@SF_Session.ExecuteCalcFunction', args) + executeCalcFunction, executecalcfunction = ExecuteCalcFunction, ExecuteCalcFunction + + def ExecutePythonScript(self, scope = '', script = '', *args): + return self.SIMPLEEXEC(scope + ':' + script, *args) + executePythonScript, executepythonscript = ExecutePythonScript, ExecutePythonScript + + def HasUnoMethod(self, unoobject, methodname): + return self.Execute(self.vbMethod, 'HasUnoMethod', unoobject, methodname) + hasUnoMethod, hasunomethod = HasUnoMethod, HasUnoMethod + + def HasUnoProperty(self, unoobject, propertyname): + return self.Execute(self.vbMethod, 'HasUnoProperty', unoobject, propertyname) + hasUnoProperty, hasunoproperty = HasUnoProperty, HasUnoProperty + + def OpenURLInBrowser(self, url): + py = ScriptForge.pythonhelpermodule + '$' + '_SF_Session__OpenURLInBrowser' + return self.SIMPLEEXEC(py, url) + openURLInBrowser, openurlinbrowser = OpenURLInBrowser, OpenURLInBrowser + + def RunApplication(self, command, parameters): + return self.Execute(self.vbMethod, 'RunApplication', command, parameters) + runApplication, runapplication = RunApplication, RunApplication + + def SendMail(self, recipient, cc = '', bcc = '', subject = '', body = '', filenames = '', editmessage = True): + return self.Execute(self.vbMethod, 'SendMail', recipient, cc, bcc, subject, body, filenames, editmessage) + sendMail, sendmail = SendMail, SendMail + + def UnoObjectType(self, unoobject): + return self.Execute(self.vbMethod, 'UnoObjectType', unoobject) + unoObjectType, unoobjecttype = UnoObjectType, UnoObjectType + + def UnoMethods(self, unoobject): + return self.Execute(self.vbMethod, 'UnoMethods', unoobject) + unoMethods, unomethods = UnoMethods, UnoMethods + + def UnoProperties(self, unoobject): + return self.Execute(self.vbMethod, 'UnoProperties', unoobject) + unoProperties, unoproperties = UnoProperties, UnoProperties + + def WebService(self, uri): + return self.Execute(self.vbMethod, 'WebService', uri) + webService, webservice = WebService, WebService + # ######################################################################### # SF_String CLASS # ######################################################################### _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits