# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- # # This file is part of the LibreOffice project. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. # # This file incorporates work covered by the following license notice: # # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed # with this work for additional information regarding copyright # ownership. The ASF licenses this file to you under the Apache # License, Version 2.0 (the "License"); you may not use this file # except in compliance with the License. You may obtain a copy of # the License at http://www.apache.org/licenses/LICENSE-2.0 . # # XScript implementation for python import uno import unohelper import sys import os import types import time import ast import platform from com.sun.star.uri.RelativeUriExcessParentSegments import RETAIN from urllib.parse import unquote
class LogLevel: NONE = 0 # production level
ERROR = 1 # for script developers
DEBUG = 2 # for script framework developers
# from com.sun.star.lang import typeOfXServiceInfo, typeOfXTypeProvider from com.sun.star.uno import RuntimeException from com.sun.star.lang import IllegalArgumentException from com.sun.star.container import NoSuchElementException from com.sun.star.ucb import XCommandEnvironment, XProgressHandler, Command from com.sun.star.task import XInteractionHandler from com.sun.star.beans import XPropertySet, Property from com.sun.star.container import XNameContainer from com.sun.star.xml.sax import XDocumentHandler, InputSource from com.sun.star.uno import Exception as UnoException from com.sun.star.script import XInvocation from com.sun.star.awt import XActionListener
from com.sun.star.script.provider import XScriptProvider, XScript, ScriptFrameworkErrorException from com.sun.star.script.browse import XBrowseNode from com.sun.star.script.browse.BrowseNodeTypes import SCRIPT, CONTAINER
def scriptURI2StorageUri(self, scriptURI): try: # base path to the python script location
sBaseUri = self.m_baseUri + "/"
xBaseUri = self.m_uriRefFac.parse(sBaseUri)
# path to the .py file + "$functionname, arguments, etc
xStorageUri = self.m_uriRefFac.parse(scriptURI) # getName will apply url-decoding to the name, so encode back
sStorageUri = xStorageUri.getName().replace("%", "%25")
sStorageUri = sStorageUri.replace("|", "/")
# path to the .py file, relative to the base
funcNameStart = sStorageUri.find("$") if funcNameStart != -1:
sFileUri = sStorageUri[0:funcNameStart]
sFuncName = sStorageUri[funcNameStart + 1 :] else:
sFileUri = sStorageUri
ifnot xFileUri.hasRelativePath():
message = "pythonscript: an absolute uri is invalid '" + sFileUri + "'"
log.debug(message) raise RuntimeException(message, self.ctx)
# absolute path to the .py file
xAbsScriptUri = self.m_uriRefFac.makeAbsolute(xBaseUri, xFileUri, True, RETAIN)
sAbsScriptUri = xAbsScriptUri.getUriReference()
# ensure py file is under the base path ifnot sAbsScriptUri.startswith(sBaseUri):
message = "pythonscript: storage uri '" + sAbsScriptUri + "' not in base uri '" + self.m_baseUri + "'"
log.debug(message) raise RuntimeException(message, self.ctx)
ret = sAbsScriptUri if funcNameStart != -1:
ret = ret + "$" + sFuncName
log.debug("converting scriptURI=" + scriptURI + " to storageURI=" + ret) return ret except UnoException as e:
log.error("error during converting scriptURI=" + scriptURI + ": " + e.Message) raise RuntimeException("pythonscript:scriptURI2StorageUri: " + e.Message, self.ctx) except Exception as e:
log.error("error during converting scriptURI=" + scriptURI + ": " + str(e)) raise RuntimeException("pythonscript:scriptURI2StorageUri: " + str(e), self.ctx)
def removePackageByUrl(self, url):
items = self.mapPackageName2Path.items() for i in items: if url in i[1].paths:
self.mapPackageName2Path.pop(i[0]) break
try:
code = ast.parse(src) except Exception:
log.isDebugLevel() and log.debug( "pythonscript: getFuncsByUrl: exception while parsing: " + lastException2String()
) raise
allFuncs = []
if code isNone: return allFuncs
g_exportedScripts = [] for node in ast.iter_child_nodes(code): if isinstance(node, ast.FunctionDef):
allFuncs.append(node.name) elif isinstance(node, ast.Assign): for target in node.targets: try:
identifier = target.id except AttributeError:
identifier = "" pass if identifier == "g_exportedScripts": for value in node.value.elts:
g_exportedScripts.append(value.id) return g_exportedScripts
return allFuncs
def getModuleByUrl(self, url):
entry = self.modules.get(url)
load = True
lastRead = self.sfa.getDateTimeModified(url) if entry: if hasChanged(entry.lastRead, lastRead):
log.debug("file " + url + " has changed, reloading") else:
load = False
# -------------------------------------------------- def isScript(candidate):
ret = False if isinstance(candidate, type(isScript)):
ret = True return ret
def getPropertyValue(self, name):
ret = None try: if name == "URI":
ret = self.provCtx.uriHelper.getScriptURI(
self.provCtx.getPersistentUrlFromStorageUrl(self.uri + "$" + self.funcName)
) elif name == "Editable"and ENABLE_EDIT_DIALOG:
ret = not self.provCtx.sfa.isReadOnly(self.uri)
log.debug("ScriptBrowseNode.getPropertyValue called for " + name + ", returning " + str(ret)) except Exception:
log.error("ScriptBrowseNode.getPropertyValue error " + lastException2String()) raise
return ret
def setPropertyValue(self, name, value):
log.debug("ScriptBrowseNode.setPropertyValue called " + name + "=" + str(value))
def getPropertySetInfo(self):
log.debug("ScriptBrowseNode.getPropertySetInfo called ") returnNone
def getIntrospection(self): returnNone
def invoke(self, name, params, outparamindex, outparams): if name == "Editable":
servicename = "com.sun.star.awt.DialogProvider"
ctx = self.provCtx.scriptContext.getComponentContext()
dlgprov = ctx.ServiceManager.createInstanceWithContext(servicename, ctx)
class ManifestHandler(XDocumentHandler, unohelper.Base): def __init__(self, rootUrl):
self.rootUrl = rootUrl
def startDocument(self):
self.urlList = []
def endDocument(self): pass
def startElement(self, name, attlist): if name == "manifest:file-entry": if attlist.getValueByName("manifest:media-type") == "application/vnd.sun.star.framework-script":
self.urlList.append(self.rootUrl + "/" + attlist.getValueByName("manifest:full-path"))
def endElement(self, name): pass
def characters(self, chars): pass
def ignoreableWhitespace(self, chars): pass
def setDocumentLocator(self, locator): pass
def isPyFileInPath(sfa, path):
ret = False
contents = sfa.getFolderContents(path, True) for i in contents: if sfa.isFolder(i):
ret = isPyFileInPath(sfa, i) else: if i.endswith(".py"):
ret = True if ret: break return ret
# extracts META-INF directory from def getPathsFromPackage(rootUrl, sfa):
ret = () try:
fileUrl = rootUrl + "/META-INF/manifest.xml"
inputStream = sfa.openFileRead(fileUrl)
parser = uno.getComponentContext().ServiceManager.createInstance("com.sun.star.xml.sax.Parser")
handler = ManifestHandler(rootUrl)
parser.setDocumentHandler(handler)
parser.parseStream(InputSource(inputStream, "", fileUrl, fileUrl)) for i in tuple(handler.urlList): ifnot isPyFileInPath(sfa, i):
handler.urlList.remove(i)
ret = tuple(handler.urlList) except UnoException:
text = lastException2String()
log.debug("getPathsFromPackage " + fileUrl + " Exception: " + text) pass return ret
def mapStorageType2PackageContext(storageType):
ret = storageType if storageType == "share:uno_packages":
ret = "shared" if storageType == "user:uno_packages":
ret = "user" return ret
def getPackageName2PathMap(sfa, storageType):
ret = {}
class PythonScript(unohelper.Base, XScript): def __init__(self, func, mod, args):
self.func = func
self.mod = mod
self.args = args
def invoke(self, args, out, outindex):
log.debug("PythonScript.invoke " + str(args)) try: if self.args:
args += self.args
ret = self.func(*args) except UnoException as e: # UNO Exception continue to fly ...
text = lastException2String()
complete = ( "Error during invoking function "
+ str(self.func.__name__)
+ " in module "
+ self.mod.__file__
+ " ("
+ text
+ ")"
)
log.debug(complete) # some people may beat me up for modifying the exception text, # but otherwise office just shows # the type name and message text with no more information, # this is really bad for most users.
e.Message = e.Message + " (" + complete + ")" raise except Exception: # General python exception are converted to uno RuntimeException
text = lastException2String()
complete = ( "Error during invoking function "
+ str(self.func.__name__)
+ " in module "
+ self.mod.__file__
+ " ("
+ text
+ ")"
)
log.debug(complete) raise RuntimeException(complete, self)
log.debug("PythonScript.invoke ret = " + str(ret)) return ret, (), ()
def expandUri(uri): if uri.startswith("vnd.sun.star.expand:"):
uri = uri.replace("vnd.sun.star.expand:", "", 1)
uri = (
uno.getComponentContext()
.getByName("/singletons/com.sun.star.util.theMacroExpander")
.expandMacros(unquote(uri))
) if uri.startswith("file:"):
uri = uno.absolutize("", uri) # necessary to get rid of .. in uri return uri
# -------------------------------------------------------------- class PythonScriptProvider(unohelper.Base, XBrowseNode, XScriptProvider, XNameContainer): def __init__(self, ctx, *args): if log.isDebugLevel():
mystr = "" for i in args: if len(mystr) > 0:
mystr = mystr + ","
mystr = mystr + str(i)
log.debug("Entering PythonScriptProvider.ctor" + mystr)
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.