home *** CD-ROM | disk | FTP | other *** search
- """Python ActiveX Scripting Implementation
-
- This module implements the Python ActiveX Scripting client.
-
- To register the implementation, simply "run" this Python program - ie
- either double-click on it, or run "python.exe pyscript.py" from the
- command line.
- """
-
- import framework
- import winerror
- import win32com
- import win32api
- import pythoncom
- from win32com.axscript import axscript
- import win32com.server.register
- import sys
- import string
- import traceback
- import scriptdispatch
- import re
- import win32com.client.dynamic
-
- from framework import RaiseAssert, trace, Exception, SCRIPTTEXT_FORCEEXECUTION, SCRIPTTEXT_ISEXPRESSION, SCRIPTTEXT_ISPERSISTENT
-
- PyScript_CLSID = "{DF630910-1C1D-11d0-AE36-8C0F5E000000}"
-
- debugging_attr = 0
-
- def debug_attr_print(*args):
- if debugging_attr:
- apply(trace, args)
-
- def ExpandTabs(text):
- return re.sub('\t',' ', text)
-
- def AddCR(text):
- return re.sub('\n','\r\n',text)
- # return string.join(string.split(text,'\n'),'\r\n')
-
- def RemoveCR(text):
- # No longer just "RemoveCR" - should be renamed to
- # FixNewlines, or something. Idea is to fix arbitary newlines into
- # something Python can compile...
- return re.sub('(\r\n)|\r|(\n\r)','\n',text)
-
- class AXScriptCodeBlock(framework.AXScriptCodeBlock):
- def GetDisplayName(self):
- return "PyScript - " + framework.AXScriptCodeBlock.GetDisplayName(self)
-
- #
- # Restricted execution model.
- #
- import rexec
- class AXRExec(rexec.RExec):
- ok_builtin_modules = rexec.RExec.ok_builtin_modules + ('win32trace',)
-
- def __init__(self, pretendMain, hooks = None, verbose = 0):
- self.pretendMain = pretendMain
- rexec.RExec.__init__(self, hooks, verbose)
- # mods = list(self.ok_dynamic_modules)
- # mods.append("win32trace")
- # mods = tuple(mods)
- # self.ok_dynamic_modules = mods
- def make_main(self):
- if not self.modules.has_key('__main__'):
- self.modules['__main__'] = self.pretendMain
- self.pretendMain.__builtins__ = self.modules['__builtin__']
- m = self.add_module('__main__')
-
- # Classes that looks and behaves like RExec, but isnt really!
- import ihooks
- class AXNotRHooks(ihooks.Hooks):
- pass
-
- class AXNotRExec:
- def __init__(self, pretendMain, hooks = None, verbose = 0):
- self.pretendMain = pretendMain
- self.hooks = hooks or AXNotRHooks(verbose)
- self.modules = {'__main__': self.pretendMain}
-
- def add_module(self, mname):
- if self.modules.has_key(mname):
- return self.modules[mname]
- self.modules[mname] = m = self.hooks.new_module(mname)
- # m.__builtins__ = self.modules['__builtin__']
- return m
-
- # There is only ever _one_ ax object - it exists in the global namespace
- # for all script items.
- # It performs a search from all global/visible objects
- # down.
- # This means that if 2 sub-objects of the same name are used
- # then only one is ever reachable using the ax shortcut.
- class AXScriptAttribute:
- "An attribute in a scripts namespace."
- def __init__(self, engine):
- self.__dict__['_scriptEngine_'] = engine
- def __getattr__(self, attr):
- if attr[1]=="_" and attr[:-1]=="_":
- raise AttributeError, attr
- rc = self._FindAttribute_(attr)
- if rc is None:
- raise AttributeError, attr
- return rc
- def _Close_(self):
- self.__dict__['_scriptEngine_'] = None
-
- def _DoFindAttribute_(self, obj, attr):
- try:
- return obj.subItems[string.lower(attr)].attributeObject
- except KeyError:
- pass
- # Check out the sub-items
- for item in obj.subItems.values():
- try:
- return self._DoFindAttribute_(item, attr)
- except AttributeError:
- pass
- raise AttributeError, attr
-
- def _FindAttribute_(self, attr):
- for item in self._scriptEngine_.subItems.values():
- try:
- return self._DoFindAttribute_(item, attr)
- except AttributeError:
- pass
- # All else fails, see if it is a global
- # (mainly b/w compat)
- return getattr(self._scriptEngine_.globalNameSpaceModule, attr)
- # raise AttributeError, attr
-
- class NamedScriptAttribute:
- "An explicitely named object in an objects namespace"
- # Each named object holds a reference to one of these.
- # Whenever a sub-item appears in a namespace, it is really one of these
- # objects. Has a circular reference back to the item itself, which is
- # closed via _Close_()
- def __init__(self, scriptItem):
- self.__dict__['_scriptItem_'] = scriptItem
- def __repr__(self):
- return "<NamedItemAttribute" + repr(self._scriptItem_) + ">"
- def __getattr__(self, attr):
- # If a known subitem, return it.
- try:
- return self._scriptItem_.subItems[string.lower(attr)].attributeObject
- except KeyError:
- # Otherwise see if the dispatch can give it to us
- if self._scriptItem_.dispatchContainer:
- return getattr(self._scriptItem_.dispatchContainer,attr)
- raise AttributeError, attr
- def __setattr__(self, attr, value):
- # XXX - todo - if a known item, then should call its default
- # dispatch method.
- attr=string.lower(attr)
- if self._scriptItem_.dispatchContainer:
- try:
- return setattr(self._scriptItem_.dispatchContainer,attr, value)
- except AttributeError:
- pass
- raise AttributeError, attr
- def _Close_(self):
- self.__dict__['_scriptItem_'] = None
-
-
- class ScriptItem(framework.ScriptItem):
- def __init__(self, parentItem, name, dispatch, flags):
- framework.ScriptItem.__init__(self, parentItem, name, dispatch, flags)
- self.scriptlets = {}
- self.attributeObject = None
- def Reset(self):
- framework.ScriptItem.Reset(self)
- if self.attributeObject:
- self.attributeObject._Close_()
- self.attributeObject = None
- def Close(self):
- framework.ScriptItem.Close(self) # calls reset.
- self.dispatchContainer = None
- self.scriptlets = {}
-
- def Register(self):
- framework.ScriptItem.Register(self)
- self.attributeObject = NamedScriptAttribute(self)
- if self.dispatch:
- # Need to avoid the new Python "lazy" dispatch behaviour.
- try:
- engine = self.GetEngine()
- olerepr = clsid = None
- typeinfo = self.dispatch.GetTypeInfo()
- clsid = typeinfo.GetTypeAttr()[0]
- try:
- olerepr = engine.mapKnownCOMTypes[clsid]
- except KeyError:
- pass
- except pythoncom.com_error:
- typeinfo = None
- if olerepr is None:
- olerepr = win32com.client.dynamic.MakeOleRepr(self.dispatch, typeinfo, None)
- if clsid is not None:
- engine.mapKnownCOMTypes[clsid] = olerepr
- self.dispatchContainer = win32com.client.dynamic.CDispatch(self.dispatch, olerepr, self.name)
- # self.dispatchContainer = win32com.client.dynamic.Dispatch(self.dispatch, userName = self.name)
- # self.dispatchContainer = win32com.client.dynamic.DumbDispatch(self.dispatch, userName = self.name)
-
- # def Connect(self):
- # framework.ScriptItem.Connect(self)
- # def Disconnect(self):
- # framework.ScriptItem.Disconnect(self)
-
- class PyScript(framework.COMScript):
- # Setup the auto-registration stuff...
- _reg_verprogid_ = "Python.AXScript.2"
- _reg_progid_ = "Python"
- # _reg_policy_spec_ = default
- _reg_catids_ = [axscript.CATID_ActiveScript,axscript.CATID_ActiveScriptParse]
- _reg_desc_ = "Python ActiveX Scripting Engine"
- _reg_clsid_ = PyScript_CLSID
- _reg_class_spec_ = "win32com.axscript.client.pyscript.PyScript"
- _reg_remove_keys_ = [(".pys",), ("pysFile",)]
- _reg_threading_ = "Apartment"
-
- def __init__(self):
- framework.COMScript.__init__(self)
- self.globalNameSpaceModule = None
- self.codeBlocks = []
- self.scriptDispatch = None
-
- def InitNew(self):
- framework.COMScript.InitNew(self)
- import imp
- self.scriptDispatch = None
- self.globalNameSpaceModule = imp.new_module("__ax_main__")
- self.globalNameSpaceModule.__dict__['ax'] = AXScriptAttribute(self)
- self.rexec_env = None # will be created first time around.
-
- self.codeBlocks = []
- self.persistedCodeBlocks = []
- self.mapKnownCOMTypes = {} # Map of known CLSID to typereprs
- self.codeBlockCounter = 0
-
- def Stop(self):
- # Flag every pending script as already done
- for b in self.codeBlocks:
- b.beenExecuted = 1
- return framework.COMScript.Stop(self)
-
- def Reset(self):
- # Reset all code-blocks that are persistent, and discard the rest
- oldCodeBlocks = self.codeBlocks[:]
- self.codeBlocks = []
- for b in oldCodeBlocks:
- if b.flags & SCRIPTTEXT_ISPERSISTENT:
- b.beenExecuted = 0
- self.codeBlocks.append(b)
- return framework.COMScript.Reset(self)
-
- def _GetNextCodeBlockNumber(self):
- self.codeBlockCounter = self.codeBlockCounter + 1
- return self.codeBlockCounter
-
- def RegisterNamedItem(self, item):
- if self.rexec_env is None:
- if self.safetyOptions & (axscript.INTERFACESAFE_FOR_UNTRUSTED_DATA | axscript.INTERFACESAFE_FOR_UNTRUSTED_CALLER):
- # Use RExec.
- self.rexec_env = AXRExec(self.globalNameSpaceModule)
- else:
- # DONT use RExec.
- self.rexec_env = AXNotRExec(self.globalNameSpaceModule)
-
- wasReg = item.isRegistered
- framework.COMScript.RegisterNamedItem(self, item)
- if not wasReg:
- # Insert into our namespace.
- # Add every item by name
- if item.IsVisible():
- self.globalNameSpaceModule.__dict__[item.name] = item.attributeObject
- if item.IsGlobal():
- # Global items means sub-items are also added...
- for subitem in item.subItems.values():
- self.globalNameSpaceModule.__dict__[subitem.name] = subitem.attributeObject
- # Also add all methods
- for name, entry in item.dispatchContainer._olerepr_.mapFuncs.items():
- if not entry.hidden:
- self.globalNameSpaceModule.__dict__[name] = getattr(item.dispatchContainer,name)
-
- def DoExecutePendingScripts(self):
- try:
- globs = self.globalNameSpaceModule.__dict__
- for codeBlock in self.codeBlocks:
- if not codeBlock.beenExecuted:
- if self.CompileInScriptedSection(codeBlock, "exec"):
- self.ExecInScriptedSection(codeBlock, globs)
- finally:
- pass
-
- def DoRun(self):
- pass
-
- def Close(self):
- self.ResetNamespace()
- self.globalNameSpaceModule = None
- self.codeBlocks = []
- self.scriptDispatch = None
- framework.COMScript.Close(self)
-
- def GetScriptDispatch(self, name):
- # trace("GetScriptDispatch with", name)
- # if name is not None: return None
- if self.scriptDispatch is None:
- self.scriptDispatch = scriptdispatch.MakeScriptDispatch(self, self.globalNameSpaceModule)
- return self.scriptDispatch
-
- def MakeEventMethodName(self, subItemName, eventName):
- return string.upper(subItemName[0])+subItemName[1:] + "_" + string.upper(eventName[0])+eventName[1:]
-
- def DoAddScriptlet(self, defaultName, code, itemName, subItemName, eventName, delimiter,sourceContextCookie, startLineNumber):
- # Just store the code away - compile when called. (JIT :-)
- item = self.GetNamedItem(itemName)
- if itemName==subItemName: # Explicit handlers - eg <SCRIPT LANGUAGE="Python" for="TestForm" Event="onSubmit">
- subItem = item
- else:
- subItem = item.GetCreateSubItem(item, subItemName, None, None)
- funcName = self.MakeEventMethodName(subItemName, eventName)
-
- codeBlock = AXScriptCodeBlock("Script Event %s" %funcName, code, sourceContextCookie, startLineNumber, 0)
- self._AddScriptCodeBlock(codeBlock)
- subItem.scriptlets[funcName] = codeBlock
-
- def DoProcessScriptItemEvent(self, item, event, lcid, wFlags, args):
- # trace("ScriptItemEvent", self, item, event, event.name, lcid, wFlags, args)
- funcName = self.MakeEventMethodName(item.name, event.name)
- codeBlock = function = None
- try:
- function = item.scriptlets[funcName]
- if type(function)==type(self): # ie, is a CodeBlock instance
- codeBlock = function
- function = None
- except KeyError:
- pass
- if codeBlock is not None:
- realCode = "def %s():\n" % funcName
- for line in string.split(RemoveCR(codeBlock.codeText),"\n"):
- realCode = realCode + '\t' + line + '\n'
- realCode = realCode + '\n'
- if not self.CompileInScriptedSection(codeBlock, "exec", realCode):
- return
- dict = {}
- self.ExecInScriptedSection(codeBlock, self.globalNameSpaceModule.__dict__, dict)
- function = dict[funcName]
- # cache back in scriptlets as a function.
- item.scriptlets[funcName] = function
- if function is None:
- # still no function - see if in the global namespace.
- try:
- function = self.globalNameSpaceModule.__dict__[funcName]
- except KeyError:
- # Not there _exactly_ - do case ins search.
- funcNameLook = string.lower(funcName)
- for attr in self.globalNameSpaceModule.__dict__.keys():
- if funcNameLook==string.lower(attr):
- function = self.globalNameSpaceModule.__dict__[attr]
- # cache back in scriptlets, to avoid this overhead next time
- item.scriptlets[funcName] = function
-
- if function is None:
- raise Exception(scode=winerror.DISP_E_MEMBERNOTFOUND)
- return self.ApplyInScriptedSection(codeBlock, function, args)
-
- def DoParseScriptText(self, code, sourceContextCookie, startLineNumber, bWantResult, flags):
- code = RemoveCR(code) + "\n"
- if flags & SCRIPTTEXT_ISEXPRESSION:
- name = "Script Expression"
- exec_type = "eval"
- else:
- name = "Script Block"
- exec_type = "exec"
- num = self._GetNextCodeBlockNumber()
- if num==1: num=""
- name = "%s %s" % (name, num)
- codeBlock = AXScriptCodeBlock(name, code, sourceContextCookie, startLineNumber, flags)
- self._AddScriptCodeBlock(codeBlock)
- globs = self.globalNameSpaceModule.__dict__
- if bWantResult: # always immediate.
- if self.CompileInScriptedSection(codeBlock, exec_type):
- if flags & SCRIPTTEXT_ISEXPRESSION:
- return self.EvalInScriptedSection(codeBlock, globs)
- else:
- return self.ExecInScriptedSection(codeBlock, globs)
-
- # else compile failed, but user chose to keep running...
- else:
- if flags & SCRIPTTEXT_FORCEEXECUTION:
- if self.CompileInScriptedSection(codeBlock, exec_type):
- self.ExecInScriptedSection(codeBlock, globs)
- else:
- self.codeBlocks.append(codeBlock)
-
- def GetNamedItemClass(self):
- return ScriptItem
-
- def ResetNamespace(self):
- if self.globalNameSpaceModule is not None:
- try:
- self.globalNameSpaceModule.ax._Reset_()
- except AttributeError:
- pass # ???
- globalNameSpaceModule = None
-
- self.rexec_env = None
-
-
- def Register(klass=PyScript):
- import sys
- ret = win32com.server.register.UseCommandLine(klass)
- if '--unregister' not in sys.argv and \
- '--unregister_info' not in sys.argv:
- # If we are registering, do our extra stuff.
- win32com.server.register._set_subkeys(klass._reg_progid_ + "\\OLEScript", {}) # Just a CreateKey
- # Basic Registration for wsh.
- win32com.server.register._set_string(".pys", "pysFile")
- win32com.server.register._set_string("pysFile\\ScriptEngine", klass._reg_progid_)
- print "Registration of %s complete." % (klass._reg_desc_,)
- return ret
-
- if __name__=='__main__':
- Register()