28from com.sun.star.uri.RelativeUriExcessParentSegments
import RETAIN
29from urllib.parse
import unquote
36PYSCRIPT_LOG_ENV =
"PYSCRIPT_LOG_LEVEL"
37PYSCRIPT_LOG_STDOUT_ENV =
"PYSCRIPT_LOG_STDOUT"
40LogLevel.use = LogLevel.NONE
41if os.environ.get(PYSCRIPT_LOG_ENV) ==
"ERROR":
42 LogLevel.use = LogLevel.ERROR
43elif os.environ.get(PYSCRIPT_LOG_ENV) ==
"DEBUG":
44 LogLevel.use = LogLevel.DEBUG
48LOG_STDOUT = os.environ.get(PYSCRIPT_LOG_STDOUT_ENV,
"1") !=
"0"
50ENABLE_EDIT_DIALOG=
False
54 return uni.encode( sys.getfilesystemencoding())
57 (excType,excInstance,excTraceback) = sys.exc_info()
58 ret = str(excType) +
": "+str(excInstance) +
"\n" + \
64 if level == LogLevel.ERROR:
66 elif level >= LogLevel.DEBUG:
75 "com.sun.star.util.PathSubstitution" )
76 userInstallation = pathSubst.getSubstituteVariableValue(
"user" )
77 if len( userInstallation ) > 0:
79 ret = open( systemPath ,
"a" )
81 print(
"Exception during creation of pythonscript logfile: "+
lastException2String() +
"\n, delegating log to stdout\n")
89 return self.use >= self.
DEBUG
96 return self.use >= self.
ERROR
102 def log( self, level, msg ):
103 if self.use >= level:
118log.debug(
"pythonscript loading" )
126from com.sun.star.ucb import CommandAbortedException, XCommandEnvironment, XProgressHandler, Command
135from com.sun.star.script.provider
import XScriptProvider, XScript, XScriptContext, ScriptFrameworkErrorException
136from com.sun.star.script.browse
import XBrowseNode
137from com.sun.star.script.browse.BrowseNodeTypes
import SCRIPT, CONTAINER, ROOT
140LANGUAGENAME =
"Python"
141GLOBAL_SCRIPTCONTEXT_NAME =
"XSCRIPTCONTEXT"
142CALLABLE_CONTAINER_NAME =
"g_exportedScripts"
146g_implName =
"org.libreoffice.pyuno.LanguageScriptProviderFor"+LANGUAGENAME
155 read,out = inputStream.readBytes(
None , BLOCK_SIZE )
157 if read < BLOCK_SIZE:
162 if platform.system() ==
"Windows":
168""" definition: storageURI is the system dependent, absolute file url, where the script is stored on disk
169 scriptURI is the system independent uri
176 {
"share" :
"vnd.sun.star.expand:$BRAND_BASE_DIR/$BRAND_SHARE_SUBDIR/Scripts/python" , \
177 "share:uno_packages" :
"vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE/uno_packages", \
178 "user" :
"vnd.sun.star.expand:${$BRAND_INI_DIR/" +
toIniName(
"bootstrap") +
"::UserInstallation}/user/Scripts/python" , \
179 "user:uno_packages" :
"vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/uno_packages" }
180 self.
m_uriRefFac = ctx.ServiceManager.createInstanceWithContext(
"com.sun.star.uri.UriReferenceFactory",ctx)
181 if location.startswith(
"vnd.sun.star.tdoc" ):
199 if not storageURI.startswith( self.
m_baseUri ):
200 message =
"pythonscript: storage uri '" + storageURI +
"' not in base uri '" + self.
m_baseUri +
"'"
202 raise RuntimeException( message, self.
ctx )
204 ret =
"vnd.sun.star.script:" + \
205 storageURI[len(self.
m_baseUri)+1:].replace(
"/",
"|") + \
207 log.debug(
"converting storageURI="+storageURI +
" to scriptURI=" + ret )
219 sStorageUri = xStorageUri.getName().replace(
"%",
"%25")
220 sStorageUri = sStorageUri.replace(
"|",
"/" )
223 funcNameStart = sStorageUri.find(
"$")
224 if funcNameStart != -1:
225 sFileUri = sStorageUri[0:funcNameStart]
226 sFuncName = sStorageUri[funcNameStart+1:]
228 sFileUri = sStorageUri
232 message =
"pythonscript: invalid relative uri '" + sFileUri+
"'"
234 raise RuntimeException( message, self.
ctx )
236 if not xFileUri.hasRelativePath():
237 message =
"pythonscript: an absolute uri is invalid '" + sFileUri+
"'"
239 raise RuntimeException( message, self.
ctx )
242 xAbsScriptUri = self.
m_uriRefFac.makeAbsolute(xBaseUri, xFileUri,
True, RETAIN)
243 sAbsScriptUri = xAbsScriptUri.getUriReference()
246 if not sAbsScriptUri.startswith(sBaseUri):
247 message =
"pythonscript: storage uri '" + sAbsScriptUri +
"' not in base uri '" + self.
m_baseUri +
"'"
249 raise RuntimeException( message, self.
ctx )
252 if funcNameStart != -1:
253 ret = ret +
"$" + sFuncName
254 log.debug(
"converting scriptURI="+scriptURI +
" to storageURI=" + ret )
256 except UnoException
as e:
257 log.error(
"error during converting scriptURI="+scriptURI +
": " + e.Message)
258 raise RuntimeException(
"pythonscript:scriptURI2StorageUri: " + e.Message, self.
ctx )
259 except Exception
as e:
260 log.error(
"error during converting scriptURI="+scriptURI +
": " + str(e))
261 raise RuntimeException(
"pythonscript:scriptURI2StorageUri: " + str(e), self.
ctx )
270 return newDate.Year > oldDate.Year
or \
271 newDate.Month > oldDate.Month
or \
272 newDate.Day > oldDate.Day
or \
273 newDate.Hours > oldDate.Hours
or \
274 newDate.Minutes > oldDate.Minutes
or \
275 newDate.Seconds > oldDate.Seconds
or \
276 newDate.NanoSeconds > oldDate.NanoSeconds
279 if code.endswith(b
"\n"):
281 code = code.replace(b
"\r", b
"")
286 if url.startswith(
"file:" ):
288 log.log( LogLevel.DEBUG,
"checking for existence of " + path )
289 if 1 == os.access(
encfile(path), os.F_OK)
and not path
in sys.path:
290 log.log( LogLevel.DEBUG,
"adding " + path +
" to sys.path" )
291 sys.path.append( path )
294 log.log( LogLevel.DEBUG,
"checking for existence of " + path )
295 if 1 == os.access(
encfile(path), os.F_OK)
and not path
in sys.path:
296 log.log( LogLevel.DEBUG,
"adding " + path +
" to sys.path" )
297 sys.path.append( path )
310 return self.
getDesktop().getCurrentComponent()
313 return self.
ctx.ServiceManager.createInstanceWithContext(
314 "com.sun.star.frame.Desktop", self.
ctx )
354 def __init__( self, storageType, sfa, uriHelper, scriptContext ):
364 rest = url.replace( self.
rootUrl ,
"",1 ).replace(
"/",
"",1)
365 return rest[0:rest.find(
"/")]
368 rest = url.replace( self.
rootUrl ,
"",1 ).replace(
"/",
"",1)
369 start = rest.find(
"/") +1
370 return rest[start:rest.find(
"/",start)]
376 if url
in i[1].paths:
383 log.debug(
"addPackageByUrl : " + packageName +
", " + transientPart +
"("+url+
")" +
", rootUrl="+self.
rootUrl )
386 package.paths = package.paths + (url, )
388 package =
Package( (url,), transientPart)
409 ret = url[0:pos]+url[url.find(
"/",pos)+1:len(url)]
410 log.debug(
"getPersistentUrlFromStorageUrl " + url +
" -> "+ ret)
417 packageName = url[pos:url.find(
"/",pos+1)]
419 ret = url[0:pos]+ package.transientPathElement +
"/" + url[pos:len(url)]
420 log.debug(
"getStorageUrlFromPersistentUrl " + url +
" -> "+ ret)
429 code = ast.parse( src )
431 log.isDebugLevel()
and log.debug(
"pythonscript: getFuncsByUrl: exception while parsing: " +
lastException2String())
439 g_exportedScripts = []
440 for node
in ast.iter_child_nodes(code):
441 if isinstance(node, ast.FunctionDef):
442 allFuncs.append(node.name)
443 elif isinstance(node, ast.Assign):
444 for target
in node.targets:
446 identifier = target.id
447 except AttributeError:
450 if identifier ==
"g_exportedScripts":
451 for value
in node.value.elts:
452 g_exportedScripts.append(value.id)
453 return g_exportedScripts
472 lastRead = self.
sfa.getDateTimeModified( url )
475 log.debug(
"file " + url +
" has changed, reloading" )
480 log.debug(
"opening >" + url +
"<" )
487 entry =
ModuleEntry( lastRead, types.ModuleType(
"ooo_script_framework") )
488 entry.module.__dict__[GLOBAL_SCRIPTCONTEXT_NAME] = self.
scriptContext
491 if url.startswith(
"file:" ):
494 code = compile( src, url,
"exec" )
495 exec(code, entry.module.__dict__)
496 entry.module.__file__ = url
498 log.debug(
"mapped " + url +
" to " + str( entry.module ) )
504 if isinstance( candidate, type(isScript) ):
510 def __init__( self, provCtx, uri, fileName, funcName ):
532 ret = self.
provCtx.uriHelper.getScriptURI(
534 elif name ==
"Editable" and ENABLE_EDIT_DIALOG:
535 ret =
not self.
provCtx.sfa.isReadOnly( self.
uri )
537 log.debug(
"ScriptBrowseNode.getPropertyValue called for " + name +
", returning " + str(ret) )
544 log.debug(
"ScriptBrowseNode.setPropertyValue called " + name +
"=" +str(value ) )
546 log.debug(
"ScriptBrowseNode.getPropertySetInfo called " )
552 def invoke( self, name, params, outparamindex, outparams ):
553 if name ==
"Editable":
554 servicename =
"com.sun.star.awt.DialogProvider"
555 ctx = self.
provCtx.scriptContext.getComponentContext()
556 dlgprov = ctx.ServiceManager.createInstanceWithContext(
560 "vnd.sun.star.script:" +
561 "ScriptBindingLibrary.MacroEditor?location=application")
565 self.
editor.getControl(
"EditorTextField").setText(code)
567 self.
editor.getControl(
"RunButton").setActionCommand(
"Run")
568 self.
editor.getControl(
"RunButton").addActionListener(self)
569 self.
editor.getControl(
"SaveButton").setActionCommand(
"Save")
570 self.
editor.getControl(
"SaveButton").addActionListener(self)
578 if event.ActionCommand ==
"Run":
579 code = self.
editor.getControl(
"EditorTextField").getText()
581 mod = types.ModuleType(
"ooo_script_framework")
582 mod.__dict__[GLOBAL_SCRIPTCONTEXT_NAME] = self.
provCtx.scriptContext
583 exec(code, mod.__dict__)
584 values = mod.__dict__.get( CALLABLE_CONTAINER_NAME ,
None )
586 values = mod.__dict__.values()
593 elif event.ActionCommand ==
"Save":
595 self.
editor.getControl(
"EditorTextField").getText().encode(
596 sys.getdefaultencoding()) )
597 copyUrl = self.
uri +
".orig"
599 out = self.
provCtx.sfa.openFileWrite( self.
uri )
600 out.writeBytes( toWrite )
602 self.
provCtx.sfa.kill( copyUrl )
642 scriptNodeList.append(
645 ret = tuple( scriptNodeList )
646 log.debug(
"returning " +str(len(ret)) +
" ScriptChildNodes on " + self.
uri )
649 log.error(
"Error while evaluating " + self.
uri +
":" + text )
675 log.debug(
"DirBrowseNode.getChildNodes called for " + self.
rootUrl )
676 contents = self.
provCtx.sfa.getFolderContents( self.
rootUrl,
True )
679 if i.endswith(
".py" ):
680 log.debug(
"adding filenode " + i )
681 browseNodeList.append(
683 elif self.
provCtx.sfa.isFolder( i )
and not i.endswith(
"/pythonpath"):
684 log.debug(
"adding DirBrowseNode " + i )
686 return tuple( browseNodeList )
687 except Exception
as e:
689 log.error(
"DirBrowseNode error: " + str(e) +
" while evaluating " + self.
rootUrl)
700 log.debug(
"DirBrowseNode getScript " + uri +
" invoked" )
701 raise IllegalArgumentException(
"DirBrowseNode couldn't instantiate script " + uri , self , 0 )
715 if name ==
"manifest:file-entry":
716 if attlist.getValueByName(
"manifest:media-type" ) ==
"application/vnd.sun.star.framework-script":
718 self.rootUrl +
"/" + attlist.getValueByName(
"manifest:full-path" ) )
734 contents = sfa.getFolderContents( path,
True )
739 if i.endswith(
".py"):
749 fileUrl = rootUrl +
"/META-INF/manifest.xml"
750 inputStream = sfa.openFileRead( fileUrl )
753 parser.setDocumentHandler( handler )
754 parser.parseStream( InputSource( inputStream ,
"", fileUrl, fileUrl ) )
755 for i
in tuple(handler.urlList):
757 handler.urlList.remove(i)
758 ret = tuple( handler.urlList )
761 log.debug(
"getPathsFromPackage " + fileUrl +
" Exception: " +text )
775 log.debug(
"pythonscript: DummyInteractionHandler.handle " + str( event ) )
782 log.debug(
"pythonscript: DummyProgressHandler.push " + str( status ) )
784 log.debug(
"pythonscript: DummyProgressHandler.update " + str( status ) )
786 log.debug(
"pythonscript: DummyProgressHandler.push " + str( event ) )
807 """Get document model from document url."""
809 args = (
"Local",
"Office")
810 ucb = ctx.getServiceManager().createInstanceWithArgumentsAndContext(
811 "com.sun.star.ucb.UniversalContentBroker", args, ctx)
812 identifier = ucb.createContentIdentifier(url)
813 content = ucb.queryContent(identifier)
815 p.Name =
"DocumentModel"
820 c.Name =
"getPropertyValues"
821 c.Argument =
uno.Any(
"[]com.sun.star.beans.Property", (p,))
825 ret = content.execute(c, 0, env)
826 doc = ret.getObject(1,
None)
827 except Exception
as e:
828 log.isErrorLevel()
and log.error(
"getModelFromDocUrl: %s" % url)
833 if( storageType ==
"share:uno_packages" ):
835 if( storageType ==
"user:uno_packages" ):
842 "/singletons/com.sun.star.deployment.thePackageManagerFactory" )
843 packageManager = packageManagerFactory.getPackageManager(
846 log.debug(
"pythonscript: getPackageName2PathMap start getDeployedPackages" )
847 packages = packageManager.getDeployedPackages(
849 log.debug(
"pythonscript: getPackageName2PathMap end getDeployedPackages (" + str(len(packages))+
")" )
852 log.debug(
"inspecting package " + i.Name +
"("+i.Identifier.Value+
")" )
858 log.debug(
"adding Package " + transientPathElement +
" " + str( paths ) )
863 lastSlash = aStr.rindex(
"/")
864 penultimateSlash = aStr.rindex(
"/",0,lastSlash-1)
865 return aStr[ penultimateSlash+1:lastSlash ]
868 return aStr[ aStr.rfind(
"/" )+1:len(aStr)]
880 items = self.
provCtx.mapPackageName2Path.items()
883 if len( i[1].paths ) == 1:
884 browseNodeList.append(
888 browseNodeList.append(
890 return tuple( browseNodeList )
893 return len( self.
provCtx.mapPackageName2Path ) > 0
899 log.debug(
"PackageBrowseNode getScript " + uri +
" invoked" )
900 raise IllegalArgumentException(
"PackageBrowseNode couldn't instantiate script " + uri , self , 0 )
912 log.debug(
"PythonScript.invoke " + str( args ) )
916 ret = self.
func( *args )
917 except UnoException
as e:
920 complete =
"Error during invoking function " + \
921 str(self.
func.__name__) +
" in module " + \
922 self.
mod.__file__ +
" (" + text +
")"
923 log.debug( complete )
928 e.Message = e.Message +
" (" + complete +
")"
930 except Exception
as e:
933 complete =
"Error during invoking function " + \
934 str(self.
func.__name__) +
" in module " + \
935 self.
mod.__file__ +
" (" + text +
")"
936 log.debug( complete )
937 raise RuntimeException( complete , self )
938 log.debug(
"PythonScript.invoke ret = " + str( ret ) )
942 if uri.startswith(
"vnd.sun.star.expand:" ):
943 uri = uri.replace(
"vnd.sun.star.expand:",
"",1)
945 "/singletons/com.sun.star.util.theMacroExpander" ).expandMacros( unquote(uri) )
946 if uri.startswith(
"file:" ):
953 if log.isDebugLevel():
958 mystr = mystr + str(i)
959 log.debug(
"Entering PythonScriptProvider.ctor" + mystr )
965 if isinstance(args[0], str):
966 storageType = args[0]
967 if storageType.startswith(
"vnd.sun.star.tdoc" ):
972 doc = inv.ScriptContainer
973 content = ctx.getServiceManager().createInstanceWithContext(
974 "com.sun.star.frame.TransientDocumentsDocumentContentFactory",
975 ctx).createDocumentContent(doc)
976 storageType = content.getIdentifier().getContentIdentifier()
977 except Exception
as e:
981 isPackage = storageType.endswith(
":uno_packages" )
987 log.debug(
"got urlHelper " + str( urlHelper ) )
989 rootUrl =
expandUri( urlHelper.getRootStorageURI() )
990 log.debug( storageType +
" transformed to " + rootUrl )
992 ucbService =
"com.sun.star.ucb.SimpleFileAccess"
993 sfa = ctx.ServiceManager.createInstanceWithContext( ucbService, ctx )
995 log.debug(
"PythonScriptProvider couldn't instantiate " +ucbService)
996 raise RuntimeException(
997 "PythonScriptProvider couldn't instantiate " +ucbService, self)
1002 self.
provCtx.setPackageAttributes( mapPackageName2Path , rootUrl )
1007 except Exception
as e:
1009 log.debug(
"PythonScriptProvider could not be instantiated because of : " + text )
1026 nOpenParenthesis = func_signature.find(
"(" )
1027 if -1 == nOpenParenthesis:
1028 function_name = func_signature
1031 function_name = func_signature[0:nOpenParenthesis]
1032 arg_part = func_signature[nOpenParenthesis+1:len(func_signature)]
1033 nCloseParenthesis = arg_part.find(
")" )
1034 if -1 == nCloseParenthesis:
1035 raise IllegalArgumentException(
"PythonLoader: mismatch parenthesis " + func_signature, self, 0 )
1036 arguments = arg_part[0:nCloseParenthesis].strip()
1040 arguments = tuple([x.strip().strip(
'"')
for x
in arguments.split(
",")])
1041 return function_name, arguments
1045 log.debug(
"getScript " + scriptUri +
" invoked")
1047 storageUri = self.
provCtx.getStorageUrlFromPersistentUrl(
1048 self.
provCtx.uriHelper.getStorageURI(scriptUri) );
1049 log.debug(
"getScript: storageUri = " + storageUri)
1050 fileUri = storageUri[0:storageUri.find(
"$" )]
1051 funcName = storageUri[storageUri.find(
"$" )+1:len(storageUri)]
1055 log.debug(
" getScript : parsed funcname " + str(funcName) )
1056 log.debug(
" getScript : func args " + str(funcArgs) )
1058 mod = self.
provCtx.getModuleByUrl( fileUri )
1059 log.debug(
" got mod " + str(mod) )
1061 func = mod.__dict__[ funcName ]
1063 log.debug(
"got func " + str( func ) )
1068 raise ScriptFrameworkErrorException( text, self, scriptUri, LANGUAGENAME, 0 )
1073 return g_ImplementationHelper.getSupportedServices(g_implName)
1076 return g_ImplementationHelper.supportsService( g_implName, ServiceName )
1082 log.debug(
"getByName called" + str( name ))
1087 log.debug(
"getElementNames called")
1092 log.debug(
"hasByName called " + str( name ))
1094 ret = self.
provCtx.isUrlInPackage( uri )
1095 log.debug(
"hasByName " + uri +
" " +str( ret ) )
1099 log.debug(
"Error in hasByName:" + text )
1103 log.debug(
"removeByName called" + str( name ))
1105 if self.
provCtx.isUrlInPackage( uri ):
1106 self.
provCtx.removePackageByUrl( uri )
1108 log.debug(
"removeByName unknown uri " + str( name ) +
", ignoring" )
1109 raise NoSuchElementException( uri +
"is not in package" , self )
1110 log.debug(
"removeByName called" + str( uri ) +
" successful" )
1113 log.debug(
"insertByName called " + str( name ) +
" " + str( value ))
1116 self.
provCtx.addPackageByUrl( uri )
1119 log.debug(
"insertByName: no python files in " + str( uri ) +
", ignoring" )
1120 raise IllegalArgumentException( uri +
" does not contain .py files", self, 1 )
1121 log.debug(
"insertByName called " + str( uri ) +
" successful" )
1124 log.debug(
"replaceByName called " + str( name ) +
" " + str( value ))
1128 log.debug(
"replaceByName called" + str( uri ) +
" successful" )
1131 log.debug(
"getElementType called" )
1135 log.debug(
"hasElements got called")
1138g_ImplementationHelper.addImplementation( \
1139 PythonScriptProvider,g_implName, \
1140 (
"com.sun.star.script.provider.LanguageScriptProvider",
1141 "com.sun.star.script.provider.ScriptProviderFor"+ LANGUAGENAME,),)
1144log.debug(
"pythonscript finished initializing" )
def getInteractionHandler(self)
def getProgressHandler(self)
def __init__(self, provCtx, name, rootUrl)
def __init__(self, provCtx, uri, name)
def __init__(self, target)
def log(self, level, msg)
def __init__(self, rootUrl)
def startElement(self, name, attlist)
def endElement(self, name)
def setDocumentLocator(self, locator)
def characters(self, chars)
def ignoreableWhitespace(self, chars)
def __init__(self, lastRead, module)
def scriptURI2StorageUri(self, scriptURI)
def __init__(self, ctx, location)
def getStorageURI(self, scriptURI)
def getScriptURI(self, storageURI)
def storageURI2ScriptUri(self, storageURI)
def getRootStorageURI(self)
def __init__(self, provCtx, name, rootUrl)
def __init__(self, paths, transientPathElement)
def getModuleByUrl(self, url)
def getStorageUrlFromPersistentUrl(self, url)
def addPackageByUrl(self, url)
def removePackageByUrl(self, url)
def getPackageNameFromUrl(self, url)
def setPackageAttributes(self, mapPackageName2Path, rootUrl)
def getTransientPartFromUrl(self, url)
def __init__(self, storageType, sfa, uriHelper, scriptContext)
def getFuncsByUrl(self, url)
def isUrlInPackage(self, url)
def getPersistentUrlFromStorageUrl(self, url)
def getImplementationName(self)
def getElementNames(self)
def getScript(self, scriptUri)
def replaceByName(self, name, value)
def insertByName(self, name, value)
def supportsService(self, ServiceName)
def hasByName(self, name)
def getSupportedServices(self)
def __init__(self, ctx, *args)
def getByName(self, name)
def removeByName(self, name)
def getFunctionArguments(self, func_signature)
def invoke(self, args, out, outindex)
def __init__(self, func, mod, args)
def setPropertyValue(self, name, value)
def getIntrospection(self)
def getPropertySetInfo(self)
def __init__(self, provCtx, uri, fileName, funcName)
def getPropertyValue(self, name)
def invoke(self, name, params, outparamindex, outparams)
def actionPerformed(self, event)
def hasProperty(self, name)
def hasMethod(self, name)
def setValue(self, name, value)
def __init__(self, ctx, doc, inv)
def getInvocationContext(self)
def getComponentContext(self)
def getModelFromDocUrl(ctx, url)
def isPyFileInPath(sfa, path)
def hasChanged(oldDate, newDate)
def lastException2String()
def mapStorageType2PackageContext(storageType)
def getPathsFromPackage(rootUrl, sfa)
def getPackageName2PathMap(sfa, storageType)
def ensureSourceState(code)
def checkForPythonPathBesideScript(url)
def readTextFromStream(inputStream)
def penultimateElement(aStr)
def logLevel2String(level)
def absolutize(path, relativeUrl)
def _uno_extract_printable_stacktrace(trace)
def getComponentContext()
def fileUrlToSystemPath(url)
def getTypeByName(typeName)
def fileUrlToSystemPath(url)