home *** CD-ROM | disk | FTP | other *** search
/ c't freeware shareware 1997 / CT_SW_97.ISO / mac / Software / entwickl / win95 / pythowin.exe / DATA.4 / AXScript / pyaximpl.py next >
Text File  |  1997-01-14  |  15KB  |  423 lines

  1. # pyaximpl - Implementation
  2.  
  3. import sys, string, traceback # Need these Python lib as minimum.
  4. import rexec   # Restricted execution module.
  5.  
  6. import ni
  7.  
  8. #import win32com.client.dynamic
  9. #pythoncom = win32com.pythoncom
  10. # I cant make the above work.  By the time I come to use it
  11. # down below, "win32com" has transformed into "win32com.client.dynamic"??
  12. from win32com.client import dynamic
  13. from win32com import pythoncom
  14.  
  15. # Ideally, should be "axscript.", but Im not too worried about these, 
  16. # as this implementation may be removed.
  17. INTERFACESAFE_FOR_UNTRUSTED_CALLER =     0x00000001    # Caller of interface may be untrusted
  18. INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002    # Data passed into interface may be untrusted
  19.  
  20.  
  21. debugging=0            # General debugging
  22. debugging_attr=0    # Debugging dynamic attribute lookups.
  23. debugging_reset=0    # Debugging Reset and cleanup of objects.
  24.  
  25. def debug_print(*args):
  26.     if debugging:
  27.         for arg in args:
  28.             print arg,
  29.         print
  30. def debug_reset_print(*args):
  31.     if debugging_reset:
  32.         for arg in args:
  33.             print arg,
  34.         print
  35.  
  36. def debug_attr_print(*args):
  37.     if debugging_attr:
  38.         for arg in args:
  39.             print arg,
  40.         print
  41.  
  42. def FormatForAX(text):
  43.     return ExpandTabs(AddCR(text))
  44.  
  45. def ExpandTabs(text):
  46.     import regsub
  47.     return regsub.gsub('\t','    ', text)
  48.  
  49. def AddCR(text):
  50.     import regsub
  51.     return regsub.gsub('\n','\r\n',text)
  52. #    return string.join(string.split(text,'\n'),'\r\n')
  53.  
  54. def RemoveCR(text):
  55.     import regsub
  56.     return regsub.gsub('\r\n','\n',text)
  57.  
  58. class AXScriptException:
  59.     def __init__(self, type = None, value = None, tb = None):
  60.         if type is None:
  61.             type, value, tb = sys.exc_type, sys.exc_value, sys.exc_traceback
  62.         try:
  63.             import linecache
  64.             linecache.clearcache() # while debugging.
  65.         except:
  66.             pass
  67.         self.source = "Python ActiveX Scripting Engine"
  68.         try:
  69.             if type is SyntaxError:
  70.                 try:
  71.                     msg, (filename, lineno, offset, line) = value
  72.                 except:
  73.                     msg = "Unknown"
  74.                     lineno = 0
  75.                     offset = -1
  76.                     line = "Unknown"
  77.                 self.description=FormatForAX(msg)
  78.                 self.lineno = lineno
  79.                 self.colno = offset
  80.                 self.linetext = ExpandTabs(line)
  81.             else:
  82.                 if debugging: # Full traceback if debugging.
  83.                     list=traceback.format_exception(type, value, tb)
  84.                     self.description = ExpandTabs(string.join(list,""))
  85.                     return
  86.                 # Run down the traceback list, looking for the first "<AX..>"
  87.                 # Hide traceback above this.  In addition, keep going down
  88.                 # looking for a "_*_" attribute, and below hide these also.
  89.                 hide_names = ["r_import","r_reload","r_open"] # hide from these functions down in the traceback.
  90.                 depth = None
  91.                 tb_top = tb
  92.                 while tb_top:
  93.                     filename, lineno, name, line = self.ExtractTracebackInfo(tb_top)
  94.                     if filename[:3]=="<AX":
  95.                         break
  96.                     tb_top = tb_top.tb_next
  97.                 if tb_top: # found one.
  98.                     depth = 0
  99.                     tb_look = tb_top
  100.                     # Look down for _*_
  101.                     while tb_look:
  102.                         filename, lineno, name, line = self.ExtractTracebackInfo(tb_look)
  103.                         if (name[0]=='_' and name[-1]=='_') or name in hide_names:
  104.                             break
  105.                         depth = depth + 1
  106.                         tb_look = tb_look.tb_next
  107.                 else:
  108.                     depth = None
  109.                     tb_top = tb
  110.                 list=traceback.format_exception(type, value, tb_top, depth)
  111.                 self.description = ExpandTabs(string.join(list,""))
  112.                 # Clear tracebacks etc.
  113.                 tb = tb_top = tb_look = None
  114.                 sys.exc_type = sys.exc_value = sys.exc_traceback = None
  115.         except:
  116.             traceback.print_exc()
  117.             # re-raise.
  118.             raise sys.exc_type, sys.exc_value, sys.exc_traceback
  119.     def ExtractTracebackInfo(self, tb):
  120.         import linecache
  121.         f = tb.tb_frame
  122.         lineno = tb.tb_lineno
  123.         co = f.f_code
  124.         filename = co.co_filename
  125.         name = co.co_name
  126.         line = linecache.getline(filename, lineno)
  127.         if line: line = string.strip(line)
  128.         else: line = None
  129.         return filename, lineno, name, line
  130.     def __repr__(self):
  131.         return "AXScriptException:" + self.description
  132.  
  133. class AXAttributeContainer:
  134.     "Provides the 'ax' attribute - does the module level lookup of attributes"
  135.     def __init__(self):
  136.         self.__dict__['_globalmodule_'] = None
  137.         self.__dict__['_localmodule_'] = None
  138.         self.__dict__['_defaultdispatch_'] = None
  139.     def __del__(self):
  140.         debug_reset_print(self, "dieing")
  141.     def __getattr__(self, attr):
  142.         if attr[0]=='_' and attr[-1]=='_':
  143.             raise AttributeError, attr
  144.         debug_attr_print("GetAttr called for '%s' on %s" % (attr,`self`))
  145.         if self._defaultdispatch_:
  146.             try:
  147.                 return getattr(self._defaultdispatch_,attr)
  148.             except AttributeError:
  149.                 pass
  150.         if self._localmodule_:
  151.             try:
  152.                 return self._localmodule_.FindAttribute(attr)
  153.             except AttributeError:
  154.                 pass
  155.         if self._globalmodule_:
  156.             try:
  157.                 return self._globalmodule_.FindAttribute(attr)
  158.             except AttributeError:
  159.                 pass
  160.         debug_attr_print("AXAttributeContainer raising attribute error on ", attr)
  161.         raise AttributeError, attr
  162.     def __setattr__(self, attr, value):
  163.         if attr[0]=='_' and attr[-1]=='_':
  164.             # inject directly
  165.             self.__dict__[attr] = value
  166.         debug_attr_print("SetAttr called for '%s=%s' on %s" % (attr,`value`,`self`))
  167.         if self._defaultdispatch_:
  168.             try:
  169.                 debug_attr_print("Trying DefaultDispatch")
  170.                 return setattr(self._defaultdispatch_,attr, value)
  171.             except AttributeError:
  172.                 pass
  173.         if self._localmodule_:
  174.             try:
  175.                 debug_attr_print("Trying LocalModule")
  176.                 return self._localmodule_.FindSetAttribute(attr, value)
  177.             except AttributeError:
  178.                 pass
  179.         if self._globalmodule_:
  180.             try:
  181.                 debug_attr_print("Trying GlobalModule")
  182.                 return self._globalmodule_.FindSetAttribute(attr, value)
  183.             except AttributeError:
  184.                 pass
  185.         # Dont allow setting of unknown properties!
  186.         raise AttributeError, attr
  187.  
  188. class AXScriptCodeObject:
  189.     def __init__(self, sourceCode, useEntry, flags, linebase, args):
  190.         # Framework removes trailing \n, and Python cant handle '\r\n'
  191.         self.codeObject = compile(RemoveCR(sourceCode)+'\n', "<AXScript>", "exec")
  192.         self.useEntry = useEntry
  193.         self.flags = flags
  194.         self.linebase = linebase
  195.         self.args = args
  196.     def Reset(self):
  197.         debug_reset_print("Reset called for AXScriptCodeObject", self,"with refcount=",sys.getrefcount(self))
  198.         self.codeObject = None
  199.         self.useEntry = None
  200.         self.flags=None
  201.         self.linebase=None
  202.         self.args=None
  203.  
  204. class AXScriptObject:
  205.     def __init__(self, name, IDispatch, flags):
  206.         self.__dict__['name'] = name
  207.         self.__dict__['dispatchContainer'] = dynamic.Dispatch(IDispatch, name)
  208.         self.__dict__['flags'] = flags
  209.     def __getattr__(self, attr):
  210.         return getattr(self.dispatchContainer, attr)
  211.     def __setattr__(self,attr, value):
  212.         return self.dispatchContainer.__setattr__(attr, value)
  213.     def Reset(self):
  214.         debug_reset_print("Reset called for ", self,"dispCont=",self.dispatchContainer,"with refcnt=",sys.getrefcount(self))
  215.         if self.dispatchContainer:
  216.             self.dispatchContainer._Release_()
  217.             self.__dict__['dispatchContainer'] = None
  218.     def __repr__(self):
  219.         return "AXScriptObject: Name: %s, flags: %d" % (self.name, self.flags)
  220.  
  221. class AXRExec(rexec.RExec):
  222.     def __init__(self, pretendMain, hooks = None, verbose = 0):
  223.         self.pretendMain = pretendMain
  224.         rexec.RExec.__init__(self, hooks, verbose)
  225.         self.ok_builtin_modules.append("axscript")
  226.     def make_main(self):
  227.         if not self.modules.has_key('__main__'):
  228.             self.modules['__main__'] = self.pretendMain
  229.             self.pretendMain.__builtins__ = self.modules['__builtin__']
  230.             m = self.add_module('__main__')
  231.  
  232. # Classes that looks and behaves like RExec, but isnt really!
  233. import IHooks
  234. class AXNotRHooks(IHooks.Hooks):
  235.     pass
  236.  
  237. class AXNotRExec:
  238.     def __init__(self, pretendMain, hooks = None, verbose = 0):
  239.         self.pretendMain = pretendMain
  240.         self.hooks = hooks or AXNotRHooks(verbose)
  241.         self.modules = {'__main__': self.pretendMain}
  242.  
  243.     def add_module(self, mname):
  244.         if self.modules.has_key(mname):
  245.             return self.modules[mname]
  246.         self.modules[mname] = m = self.hooks.new_module(mname)
  247. #        m.__builtins__ = self.modules['__builtin__']
  248.         return m
  249.  
  250. class AXScriptModule:
  251.     def __init__(self, modId, safetyOptions):
  252.         import imp
  253.         self.modId = modId;
  254.         self.scriptObjects = {}
  255.         self.codeObjects = []
  256.         self.attribContainer = None
  257.         self.defaultDispatchContainer = None
  258.         # Set up the execution dictionary for this module (ie, the locals).
  259.         self.pretendMain = imp.new_module("__ax_main__")
  260.         if modId==0: 
  261.             self.attribContainer = AXAttributeContainer()
  262.             self.pretendMain.ax = self.attribContainer
  263.         if safetyOptions:
  264.             # Use RExec.
  265.             self.rexec_env = AXRExec(self.pretendMain)
  266.         else:
  267.             # DONT use RExec.
  268.             self.rexec_env = AXNotRExec(self.pretendMain)
  269.     def FindAttribute(self, name):
  270.         # For all global scriptObjects, see if they define
  271.         # an attribute of that name.  Returns the value itself (NOT the object with the value)
  272.         # First step look for the explicit name (eg, "Window")
  273.         debug_attr_print("FindAttribute for name=%s on module id %d" % (name, self.modId))
  274.         try:
  275.             return self.scriptObjects[name]
  276.         except KeyError:
  277.             pass # Keep looking.
  278.         # Now look for an implicit object - ie, to allow "ax.abc"
  279.         # to mean "ax.window.abc"
  280.         for so in self.scriptObjects.values():
  281.             try:
  282.                 return getattr(so, name)
  283.             except AttributeError:
  284.                 pass
  285.         debug_attr_print("FindAttribute - Could not find it!")
  286.         raise AttributeError, name
  287.     def FindSetAttribute(self, name, value):
  288.         # For all global scriptObjects, attempt to set the objects atribute.
  289.         debug_attr_print("FindSetAttribute for %s=%s on module id %d" % (name, `value`, self.modId))
  290.         # Can not assign to the script objects themselves until we support OLE better.
  291.         # ie, ax.window = "http:..." will not work - ax.window.prop="..." will, tho.
  292.     
  293.         # Look for an implicit object - ie, to allow "ax.abc=10"
  294.         # to mean "ax.window.abc"
  295.         for so in self.scriptObjects.values():
  296.             try:
  297.                 return setattr(so, name, value)
  298.             except AttributeError:
  299.                 pass
  300.         debug_attr_print("FindSetAttribute - Could not find it!")
  301.         raise AttributeError, name
  302.         
  303.     def Reset(self):
  304.         import axscript
  305.         axscript.ClearDebugWindow()
  306.         debug_reset_print("Doing Reset for module", self)
  307.         for object in self.codeObjects:
  308.             object.Reset()
  309.         self.codeObjects = []
  310.         for object in self.scriptObjects.values():
  311.             debug_reset_print("Resetting object", object,"with refcnt",sys.getrefcount(object))
  312.             object.Reset()
  313.         self.scriptObjects = {}
  314.         self.rexec_env = None
  315.         self.attribContainer = None
  316.         self.pretendMain = None
  317.         if self.defaultDispatchContainer: 
  318.             self.defaultDispatchContainer._Release_()
  319.             self.defaultDispatchContainer = None
  320.     def AddObject(self, name, IDispatch, flags):
  321.         self.scriptObjects[name] = AXScriptObject(name, IDispatch, flags)
  322.         
  323.     def GetEntryPoint(self, name):
  324.         # Entry points are case insensitive
  325.         name=string.lower(name)
  326.         execDict = self.rexec_env.add_module('__main__').__dict__
  327.         for dictName, item in execDict.items():
  328.             if string.lower(dictName)==name:
  329.                 return self.modId, item
  330.         return None
  331.     def SetupForExec(self, localModule, defDispatchContainer):
  332.         globalModule = self
  333.         if defDispatchContainer is None:
  334.             defDispatchContainer = self.defaultDispatchContainer
  335.         if self.modId or self.attribContainer is None:
  336.             raise TypeError, "SetupForExec only valid for global modules"
  337.         cont = self.attribContainer
  338.         if not localModule is None:
  339.             cont.__dict__['_globalmodule_'] = self
  340.             # no harm having both the same, except redundant lookup.
  341.             if localModule is globalModule:
  342.                 cont.__dict__['_localmodule_'] = None
  343.             else:
  344.                 cont.__dict__['_localmodule_'] = localModule
  345.         else:
  346.             cont.__dict__['_globalmodule_'] = None
  347.             cont.__dict__['_localmodule_'] = None
  348.         cont.__dict__['_defaultdispatch_'] = defDispatchContainer
  349.         
  350.     def AddToScript(self, globalModule, sourceCode, useEntry, flags, linebase, args):
  351.         codeObject = AXScriptCodeObject(sourceCode, useEntry, flags, linebase, args)
  352.         self.codeObjects.append(codeObject)
  353.         globalModule.SetupForExec(self, None)
  354.         try:
  355.             exec codeObject.codeObject in globalModule.pretendMain.__dict__, self.pretendMain.__dict__
  356. #            self.rexec_env.r_exec(codeObject.codeObject)
  357.         finally:
  358.             globalModule.SetupForExec(None, None)
  359.     def Call(self, globalModule, method, defIDisp, fnArgs):
  360.         dispcont = dynamic.Dispatch(defIDisp,'<call default>')
  361.         globalModule.SetupForExec(self, dispcont)
  362.         try:
  363.             return apply(method,fnArgs)
  364.         finally:
  365.             dispcont._Release_()
  366.             globalModule.SetupForExec(None, None)
  367.  
  368.     def GetDispatchForModule(self):
  369.         print "GetDispatchForModule called"
  370.         return self.defaultDispatchContainer
  371.     def SetDefaultDispatch(self, defIDisp):
  372.         if self.defaultDispatchContainer: self.defaultDispatchContainer._Release_()
  373.         if defIDisp:
  374.             self.defaultDispatchContainer = dynamic.Dispatch(defIDisp,'<module default>')
  375.         else:
  376.             self.defaultDispatchContainer = None
  377.     
  378.     def __repr__(self):
  379.         return "AXScriptModule: Id: %d, %d objects" % (self.modId, len(self.scriptObjects))
  380.  
  381.  
  382. class AXScriptManager:
  383.     def __init__(self):
  384.         self.modules = {}
  385.         self.currentInterfaceSafetyOptions = 0
  386.     def Reset(self):
  387.         for module in self.modules.values():
  388.             module.Reset()
  389.     def Release(self):
  390.         self.Reset()
  391.     def GetModule(self, modId):
  392.         if not self.modules.has_key(modId):
  393.             self.modules[modId] = AXScriptModule(modId,self.currentInterfaceSafetyOptions)
  394.         return self.modules[modId]
  395.     def Call(self, modId, method, flags, defIDisp, fnArgs):
  396.         debug_print("AXScriptManager.Call called with ",modId, method, flags, defIDisp, fnArgs)
  397.         localModule = self.GetModule(modId)
  398.         globalModule = self.GetModule(0)
  399.         return localModule.Call(globalModule, method, defIDisp, fnArgs)
  400.  
  401.     def AddToScript(self, modId, sourceCode, useEntry, flags, linebase, args):
  402.         localModule = self.GetModule(modId)
  403.         globalModule = self.GetModule(0)
  404.         return localModule.AddToScript(globalModule, sourceCode, useEntry, flags, linebase, args)
  405.         
  406.     def SetDefaultDispatch(self, modId, defIDisp):
  407.         module = self.GetModule(modId)
  408.         module.SetDefaultDispatch(defIDisp)
  409.         
  410.     def GetDispatchForModule(self, modId):
  411.         module = self.GetModule(modId)
  412.         return module.GetDispatchForModule()
  413.  
  414.     def GetInterfaceSafetyOptions(self):
  415.         supported = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA
  416.         return supported, self.currentInterfaceSafetyOptions
  417.     def SetInterfaceSafetyOptions(self, optionsMask, enabledOptions):
  418.         if (optionsMask & enabledOptions)==INTERFACESAFE_FOR_UNTRUSTED_DATA:
  419.             self.currentInterfaceSafetyOptions = self.currentInterfaceSafetyOptions | INTERFACESAFE_FOR_UNTRUSTED_DATA
  420.             return 1
  421.         else:
  422.             return 0
  423.