home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 July / CMCD0704.ISO / Software / Shareware / Comunicatii / jyte / jyte.exe / pyscript.py < prev    next >
Text File  |  2002-05-30  |  15KB  |  426 lines

  1. """Python ActiveX Scripting Implementation
  2.  
  3. This module implements the Python ActiveX Scripting client.
  4.  
  5. To register the implementation, simply "run" this Python program - ie
  6. either double-click on it, or run "python.exe pyscript.py" from the
  7. command line.
  8. """
  9.  
  10. import framework
  11. import winerror
  12. import win32com
  13. import win32api
  14. import pythoncom
  15. from win32com.axscript import axscript
  16. import win32com.server.register
  17. import sys
  18. import string
  19. import traceback
  20. import scriptdispatch
  21. import re
  22. import win32com.client.dynamic
  23.  
  24. from framework import RaiseAssert, trace, Exception, SCRIPTTEXT_FORCEEXECUTION, SCRIPTTEXT_ISEXPRESSION, SCRIPTTEXT_ISPERSISTENT
  25.  
  26. PyScript_CLSID = "{DF630910-1C1D-11d0-AE36-8C0F5E000000}"
  27.  
  28. debugging_attr = 0
  29.  
  30. def debug_attr_print(*args):
  31.     if debugging_attr:
  32.         apply(trace, args)
  33.  
  34. def ExpandTabs(text):
  35.     return re.sub('\t','    ', text)
  36.  
  37. def AddCR(text):
  38.     return re.sub('\n','\r\n',text)
  39. #    return string.join(string.split(text,'\n'),'\r\n')
  40.  
  41. def RemoveCR(text):
  42. # No longer just "RemoveCR" - should be renamed to
  43. # FixNewlines, or something.  Idea is to fix arbitary newlines into
  44. # something Python can compile...
  45.     return re.sub('(\r\n)|\r|(\n\r)','\n',text)
  46.     
  47. class AXScriptCodeBlock(framework.AXScriptCodeBlock):
  48.     def GetDisplayName(self):
  49.         return "PyScript - " + framework.AXScriptCodeBlock.GetDisplayName(self)
  50.  
  51. #
  52. # Restricted execution model.
  53. #
  54. import rexec
  55. class AXRExec(rexec.RExec):
  56.     ok_builtin_modules = rexec.RExec.ok_builtin_modules + ('win32trace',)
  57.  
  58.     def __init__(self, pretendMain, hooks = None, verbose = 0):
  59.         self.pretendMain = pretendMain
  60.         rexec.RExec.__init__(self, hooks, verbose)
  61. #        mods = list(self.ok_dynamic_modules)
  62. #        mods.append("win32trace")
  63. #        mods = tuple(mods)
  64. #        self.ok_dynamic_modules = mods
  65.     def make_main(self):
  66.         if not self.modules.has_key('__main__'):
  67.             self.modules['__main__'] = self.pretendMain
  68.             self.pretendMain.__builtins__ = self.modules['__builtin__']
  69.             m = self.add_module('__main__')
  70.  
  71. # Classes that looks and behaves like RExec, but isnt really!
  72. import ihooks
  73. class AXNotRHooks(ihooks.Hooks):
  74.     pass
  75.  
  76. class AXNotRExec:
  77.     def __init__(self, pretendMain, hooks = None, verbose = 0):
  78.         self.pretendMain = pretendMain
  79.         self.hooks = hooks or AXNotRHooks(verbose)
  80.         self.modules = {'__main__': self.pretendMain}
  81.  
  82.     def add_module(self, mname):
  83.         if self.modules.has_key(mname):
  84.             return self.modules[mname]
  85.         self.modules[mname] = m = self.hooks.new_module(mname)
  86. #        m.__builtins__ = self.modules['__builtin__']
  87.         return m
  88.  
  89. # There is only ever _one_ ax object - it exists in the global namespace
  90. # for all script items.
  91. # It performs a search from all global/visible objects
  92. # down.
  93. # This means that if 2 sub-objects of the same name are used
  94. # then only one is ever reachable using the ax shortcut.
  95. class AXScriptAttribute:
  96.     "An attribute in a scripts namespace."
  97.     def __init__(self, engine):
  98.         self.__dict__['_scriptEngine_'] = engine
  99.     def __getattr__(self, attr):
  100.         if attr[1]=="_" and attr[:-1]=="_":
  101.             raise AttributeError, attr
  102.         rc = self._FindAttribute_(attr)
  103.         if rc is None:
  104.             raise AttributeError, attr
  105.         return rc
  106.     def _Close_(self):
  107.         self.__dict__['_scriptEngine_'] = None
  108.  
  109.     def _DoFindAttribute_(self, obj, attr):
  110.         try:
  111.             return obj.subItems[string.lower(attr)].attributeObject
  112.         except KeyError:
  113.             pass
  114.         # Check out the sub-items
  115.         for item in obj.subItems.values():
  116.             try:
  117.                 return self._DoFindAttribute_(item, attr)
  118.             except AttributeError:
  119.                 pass
  120.         raise AttributeError, attr
  121.  
  122.     def _FindAttribute_(self, attr):
  123.         for item in self._scriptEngine_.subItems.values():
  124.             try:
  125.                 return self._DoFindAttribute_(item, attr)
  126.             except AttributeError:
  127.                 pass
  128.         # All else fails, see if it is a global
  129.         # (mainly b/w compat)
  130.         return getattr(self._scriptEngine_.globalNameSpaceModule, attr)
  131. #        raise AttributeError, attr
  132.  
  133. class NamedScriptAttribute:
  134.     "An explicitely named object in an objects namespace"
  135.     # Each named object holds a reference to one of these.
  136.     # Whenever a sub-item appears in a namespace, it is really one of these
  137.     # objects.  Has a circular reference back to the item itself, which is
  138.     # closed via _Close_()
  139.     def __init__(self, scriptItem):
  140.         self.__dict__['_scriptItem_'] = scriptItem
  141.     def __repr__(self):
  142.         return "<NamedItemAttribute" + repr(self._scriptItem_) + ">"
  143.     def __getattr__(self, attr):
  144.         # If a known subitem, return it.
  145.         try:
  146.             return self._scriptItem_.subItems[string.lower(attr)].attributeObject
  147.         except KeyError:
  148.             # Otherwise see if the dispatch can give it to us
  149.             if self._scriptItem_.dispatchContainer:
  150.                 return getattr(self._scriptItem_.dispatchContainer,attr)
  151.         raise AttributeError, attr
  152.     def __setattr__(self, attr, value):
  153.         # XXX - todo - if a known item, then should call its default
  154.         # dispatch method.
  155.         attr=string.lower(attr)
  156.         if self._scriptItem_.dispatchContainer:
  157.             try:
  158.                 return setattr(self._scriptItem_.dispatchContainer,attr, value)
  159.             except AttributeError:
  160.                 pass
  161.         raise AttributeError, attr
  162.     def _Close_(self):
  163.         self.__dict__['_scriptItem_'] = None
  164.  
  165.     
  166. class ScriptItem(framework.ScriptItem):
  167.     def __init__(self, parentItem, name, dispatch, flags):
  168.         framework.ScriptItem.__init__(self, parentItem, name, dispatch, flags)
  169.         self.scriptlets = {}
  170.         self.attributeObject = None
  171.     def Reset(self):
  172.         framework.ScriptItem.Reset(self)
  173.         if self.attributeObject:
  174.             self.attributeObject._Close_()
  175.         self.attributeObject = None
  176.     def Close(self):
  177.         framework.ScriptItem.Close(self) # calls reset.
  178.         self.dispatchContainer = None
  179.         self.scriptlets = {}
  180.  
  181.     def Register(self):
  182.         framework.ScriptItem.Register(self)
  183.         self.attributeObject = NamedScriptAttribute(self)
  184.         if self.dispatch:
  185.             # Need to avoid the new Python "lazy" dispatch behaviour.
  186.             try:
  187.                 engine = self.GetEngine()
  188.                 olerepr = clsid = None
  189.                 typeinfo = self.dispatch.GetTypeInfo()
  190.                 clsid = typeinfo.GetTypeAttr()[0]
  191.                 try:
  192.                     olerepr = engine.mapKnownCOMTypes[clsid]
  193.                 except KeyError:
  194.                     pass
  195.             except pythoncom.com_error:
  196.                 typeinfo = None
  197.             if olerepr is None:
  198.                 olerepr = win32com.client.dynamic.MakeOleRepr(self.dispatch, typeinfo, None)
  199.                 if clsid is not None:
  200.                     engine.mapKnownCOMTypes[clsid] = olerepr
  201.             self.dispatchContainer = win32com.client.dynamic.CDispatch(self.dispatch, olerepr, self.name)
  202. #            self.dispatchContainer = win32com.client.dynamic.Dispatch(self.dispatch, userName = self.name)
  203. #            self.dispatchContainer = win32com.client.dynamic.DumbDispatch(self.dispatch, userName = self.name)
  204.  
  205. #    def Connect(self):
  206. #        framework.ScriptItem.Connect(self)
  207. #    def Disconnect(self):
  208. #        framework.ScriptItem.Disconnect(self)
  209.         
  210. class PyScript(framework.COMScript):
  211.     # Setup the auto-registration stuff...
  212.     _reg_verprogid_ = "Python.AXScript.2"
  213.     _reg_progid_ = "Python"
  214. #    _reg_policy_spec_ = default
  215.     _reg_catids_ = [axscript.CATID_ActiveScript,axscript.CATID_ActiveScriptParse]
  216.     _reg_desc_ = "Python ActiveX Scripting Engine"
  217.     _reg_clsid_ = PyScript_CLSID
  218.     _reg_class_spec_ = "win32com.axscript.client.pyscript.PyScript"
  219.     _reg_remove_keys_ = [(".pys",), ("pysFile",)]
  220.     _reg_threading_ = "Apartment"
  221.     
  222.     def __init__(self):
  223.         framework.COMScript.__init__(self)
  224.         self.globalNameSpaceModule = None
  225.         self.codeBlocks = []
  226.         self.scriptDispatch = None
  227.  
  228.     def InitNew(self):
  229.         framework.COMScript.InitNew(self)
  230.         import imp
  231.         self.scriptDispatch = None
  232.         self.globalNameSpaceModule = imp.new_module("__ax_main__")
  233.         self.globalNameSpaceModule.__dict__['ax'] = AXScriptAttribute(self)
  234.         self.rexec_env = None # will be created first time around.
  235.         
  236.         self.codeBlocks = []
  237.         self.persistedCodeBlocks = []
  238.         self.mapKnownCOMTypes = {} # Map of known CLSID to typereprs
  239.         self.codeBlockCounter = 0
  240.  
  241.     def Stop(self):
  242.         # Flag every pending script as already done
  243.         for b in self.codeBlocks:
  244.             b.beenExecuted = 1
  245.         return framework.COMScript.Stop(self)
  246.  
  247.     def Reset(self):
  248.         # Reset all code-blocks that are persistent, and discard the rest
  249.         oldCodeBlocks = self.codeBlocks[:]
  250.         self.codeBlocks = []
  251.         for b in oldCodeBlocks:
  252.             if b.flags & SCRIPTTEXT_ISPERSISTENT:
  253.                 b.beenExecuted = 0
  254.                 self.codeBlocks.append(b)
  255.         return framework.COMScript.Reset(self)
  256.  
  257.     def _GetNextCodeBlockNumber(self):
  258.         self.codeBlockCounter = self.codeBlockCounter + 1
  259.         return self.codeBlockCounter
  260.         
  261.     def RegisterNamedItem(self, item):
  262.         if self.rexec_env is None:
  263.             if self.safetyOptions & (axscript.INTERFACESAFE_FOR_UNTRUSTED_DATA | axscript.INTERFACESAFE_FOR_UNTRUSTED_CALLER):
  264.                 # Use RExec.
  265.                 self.rexec_env = AXRExec(self.globalNameSpaceModule)
  266.             else:
  267.                 # DONT use RExec.
  268.                 self.rexec_env = AXNotRExec(self.globalNameSpaceModule)
  269.  
  270.         wasReg = item.isRegistered
  271.         framework.COMScript.RegisterNamedItem(self, item)
  272.         if not wasReg:
  273.             # Insert into our namespace.
  274.             # Add every item by name
  275.             if item.IsVisible():
  276.                 self.globalNameSpaceModule.__dict__[item.name] = item.attributeObject
  277.             if item.IsGlobal():
  278.                 # Global items means sub-items are also added...
  279.                 for subitem in item.subItems.values():
  280.                     self.globalNameSpaceModule.__dict__[subitem.name] = subitem.attributeObject
  281.                 # Also add all methods
  282.                 for name, entry in item.dispatchContainer._olerepr_.mapFuncs.items():
  283.                     if not entry.hidden:
  284.                         self.globalNameSpaceModule.__dict__[name] = getattr(item.dispatchContainer,name)
  285.  
  286.     def DoExecutePendingScripts(self):
  287.         try:
  288.             globs = self.globalNameSpaceModule.__dict__
  289.             for codeBlock in self.codeBlocks:
  290.                 if not codeBlock.beenExecuted:
  291.                     if self.CompileInScriptedSection(codeBlock, "exec"):
  292.                         self.ExecInScriptedSection(codeBlock, globs)
  293.         finally:
  294.             pass
  295.     
  296.     def DoRun(self):
  297.         pass
  298.  
  299.     def Close(self):
  300.         self.ResetNamespace()
  301.         self.globalNameSpaceModule = None
  302.         self.codeBlocks = []
  303.         self.scriptDispatch = None
  304.         framework.COMScript.Close(self)
  305.  
  306.     def GetScriptDispatch(self, name):
  307. #        trace("GetScriptDispatch with", name)
  308. #        if name is not None: return None
  309.         if self.scriptDispatch is None:
  310.             self.scriptDispatch = scriptdispatch.MakeScriptDispatch(self, self.globalNameSpaceModule)
  311.         return self.scriptDispatch
  312.  
  313.     def MakeEventMethodName(self, subItemName, eventName):
  314.         return string.upper(subItemName[0])+subItemName[1:] + "_" + string.upper(eventName[0])+eventName[1:]
  315.  
  316.     def DoAddScriptlet(self, defaultName, code, itemName, subItemName, eventName, delimiter,sourceContextCookie, startLineNumber):
  317.         # Just store the code away - compile when called.  (JIT :-)
  318.         item = self.GetNamedItem(itemName)
  319.         if itemName==subItemName: # Explicit handlers - eg <SCRIPT LANGUAGE="Python" for="TestForm" Event="onSubmit">
  320.             subItem = item
  321.         else:
  322.             subItem = item.GetCreateSubItem(item, subItemName, None, None)
  323.         funcName = self.MakeEventMethodName(subItemName, eventName)
  324.         
  325.         codeBlock = AXScriptCodeBlock("Script Event %s" %funcName, code, sourceContextCookie, startLineNumber, 0)
  326.         self._AddScriptCodeBlock(codeBlock)
  327.         subItem.scriptlets[funcName] = codeBlock
  328.  
  329.     def DoProcessScriptItemEvent(self, item, event, lcid, wFlags, args):
  330. #        trace("ScriptItemEvent", self, item, event, event.name, lcid, wFlags, args)
  331.         funcName = self.MakeEventMethodName(item.name, event.name)
  332.         codeBlock = function = None
  333.         try:
  334.             function = item.scriptlets[funcName]
  335.             if type(function)==type(self): # ie, is a CodeBlock instance
  336.                 codeBlock = function
  337.                 function = None
  338.         except KeyError:
  339.             pass
  340.         if codeBlock is not None:
  341.             realCode = "def %s():\n" % funcName
  342.             for line in string.split(RemoveCR(codeBlock.codeText),"\n"):
  343.                 realCode = realCode + '\t' + line + '\n'
  344.             realCode = realCode + '\n'
  345.             if not self.CompileInScriptedSection(codeBlock, "exec", realCode):
  346.                 return
  347.             dict = {}
  348.             self.ExecInScriptedSection(codeBlock, self.globalNameSpaceModule.__dict__, dict)
  349.             function = dict[funcName]
  350.             # cache back in scriptlets as a function.
  351.             item.scriptlets[funcName] = function
  352.         if function is None:
  353.             # still no function - see if in the global namespace.
  354.             try:
  355.                 function = self.globalNameSpaceModule.__dict__[funcName]
  356.             except KeyError:
  357.                 # Not there _exactly_ - do case ins search.
  358.                 funcNameLook = string.lower(funcName)
  359.                 for attr in self.globalNameSpaceModule.__dict__.keys():
  360.                     if funcNameLook==string.lower(attr):
  361.                         function = self.globalNameSpaceModule.__dict__[attr]
  362.                         # cache back in scriptlets, to avoid this overhead next time
  363.                         item.scriptlets[funcName] = function
  364.  
  365.         if function is None:
  366.             raise Exception(scode=winerror.DISP_E_MEMBERNOTFOUND)
  367.         return self.ApplyInScriptedSection(codeBlock, function, args)
  368.  
  369.     def DoParseScriptText(self, code, sourceContextCookie, startLineNumber, bWantResult, flags):
  370.         code = RemoveCR(code) + "\n"
  371.         if flags & SCRIPTTEXT_ISEXPRESSION:
  372.             name = "Script Expression"
  373.             exec_type = "eval"
  374.         else:
  375.             name = "Script Block"
  376.             exec_type = "exec"
  377.         num = self._GetNextCodeBlockNumber()
  378.         if num==1: num=""
  379.         name = "%s %s" % (name, num)
  380.         codeBlock = AXScriptCodeBlock(name, code, sourceContextCookie, startLineNumber, flags)
  381.         self._AddScriptCodeBlock(codeBlock)
  382.         globs = self.globalNameSpaceModule.__dict__
  383.         if bWantResult: # always immediate.
  384.             if self.CompileInScriptedSection(codeBlock, exec_type):
  385.                 if flags & SCRIPTTEXT_ISEXPRESSION:
  386.                     return self.EvalInScriptedSection(codeBlock, globs)
  387.                 else:
  388.                     return self.ExecInScriptedSection(codeBlock, globs)
  389.                 
  390.             # else compile failed, but user chose to keep running...
  391.         else:
  392.             if flags & SCRIPTTEXT_FORCEEXECUTION:
  393.                 if self.CompileInScriptedSection(codeBlock, exec_type):
  394.                     self.ExecInScriptedSection(codeBlock, globs)
  395.             else:
  396.                 self.codeBlocks.append(codeBlock)
  397.  
  398.     def GetNamedItemClass(self):
  399.         return ScriptItem
  400.  
  401.     def ResetNamespace(self):
  402.         if self.globalNameSpaceModule is not None:
  403.             try:
  404.                 self.globalNameSpaceModule.ax._Reset_()
  405.             except AttributeError:
  406.                 pass # ???
  407.             globalNameSpaceModule = None
  408.             
  409.         self.rexec_env = None
  410.         
  411.  
  412. def Register(klass=PyScript):
  413.     import sys
  414.     ret = win32com.server.register.UseCommandLine(klass)
  415.     if '--unregister' not in sys.argv and \
  416.        '--unregister_info' not in sys.argv:
  417.         # If we are registering, do our extra stuff.
  418.         win32com.server.register._set_subkeys(klass._reg_progid_ + "\\OLEScript", {}) # Just a CreateKey
  419.         # Basic Registration for wsh.
  420.         win32com.server.register._set_string(".pys", "pysFile")
  421.         win32com.server.register._set_string("pysFile\\ScriptEngine", klass._reg_progid_)
  422.         print "Registration of %s complete." % (klass._reg_desc_,)
  423.     return ret
  424.     
  425. if __name__=='__main__':
  426.     Register()