pythonloader.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. # -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*-
  2. #
  3. # This file is part of the LibreOffice project.
  4. #
  5. # This Source Code Form is subject to the terms of the Mozilla Public
  6. # License, v. 2.0. If a copy of the MPL was not distributed with this
  7. # file, You can obtain one at http://mozilla.org/MPL/2.0/.
  8. #
  9. # This file incorporates work covered by the following license notice:
  10. #
  11. # Licensed to the Apache Software Foundation (ASF) under one or more
  12. # contributor license agreements. See the NOTICE file distributed
  13. # with this work for additional information regarding copyright
  14. # ownership. The ASF licenses this file to you under the Apache
  15. # License, Version 2.0 (the "License"); you may not use this file
  16. # except in compliance with the License. You may obtain a copy of
  17. # the License at http://www.apache.org/licenses/LICENSE-2.0 .
  18. #
  19. import uno
  20. import unohelper
  21. import sys
  22. import types
  23. import os
  24. from urllib.parse import unquote
  25. from com.sun.star.uno import Exception,RuntimeException
  26. from com.sun.star.loader import XImplementationLoader
  27. from com.sun.star.lang import XServiceInfo
  28. MODULE_PROTOCOL = "vnd.openoffice.pymodule:"
  29. DEBUG = 0
  30. g_supportedServices = "com.sun.star.loader.Python", # referenced by the native C++ loader !
  31. g_implementationName = "org.openoffice.comp.pyuno.Loader" # referenced by the native C++ loader !
  32. def splitUrl( url ):
  33. nColon = url.find( ":" )
  34. if -1 == nColon:
  35. raise RuntimeException( "PythonLoader: No protocol in url " + url, None )
  36. return url[0:nColon], url[nColon+1:len(url)]
  37. g_loadedComponents = {}
  38. def checkForPythonPathBesideComponent( url ):
  39. path = unohelper.fileUrlToSystemPath( url+"/pythonpath.zip" );
  40. if DEBUG == 1:
  41. print(b"checking for existence of " + encfile( path ))
  42. if 1 == os.access( encfile( path ), os.F_OK) and not path in sys.path:
  43. if DEBUG == 1:
  44. print(b"adding " + encfile( path ) + b" to sys.path")
  45. sys.path.append( path )
  46. path = unohelper.fileUrlToSystemPath( url+"/pythonpath" );
  47. if 1 == os.access( encfile( path ), os.F_OK) and not path in sys.path:
  48. if DEBUG == 1:
  49. print(b"adding " + encfile( path ) + b" to sys.path")
  50. sys.path.append( path )
  51. def encfile(uni):
  52. return uni.encode( sys.getfilesystemencoding())
  53. class Loader( XImplementationLoader, XServiceInfo, unohelper.Base ):
  54. def __init__(self, ctx ):
  55. if DEBUG:
  56. print("pythonloader.Loader ctor")
  57. self.ctx = ctx
  58. def getModuleFromUrl( self, url ):
  59. if DEBUG:
  60. print("pythonloader: interpreting url " + url)
  61. protocol, dependent = splitUrl( url )
  62. if "vnd.sun.star.expand" == protocol:
  63. exp = self.ctx.getValueByName( "/singletons/com.sun.star.util.theMacroExpander" )
  64. url = exp.expandMacros(unquote(dependent))
  65. protocol,dependent = splitUrl( url )
  66. if DEBUG:
  67. print("pythonloader: after expansion " + protocol + ":" + dependent)
  68. try:
  69. if "file" == protocol:
  70. # remove \..\ sequence, which may be useful e.g. in the build env
  71. url = unohelper.absolutize( url, url )
  72. # did we load the module already ?
  73. mod = g_loadedComponents.get( url )
  74. if not mod:
  75. mod = types.ModuleType("uno_component")
  76. # check for pythonpath.zip beside .py files
  77. checkForPythonPathBesideComponent( url[0:url.rfind('/')] )
  78. # read the file
  79. filename = unohelper.fileUrlToSystemPath( url )
  80. with open( filename, encoding='utf_8' ) as fileHandle:
  81. src = fileHandle.read().replace("\r","")
  82. if not src.endswith( "\n" ):
  83. src = src + "\n"
  84. # compile and execute the module
  85. codeobject = compile( src, encfile(filename), "exec" )
  86. mod.__file__ = filename
  87. exec(codeobject, mod.__dict__)
  88. g_loadedComponents[url] = mod
  89. return mod
  90. elif "vnd.openoffice.pymodule" == protocol:
  91. nSlash = dependent.rfind('/')
  92. if -1 != nSlash:
  93. path = unohelper.fileUrlToSystemPath( dependent[0:nSlash] )
  94. dependent = dependent[nSlash+1:len(dependent)]
  95. if not path in sys.path:
  96. sys.path.append( path )
  97. mod = __import__( dependent )
  98. path_component, dot, rest = dependent.partition('.')
  99. while dot == '.':
  100. path_component, dot, rest = rest.partition('.')
  101. mod = getattr(mod, path_component)
  102. return mod
  103. else:
  104. if DEBUG:
  105. print("Unknown protocol '" + protocol + "'");
  106. raise RuntimeException( "PythonLoader: Unknown protocol " +
  107. protocol + " in url " +url, self )
  108. except Exception as e:
  109. if DEBUG:
  110. print ("Python import exception " + str(type(e)) +
  111. " message " + str(e) + " args " + str(e.args));
  112. raise RuntimeException( "Couldn't load " + url + " for reason " + str(e), None )
  113. return None
  114. def activate( self, implementationName, dummy, locationUrl, regKey ):
  115. if DEBUG:
  116. print("pythonloader.Loader.activate")
  117. mod = self.getModuleFromUrl( locationUrl )
  118. implHelper = mod.__dict__.get( "g_ImplementationHelper" , None )
  119. if DEBUG:
  120. print ("Fetched ImplHelper as " + str(implHelper))
  121. if implHelper is None:
  122. return mod.getComponentFactory( implementationName, self.ctx.ServiceManager, regKey )
  123. else:
  124. return implHelper.getComponentFactory( implementationName,regKey,self.ctx.ServiceManager)
  125. def writeRegistryInfo( self, regKey, dummy, locationUrl ):
  126. if DEBUG:
  127. print( "pythonloader.Loader.writeRegistryInfo" )
  128. mod = self.getModuleFromUrl( locationUrl )
  129. implHelper = mod.__dict__.get( "g_ImplementationHelper" , None )
  130. if implHelper is None:
  131. return mod.writeRegistryInfo( self.ctx.ServiceManager, regKey )
  132. else:
  133. return implHelper.writeRegistryInfo( regKey, self.ctx.ServiceManager )
  134. def getImplementationName( self ):
  135. return g_implementationName
  136. def supportsService( self, ServiceName ):
  137. return ServiceName in self.getSupportedServiceNames()
  138. def getSupportedServiceNames( self ):
  139. return g_supportedServices
  140. # vim: set shiftwidth=4 softtabstop=4 expandtab: