PyXR

c:\python24\lib\site-packages\win32 \ com \ client \ genpy.py



0001 """genpy.py - The worker for makepy.  See makepy.py for more details
0002 
0003 This code was moved simply to speed Python in normal circumstances.  As the makepy.py
0004 is normally run from the command line, it reparses the code each time.  Now makepy
0005 is nothing more than the command line handler and public interface.
0006 
0007 The makepy command line etc handling is also getting large enough in its own right!
0008 """
0009 
0010 # NOTE - now supports a "demand" mechanism - the top-level is a package, and
0011 # each class etc can be made individually.
0012 # This should eventually become the default.
0013 # Then the old non-package technique should be removed.
0014 # There should be no b/w compat issues, and will just help clean the code.
0015 # This will be done once the new "demand" mechanism gets a good workout.
0016 import os
0017 import sys
0018 import string
0019 import time
0020 import win32com
0021 
0022 import pythoncom
0023 import build
0024 
0025 error = "makepy.error"
0026 makepy_version = "0.4.91" # Written to generated file.
0027 
0028 GEN_FULL="full"
0029 GEN_DEMAND_BASE = "demand(base)"
0030 GEN_DEMAND_CHILD = "demand(child)"
0031 
0032 try:
0033     TrueRepr = repr(True)
0034     FalseRepr = repr(False)
0035 except NameError:
0036     TrueRepr = "1"
0037     FalseRepr = "0"
0038 
0039 # This map is used purely for the users benefit -it shows the
0040 # raw, underlying type of Alias/Enums, etc.  The COM implementation
0041 # does not use this map at runtime - all Alias/Enum have already
0042 # been translated.
0043 mapVTToTypeString = {
0044     pythoncom.VT_I2: 'types.IntType',
0045     pythoncom.VT_I4: 'types.IntType',
0046     pythoncom.VT_R4: 'types.FloatType',
0047     pythoncom.VT_R8: 'types.FloatType',
0048     pythoncom.VT_BSTR: 'types.StringType',
0049     pythoncom.VT_BOOL: 'types.IntType',
0050     pythoncom.VT_VARIANT: 'types.TypeType',
0051     pythoncom.VT_I1: 'types.IntType',
0052     pythoncom.VT_UI1: 'types.IntType',
0053     pythoncom.VT_UI2: 'types.IntType',
0054     pythoncom.VT_UI4: 'types.IntType',
0055     pythoncom.VT_I8: 'types.LongType',
0056     pythoncom.VT_UI8: 'types.LongType',
0057     pythoncom.VT_INT: 'types.IntType',
0058     pythoncom.VT_DATE: 'pythoncom.PyTimeType',
0059     pythoncom.VT_UINT: 'types.IntType',
0060 }
0061 
0062 # Given a propget function's arg desc, return the default parameters for all
0063 # params bar the first.  Eg, then Python does a:
0064 # object.Property = "foo"
0065 # Python can only pass the "foo" value.  If the property has
0066 # multiple args, and the rest have default values, this allows
0067 # Python to correctly pass those defaults.
0068 def MakeDefaultArgsForPropertyPut(argsDesc):
0069     ret = []
0070     for desc in argsDesc[1:]:
0071         default = build.MakeDefaultArgRepr(desc)
0072         if default is None:
0073             break
0074         ret.append(default)
0075     return tuple(ret)
0076                             
0077 
0078 def MakeMapLineEntry(dispid, wFlags, retType, argTypes, user, resultCLSID):
0079     # Strip the default value
0080     argTypes = tuple(map(lambda what: what[:2], argTypes))
0081     return '(%s, %d, %s, %s, "%s", %s)' % \
0082         (dispid, wFlags, retType[:2], argTypes, user, resultCLSID)
0083 
0084 def MakeEventMethodName(eventName):
0085     if eventName[:2]=="On":
0086         return eventName
0087     else:
0088         return "On"+eventName
0089 
0090 def WriteSinkEventMap(obj, stream):
0091     print >> stream, '\t_dispid_to_func_ = {'
0092     for name, entry in obj.propMapGet.items() + obj.propMapPut.items() + obj.mapFuncs.items():
0093         fdesc = entry.desc
0094         print >> stream, '\t\t%9d : "%s",' % (entry.desc[0], MakeEventMethodName(entry.names[0]))
0095     print >> stream, '\t\t}'
0096     
0097 
0098 # MI is used to join my writable helpers, and the OLE
0099 # classes.
0100 class WritableItem:
0101     def __cmp__(self, other):
0102         "Compare for sorting"   
0103         ret = cmp(self.order, other.order)
0104         if ret==0 and self.doc: ret = cmp(self.doc[0], other.doc[0])
0105         return ret
0106     def __repr__(self):
0107         return "OleItem: doc=%s, order=%d" % (`self.doc`, self.order)
0108 
0109 
0110 class RecordItem(build.OleItem, WritableItem):
0111   order = 9
0112   typename = "RECORD"
0113 
0114   def __init__(self, typeInfo, typeAttr, doc=None, bForUser=1):
0115 ##    sys.stderr.write("Record %s: size %s\n" % (doc,typeAttr.cbSizeInstance))
0116 ##    sys.stderr.write(" cVars = %s\n" % (typeAttr.cVars,))
0117 ##    for i in range(typeAttr.cVars):
0118 ##        vdesc = typeInfo.GetVarDesc(i)
0119 ##        sys.stderr.write(" Var %d has value %s, type %d, desc=%s\n" % (i, vdesc.value, vdesc.varkind, vdesc.elemdescVar))
0120 ##        sys.stderr.write(" Doc is %s\n" % (typeInfo.GetDocumentation(vdesc.memid),))
0121 
0122     build.OleItem.__init__(self, doc)
0123     self.clsid = typeAttr[0]
0124 
0125   def WriteClass(self, generator):
0126     pass
0127 
0128 # Given an enum, write all aliases for it.
0129 # (no longer necessary for new style code, but still used for old code.
0130 def WriteAliasesForItem(item, aliasItems, stream):
0131   for alias in aliasItems.values():
0132     if item.doc and alias.aliasDoc and (alias.aliasDoc[0]==item.doc[0]):
0133       alias.WriteAliasItem(aliasItems, stream)
0134       
0135 class AliasItem(build.OleItem, WritableItem):
0136   order = 2
0137   typename = "ALIAS"
0138 
0139   def __init__(self, typeinfo, attr, doc=None, bForUser = 1):
0140     build.OleItem.__init__(self, doc)
0141 
0142     ai = attr[14]
0143     self.attr = attr
0144     if type(ai) == type(()) and \
0145       type(ai[1])==type(0): # XXX - This is a hack - why tuples?  Need to resolve?
0146       href = ai[1]
0147       alinfo = typeinfo.GetRefTypeInfo(href)
0148       self.aliasDoc = alinfo.GetDocumentation(-1)
0149       self.aliasAttr = alinfo.GetTypeAttr()
0150     else:
0151       self.aliasDoc = None
0152       self.aliasAttr = None
0153 
0154   def WriteAliasItem(self, aliasDict, stream):
0155     # we could have been written as part of an alias dependency
0156     if self.bWritten:
0157       return
0158 
0159     if self.aliasDoc:
0160       depName = self.aliasDoc[0]
0161       if aliasDict.has_key(depName):
0162         aliasDict[depName].WriteAliasItem(aliasDict, stream)
0163       print >> stream, self.doc[0] + " = " + depName
0164     else:
0165       ai = self.attr[14]
0166       if type(ai) == type(0):
0167         try:
0168           typeStr = mapVTToTypeString[ai]
0169           print >> stream, "# %s=%s" % (self.doc[0], typeStr)
0170         except KeyError:
0171           print >> stream, self.doc[0] + " = None # Can't convert alias info " + str(ai)
0172     print >> stream
0173     self.bWritten = 1
0174 
0175 class EnumerationItem(build.OleItem, WritableItem):
0176   order = 1
0177   typename = "ENUMERATION"
0178 
0179   def __init__(self, typeinfo, attr, doc=None, bForUser=1):
0180     build.OleItem.__init__(self, doc)
0181 
0182     self.clsid = attr[0]
0183     self.mapVars = {}
0184     typeFlags = attr[11]
0185     self.hidden = typeFlags & pythoncom.TYPEFLAG_FHIDDEN or \
0186                   typeFlags & pythoncom.TYPEFLAG_FRESTRICTED
0187 
0188     for j in range(attr[7]):
0189       vdesc = typeinfo.GetVarDesc(j)
0190       name = typeinfo.GetNames(vdesc[0])[0]
0191       self.mapVars[name] = build.MapEntry(vdesc)
0192 
0193 ##  def WriteEnumerationHeaders(self, aliasItems, stream):
0194 ##    enumName = self.doc[0]
0195 ##    print >> stream "%s=constants # Compatibility with previous versions." % (enumName)
0196 ##    WriteAliasesForItem(self, aliasItems)
0197     
0198   def WriteEnumerationItems(self, stream):
0199     enumName = self.doc[0]
0200     # Write in name alpha order
0201     names = self.mapVars.keys()
0202     names.sort()
0203     for name in names:
0204       entry = self.mapVars[name]
0205       vdesc = entry.desc
0206       if vdesc[4] == pythoncom.VAR_CONST:
0207         val = vdesc[1]
0208         if type(val)==type(0):
0209           if val==0x80000000L: # special case
0210             use = "0x80000000L" # 'L' for future warning
0211           elif val > 0x80000000L or val < 0: # avoid a FutureWarning
0212             use = long(val)
0213           else:
0214             use = hex(val)
0215         else:
0216           use = repr(str(val))
0217         print >> stream, "\t%-30s=%-10s # from enum %s" % \
0218                       (build.MakePublicAttributeName(name, True), use, enumName)
0219 
0220 class VTableItem(build.VTableItem, WritableItem):
0221     order = 4
0222 
0223     def WriteClass(self, generator):
0224         self.WriteVTableMap(generator)
0225         self.bWritten = 1
0226 
0227     def WriteVTableMap(self, generator):
0228         stream = generator.file
0229         print >> stream, "%s_vtables_dispatch_ = %d" % (self.python_name, self.bIsDispatch)
0230         print >> stream, "%s_vtables_ = [" % (self.python_name, ) 
0231         for v in self.vtableFuncs:
0232             chunks = []
0233             names, dispid, desc = v
0234             arg_desc = desc[2]
0235 
0236             arg_reprs = []
0237             for arg in arg_desc:
0238                 defval = build.MakeDefaultArgRepr(arg)
0239                 if arg[3] is None:
0240                     arg3_repr = None
0241                 else:
0242                     arg3_repr = repr(arg[3])
0243                 arg_reprs.append((arg[0], arg[1], defval, arg3_repr))
0244             desc = desc[:2] + (arg_reprs,) + desc[3:]
0245             chunks.append("\t(%r, %d, %r)," % (names, dispid, desc))
0246             print >> stream, "".join(chunks)
0247         print >> stream, "]"
0248         print >> stream
0249 
0250 class DispatchItem(build.DispatchItem, WritableItem):
0251     order = 3
0252 
0253     def __init__(self, typeinfo, attr, doc=None):
0254         build.DispatchItem.__init__(self, typeinfo, attr, doc)
0255         self.type_attr = attr
0256         self.coclass_clsid = None
0257 
0258     def WriteClass(self, generator):
0259       if not self.bIsDispatch and not self.type_attr.typekind == pythoncom.TKIND_DISPATCH:
0260           return
0261       # This is pretty screwey - now we have vtable support we
0262       # should probably rethink this (ie, maybe write both sides for sinks, etc)
0263       if self.bIsSink:
0264           self.WriteEventSinkClassHeader(generator)
0265           self.WriteCallbackClassBody(generator)
0266       else:
0267           self.WriteClassHeader(generator)
0268           self.WriteClassBody(generator)
0269       print >> generator.file
0270       self.bWritten = 1
0271 
0272     def WriteClassHeader(self, generator):
0273         generator.checkWriteDispatchBaseClass()
0274         doc = self.doc
0275         stream = generator.file
0276         print >> stream, 'class ' + self.python_name + '(DispatchBaseClass):'
0277         if doc[1]: print >> stream, '\t' + build._safeQuotedString(doc[1])
0278         try:
0279             progId = pythoncom.ProgIDFromCLSID(self.clsid)
0280             print >> stream, "\t# This class is creatable by the name '%s'" % (progId)
0281         except pythoncom.com_error:
0282             pass
0283         print >> stream, "\tCLSID = " + repr(self.clsid)
0284         if self.coclass_clsid is None:
0285             print >> stream, "\tcoclass_clsid = None"
0286         else:
0287             print >> stream, "\tcoclass_clsid = " + repr(self.coclass_clsid)
0288         print >> stream
0289         self.bWritten = 1
0290 
0291     def WriteEventSinkClassHeader(self, generator):
0292         generator.checkWriteEventBaseClass()
0293         doc = self.doc
0294         stream = generator.file
0295         print >> stream, 'class ' + self.python_name + ':'
0296         if doc[1]: print >> stream, '\t' + build._safeQuotedString(doc[1])
0297         try:
0298             progId = pythoncom.ProgIDFromCLSID(self.clsid)
0299             print >> stream, "\t# This class is creatable by the name '%s'" % (progId)
0300         except pythoncom.com_error:
0301             pass
0302         print >> stream, '\tCLSID = CLSID_Sink = ' + repr(self.clsid)
0303         if self.coclass_clsid is None:
0304             print >> stream, "\tcoclass_clsid = None"
0305         else:
0306             print >> stream, "\tcoclass_clsid = " + repr(self.coclass_clsid)
0307         print >> stream, '\t_public_methods_ = [] # For COM Server support'
0308         WriteSinkEventMap(self, stream)
0309         print >> stream
0310         print >> stream, '\tdef __init__(self, oobj = None):'
0311         print >> stream, "\t\tif oobj is None:"
0312         print >> stream, "\t\t\tself._olecp = None"
0313         print >> stream, "\t\telse:"
0314         print >> stream, '\t\t\timport win32com.server.util'
0315         print >> stream, '\t\t\tfrom win32com.server.policy import EventHandlerPolicy'
0316         print >> stream, '\t\t\tcpc=oobj._oleobj_.QueryInterface(pythoncom.IID_IConnectionPointContainer)'
0317         print >> stream, '\t\t\tcp=cpc.FindConnectionPoint(self.CLSID_Sink)'
0318         print >> stream, '\t\t\tcookie=cp.Advise(win32com.server.util.wrap(self, usePolicy=EventHandlerPolicy))'
0319         print >> stream, '\t\t\tself._olecp,self._olecp_cookie = cp,cookie'
0320         print >> stream, '\tdef __del__(self):'
0321         print >> stream, '\t\ttry:'
0322         print >> stream, '\t\t\tself.close()'
0323         print >> stream, '\t\texcept pythoncom.com_error:'
0324         print >> stream, '\t\t\tpass'
0325         print >> stream, '\tdef close(self):'
0326         print >> stream, '\t\tif self._olecp is not None:'
0327         print >> stream, '\t\t\tcp,cookie,self._olecp,self._olecp_cookie = self._olecp,self._olecp_cookie,None,None'
0328         print >> stream, '\t\t\tcp.Unadvise(cookie)'
0329         print >> stream, '\tdef _query_interface_(self, iid):'
0330         print >> stream, '\t\timport win32com.server.util'
0331         print >> stream, '\t\tif iid==self.CLSID_Sink: return win32com.server.util.wrap(self)'
0332         print >> stream
0333         self.bWritten = 1
0334 
0335     def WriteCallbackClassBody(self, generator):
0336         stream = generator.file
0337         print >> stream, "\t# Event Handlers"
0338         print >> stream, "\t# If you create handlers, they should have the following prototypes:"
0339         for name, entry in self.propMapGet.items() + self.propMapPut.items() + self.mapFuncs.items():
0340             fdesc = entry.desc
0341             methName = MakeEventMethodName(entry.names[0])
0342             print >> stream, '#\tdef ' + methName + '(self' + build.BuildCallList(fdesc, entry.names, "defaultNamedOptArg", "defaultNamedNotOptArg","defaultUnnamedArg", "pythoncom.Missing") + '):'
0343             if entry.doc and entry.doc[1]:
0344                 print >> stream, '#\t\t' + build._safeQuotedString(entry.doc[1])
0345         print >> stream
0346         self.bWritten = 1
0347 
0348     def WriteClassBody(self, generator):
0349         stream = generator.file
0350         # Write in alpha order.
0351         names = self.mapFuncs.keys()
0352         names.sort()
0353         specialItems = {"count":None, "item":None,"value":None,"_newenum":None} # If found, will end up with (entry, invoke_tupe)
0354         itemCount = None
0355         for name in names:
0356             entry=self.mapFuncs[name]
0357             # skip [restricted] methods, unless it is the
0358             # enumerator (which, being part of the "system",
0359             # we know about and can use)
0360             dispid = entry.desc[0]
0361             if entry.desc[9] & pythoncom.FUNCFLAG_FRESTRICTED and \
0362                 dispid != pythoncom.DISPID_NEWENUM:
0363                 continue
0364             # If not accessible via IDispatch, then we can't use it here.
0365             if entry.desc[3] != pythoncom.FUNC_DISPATCH:
0366                 continue
0367             if dispid==pythoncom.DISPID_VALUE:
0368                 lkey = "value"
0369             elif dispid==pythoncom.DISPID_NEWENUM:
0370                 specialItems["_newenum"] = (entry, entry.desc[4], None)
0371                 continue # Dont build this one now!
0372             else:
0373                 lkey = string.lower(name)
0374             if specialItems.has_key(lkey) and specialItems[lkey] is None: # remember if a special one.
0375                 specialItems[lkey] = (entry, entry.desc[4], None)
0376             if generator.bBuildHidden or not entry.hidden:
0377                 if entry.GetResultName():
0378                     print >> stream, '\t# Result is of type ' + entry.GetResultName()
0379                 if entry.wasProperty:
0380                     print >> stream, '\t# The method %s is actually a property, but must be used as a method to correctly pass the arguments' % name
0381                 ret = self.MakeFuncMethod(entry,build.MakePublicAttributeName(name))
0382                 for line in ret:
0383                     print >> stream, line
0384         print >> stream, "\t_prop_map_get_ = {"
0385         names = self.propMap.keys(); names.sort()
0386         for key in names:
0387             entry = self.propMap[key]
0388             if generator.bBuildHidden or not entry.hidden:
0389                 resultName = entry.GetResultName()
0390                 if resultName:
0391                     print >> stream, "\t\t# Property '%s' is an object of type '%s'" % (key, resultName)
0392                 lkey = string.lower(key)
0393                 details = entry.desc
0394                 resultDesc = details[2]
0395                 argDesc = ()
0396                 mapEntry = MakeMapLineEntry(details[0], pythoncom.DISPATCH_PROPERTYGET, resultDesc, argDesc, key, entry.GetResultCLSIDStr())
0397             
0398                 if entry.desc[0]==pythoncom.DISPID_VALUE:
0399                     lkey = "value"
0400                 elif entry.desc[0]==pythoncom.DISPID_NEWENUM:
0401                     lkey = "_newenum"
0402                 else:
0403                     lkey = string.lower(key)
0404                 if specialItems.has_key(lkey) and specialItems[lkey] is None: # remember if a special one.
0405                     specialItems[lkey] = (entry, pythoncom.DISPATCH_PROPERTYGET, mapEntry)
0406                     # All special methods, except _newenum, are written
0407                     # "normally".  This is a mess!
0408                     if entry.desc[0]==pythoncom.DISPID_NEWENUM:
0409                         continue 
0410 
0411                 print >> stream, '\t\t"%s": %s,' % (key, mapEntry)
0412         names = self.propMapGet.keys(); names.sort()
0413         for key in names:
0414             entry = self.propMapGet[key]
0415             if generator.bBuildHidden or not entry.hidden:
0416                 if entry.GetResultName():
0417                     print >> stream, "\t\t# Method '%s' returns object of type '%s'" % (key, entry.GetResultName())
0418                 details = entry.desc
0419                 lkey = string.lower(key)
0420                 argDesc = details[2]
0421                 resultDesc = details[8]
0422                 mapEntry = MakeMapLineEntry(details[0], pythoncom.DISPATCH_PROPERTYGET, resultDesc, argDesc, key, entry.GetResultCLSIDStr())
0423                 if entry.desc[0]==pythoncom.DISPID_VALUE:
0424                     lkey = "value"
0425                 elif entry.desc[0]==pythoncom.DISPID_NEWENUM:
0426                     lkey = "_newenum"
0427                 else:
0428                     lkey = string.lower(key)
0429                 if specialItems.has_key(lkey) and specialItems[lkey] is None: # remember if a special one.
0430                     specialItems[lkey]=(entry, pythoncom.DISPATCH_PROPERTYGET, mapEntry)
0431                     # All special methods, except _newenum, are written
0432                     # "normally".  This is a mess!
0433                     if entry.desc[0]==pythoncom.DISPID_NEWENUM:
0434                         continue 
0435                 print >> stream, '\t\t"%s": %s,' % (key, mapEntry)
0436 
0437         print >> stream, "\t}"
0438 
0439         print >> stream, "\t_prop_map_put_ = {"
0440         # These are "Invoke" args
0441         names = self.propMap.keys(); names.sort()
0442         for key in names:
0443             entry = self.propMap[key]
0444             if generator.bBuildHidden or not entry.hidden:
0445                 lkey=string.lower(key)
0446                 details = entry.desc
0447                 # If default arg is None, write an empty tuple
0448                 defArgDesc = build.MakeDefaultArgRepr(details[2])
0449                 if defArgDesc is None:
0450                     defArgDesc = ""
0451                 else:
0452                     defArgDesc = defArgDesc + ","
0453                 print >> stream, '\t\t"%s" : ((%s, LCID, %d, 0),(%s)),' % (key, details[0], pythoncom.DISPATCH_PROPERTYPUT, defArgDesc)
0454 
0455         names = self.propMapPut.keys(); names.sort()
0456         for key in names:
0457             entry = self.propMapPut[key]
0458             if generator.bBuildHidden or not entry.hidden:
0459                 details = entry.desc
0460                 defArgDesc = MakeDefaultArgsForPropertyPut(details[2])
0461                 print >> stream, '\t\t"%s": ((%s, LCID, %d, 0),%s),' % (key, details[0], details[4], defArgDesc)
0462         print >> stream, "\t}"
0463         
0464         if specialItems["value"]:
0465             entry, invoketype, propArgs = specialItems["value"]
0466             if propArgs is None:
0467                 typename = "method"
0468                 ret = self.MakeFuncMethod(entry,'__call__')
0469             else:
0470                 typename = "property"
0471                 ret = [ "\tdef __call__(self):\n\t\treturn self._ApplyTypes_(*%s)" % propArgs]
0472             print >> stream, "\t# Default %s for this class is '%s'" % (typename, entry.names[0])
0473             for line in ret:
0474                 print >> stream, line
0475             print >> stream, "\t# str(ob) and int(ob) will use __call__"
0476             print >> stream, "\tdef __unicode__(self, *args):"
0477             print >> stream, "\t\ttry:"
0478             print >> stream, "\t\t\treturn unicode(self.__call__(*args))"
0479             print >> stream, "\t\texcept pythoncom.com_error:"
0480             print >> stream, "\t\t\treturn repr(self)"
0481             print >> stream, "\tdef __str__(self, *args):"
0482             print >> stream, "\t\treturn str(self.__unicode__(*args))"
0483             print >> stream, "\tdef __int__(self, *args):"
0484             print >> stream, "\t\treturn int(self.__call__(*args))"
0485             
0486 
0487         if specialItems["_newenum"]:
0488             enumEntry, invoketype, propArgs = specialItems["_newenum"]
0489             resultCLSID = enumEntry.GetResultCLSIDStr()
0490             # If we dont have a good CLSID for the enum result, assume it is the same as the Item() method.
0491             if resultCLSID == "None" and self.mapFuncs.has_key("Item"):
0492                 resultCLSID = self.mapFuncs["Item"].GetResultCLSIDStr()
0493             # "Native" Python iterator support
0494             print >> stream, '\tdef __iter__(self):'
0495             print >> stream, '\t\t"Return a Python iterator for this object"'
0496             print >> stream, '\t\tob = self._oleobj_.InvokeTypes(%d,LCID,%d,(13, 10),())' % (pythoncom.DISPID_NEWENUM, enumEntry.desc[4])
0497             print >> stream, '\t\treturn win32com.client.util.Iterator(ob)'
0498             # And 'old style' iterator support - magically used to simulate iterators
0499             # before Python grew them
0500             print >> stream, '\tdef _NewEnum(self):'
0501             print >> stream, '\t\t"Create an enumerator from this object"'
0502             print >> stream, '\t\treturn win32com.client.util.WrapEnum(self._oleobj_.InvokeTypes(%d,LCID,%d,(13, 10),()),%s)' % (pythoncom.DISPID_NEWENUM, enumEntry.desc[4], resultCLSID)
0503             print >> stream, '\tdef __getitem__(self, index):'
0504             print >> stream, '\t\t"Allow this class to be accessed as a collection"'
0505             print >> stream, "\t\tif not self.__dict__.has_key('_enum_'):"
0506             print >> stream, "\t\t\tself.__dict__['_enum_'] = self._NewEnum()"
0507             print >> stream, "\t\treturn self._enum_.__getitem__(index)"
0508         else: # Not an Enumerator, but may be an "Item/Count" based collection
0509             if specialItems["item"]:
0510                 entry, invoketype, propArgs = specialItems["item"]
0511                 print >> stream, '\t#This class has Item property/method which may take args - allow indexed access'
0512                 print >> stream, '\tdef __getitem__(self, item):'
0513                 print >> stream, '\t\treturn self._get_good_object_(self._oleobj_.Invoke(*(%d, LCID, %d, 1, item)), "Item")' % (entry.desc[0], invoketype)
0514         if specialItems["count"]:
0515             entry, invoketype, propArgs = specialItems["count"]
0516             if propArgs is None:
0517                 typename = "method"
0518                 ret = self.MakeFuncMethod(entry,'__len__')
0519             else:
0520                 typename = "property"
0521                 ret = [ "\tdef __len__(self):\n\t\treturn self._ApplyTypes_(*%s)" % propArgs]
0522             print >> stream, "\t#This class has Count() %s - allow len(ob) to provide this" % (typename)
0523             for line in ret:
0524                 print >> stream, line
0525             # Also include a __nonzero__
0526             print >> stream, "\t#This class has a __len__ - this is needed so 'if object:' always returns TRUE."
0527             print >> stream, "\tdef __nonzero__(self):"
0528             print >> stream, "\t\treturn %s" % (TrueRepr,)
0529 
0530 class CoClassItem(build.OleItem, WritableItem):
0531   order = 5
0532   typename = "COCLASS"
0533 
0534   def __init__(self, typeinfo, attr, doc=None, sources = [], interfaces = [], bForUser=1):
0535     build.OleItem.__init__(self, doc)
0536     self.clsid = attr[0]
0537     self.sources = sources
0538     self.interfaces = interfaces
0539     self.bIsDispatch = 1 # Pretend it is so it is written to the class map.
0540 
0541   def WriteClass(self, generator):
0542     generator.checkWriteCoClassBaseClass()
0543     doc = self.doc
0544     stream = generator.file
0545     if generator.generate_type == GEN_DEMAND_CHILD:
0546       # Some special imports we must setup.
0547       referenced_items = []
0548       for ref, flag in self.sources:
0549         referenced_items.append(ref)
0550       for ref, flag in self.interfaces:
0551         referenced_items.append(ref)
0552       print >> stream, "import sys"
0553       for ref in referenced_items:
0554         print >> stream, "__import__('%s.%s')" % (generator.base_mod_name, ref.python_name)
0555         print >> stream, "%s = sys.modules['%s.%s'].%s" % (ref.python_name, generator.base_mod_name, ref.python_name, ref.python_name)
0556         # And pretend we have written it - the name is now available as if we had!
0557         ref.bWritten = 1
0558     try:
0559       progId = pythoncom.ProgIDFromCLSID(self.clsid)
0560       print >> stream, "# This CoClass is known by the name '%s'" % (progId)
0561     except pythoncom.com_error:
0562       pass
0563     print >> stream, 'class %s(CoClassBaseClass): # A CoClass' % (self.python_name)
0564     if doc and doc[1]: print >> stream, '\t# ' + doc[1]
0565     print >> stream, '\tCLSID = %r' % (self.clsid,)
0566     print >> stream, '\tcoclass_sources = ['
0567     defItem = None
0568     for item, flag in self.sources:
0569       if flag & pythoncom.IMPLTYPEFLAG_FDEFAULT:
0570         defItem = item
0571       # If we have written a Python class, reference the name - 
0572       # otherwise just the IID.
0573       if item.bWritten: key = item.python_name
0574       else: key = repr(str(item.clsid)) # really the iid.
0575       print >> stream, '\t\t%s,' % (key)
0576     print >> stream, '\t]'
0577     if defItem:
0578       if defItem.bWritten: defName = defItem.python_name
0579       else: defName = repr(str(defItem.clsid)) # really the iid.
0580       print >> stream, '\tdefault_source = %s' % (defName,)
0581     print >> stream, '\tcoclass_interfaces = ['
0582     defItem = None
0583     for item, flag in self.interfaces:
0584       if flag & pythoncom.IMPLTYPEFLAG_FDEFAULT: # and dual:
0585         defItem = item
0586       # If we have written a class, refeence its name, otherwise the IID
0587       if item.bWritten: key = item.python_name
0588       else: key = repr(str(item.clsid)) # really the iid.
0589       print >> stream, '\t\t%s,' % (key,)
0590     print >> stream, '\t]'
0591     if defItem:
0592       if defItem.bWritten: defName = defItem.python_name
0593       else: defName = repr(str(defItem.clsid)) # really the iid.
0594       print >> stream, '\tdefault_interface = %s' % (defName,)
0595     self.bWritten = 1
0596     print >> stream
0597 
0598 class GeneratorProgress:
0599     def __init__(self):
0600         pass
0601     def Starting(self, tlb_desc):
0602         """Called when the process starts.
0603         """
0604         self.tlb_desc = tlb_desc
0605     def Finished(self):
0606         """Called when the process is complete.
0607         """
0608     def SetDescription(self, desc, maxticks = None):
0609         """We are entering a major step.  If maxticks, then this
0610         is how many ticks we expect to make until finished
0611         """
0612     def Tick(self, desc = None):
0613         """Minor progress step.  Can provide new description if necessary
0614         """
0615     def VerboseProgress(self, desc):
0616         """Verbose/Debugging output.
0617         """
0618     def LogWarning(self, desc):
0619         """If a warning is generated
0620         """
0621     def LogBeginGenerate(self, filename):
0622         pass
0623     def Close(self):
0624         pass
0625 
0626 class Generator:
0627   def __init__(self, typelib, sourceFilename, progressObject, bBuildHidden=1, bUnicodeToString=0):
0628     self.bHaveWrittenDispatchBaseClass = 0
0629     self.bHaveWrittenCoClassBaseClass = 0
0630     self.bHaveWrittenEventBaseClass = 0
0631     self.typelib = typelib
0632     self.sourceFilename = sourceFilename
0633     self.bBuildHidden = bBuildHidden
0634     self.bUnicodeToString = bUnicodeToString
0635     self.progress = progressObject
0636     # These 2 are later additions and most of the code still 'print's...
0637     self.file = None
0638 
0639   def CollectOleItemInfosFromType(self):
0640     ret = []
0641     for i in xrange(self.typelib.GetTypeInfoCount()):
0642       info = self.typelib.GetTypeInfo(i)
0643       infotype = self.typelib.GetTypeInfoType(i)
0644       doc = self.typelib.GetDocumentation(i)
0645       attr = info.GetTypeAttr()
0646       ret.append((info, infotype, doc, attr))
0647     return ret
0648 
0649   def _Build_CoClass(self, type_info_tuple):
0650     info, infotype, doc, attr = type_info_tuple
0651     # find the source and dispinterfaces for the coclass
0652     child_infos = []
0653     for j in range(attr[8]):
0654       flags = info.GetImplTypeFlags(j)
0655       refType = info.GetRefTypeInfo(info.GetRefTypeOfImplType(j))
0656       refAttr = refType.GetTypeAttr()
0657       child_infos.append( (info, refAttr.typekind, refType, refType.GetDocumentation(-1), refAttr, flags) )
0658       
0659     # Done generating children - now the CoClass itself.
0660     newItem = CoClassItem(info, attr, doc)
0661     return newItem, child_infos
0662 
0663   def _Build_CoClassChildren(self, coclass, coclass_info, oleItems, vtableItems):
0664     sources = {}
0665     interfaces = {}
0666     for info, info_type, refType, doc, refAttr, flags in coclass_info:
0667 #          sys.stderr.write("Attr typeflags for coclass referenced object %s=%d (%d), typekind=%d\n" % (name, refAttr.wTypeFlags, refAttr.wTypeFlags & pythoncom.TYPEFLAG_FDUAL,refAttr.typekind))
0668         if refAttr.typekind == pythoncom.TKIND_DISPATCH:
0669           clsid = refAttr[0]
0670           if oleItems.has_key(clsid):
0671             dispItem = oleItems[clsid]
0672           else:
0673             dispItem = DispatchItem(refType, refAttr, doc)
0674             oleItems[dispItem.clsid] = dispItem
0675           dispItem.coclass_clsid = coclass.clsid
0676           if flags & pythoncom.IMPLTYPEFLAG_FSOURCE:
0677             dispItem.bIsSink = 1
0678             sources[dispItem.clsid] = (dispItem, flags)
0679           else:
0680             interfaces[dispItem.clsid] = (dispItem, flags)
0681           # If dual interface, make do that too.
0682           if not vtableItems.has_key(clsid) and refAttr[11] & pythoncom.TYPEFLAG_FDUAL:
0683             refType = refType.GetRefTypeInfo(refType.GetRefTypeOfImplType(-1))
0684             refAttr = refType.GetTypeAttr()
0685             assert refAttr.typekind == pythoncom.TKIND_INTERFACE, "must be interface bynow!"
0686             vtableItem = VTableItem(refType, refAttr, doc)
0687             vtableItems[clsid] = vtableItem
0688     coclass.sources = sources.values()
0689     coclass.interfaces = interfaces.values()
0690 
0691   def _Build_Interface(self, type_info_tuple):
0692     info, infotype, doc, attr = type_info_tuple
0693     oleItem = vtableItem = None
0694     if infotype == pythoncom.TKIND_DISPATCH:
0695         oleItem = DispatchItem(info, attr, doc)
0696         # If this DISPATCH interface dual, then build that too.
0697         if (attr.wTypeFlags & pythoncom.TYPEFLAG_FDUAL):
0698 #                sys.stderr.write("interface " + doc[0] + " is not dual\n");
0699             # Get the vtable interface
0700             refhtype = info.GetRefTypeOfImplType(-1)
0701             info = info.GetRefTypeInfo(refhtype)
0702             attr = info.GetTypeAttr()
0703             infotype = pythoncom.TKIND_INTERFACE
0704         else:
0705             infotype = None
0706     assert infotype in [None, pythoncom.TKIND_INTERFACE], "Must be a real interface at this point"
0707     if infotype == pythoncom.TKIND_INTERFACE:
0708         vtableItem = VTableItem(info, attr, doc)
0709     return oleItem, vtableItem
0710 
0711   def BuildOleItemsFromType(self):
0712     assert self.bBuildHidden, "This code doesnt look at the hidden flag - I thought everyone set it true!?!?!"
0713     oleItems = {}
0714     enumItems = {}
0715     recordItems = {}
0716     vtableItems = {}
0717     
0718     for type_info_tuple in self.CollectOleItemInfosFromType():
0719       info, infotype, doc, attr = type_info_tuple
0720       clsid = attr[0]
0721       if infotype == pythoncom.TKIND_ENUM or infotype == pythoncom.TKIND_MODULE:
0722         newItem = EnumerationItem(info, attr, doc)
0723         enumItems[newItem.doc[0]] = newItem
0724       # We never hide interfaces (MSAccess, for example, nominates interfaces as
0725       # hidden, assuming that you only ever use them via the CoClass)
0726       elif infotype in [pythoncom.TKIND_DISPATCH, pythoncom.TKIND_INTERFACE]:
0727         if not oleItems.has_key(clsid):
0728           oleItem, vtableItem = self._Build_Interface(type_info_tuple)
0729           oleItems[clsid] = oleItem # Even "None" goes in here.
0730           if vtableItem is not None:
0731               vtableItems[clsid] = vtableItem
0732       elif infotype == pythoncom.TKIND_RECORD or infotype == pythoncom.TKIND_UNION:
0733         newItem = RecordItem(info, attr, doc)
0734         recordItems[newItem.clsid] = newItem
0735       elif infotype == pythoncom.TKIND_ALIAS:
0736         # We dont care about alias' - handled intrinsicly.
0737         continue
0738       elif infotype == pythoncom.TKIND_COCLASS:
0739         newItem, child_infos = self._Build_CoClass(type_info_tuple)
0740         self._Build_CoClassChildren(newItem, child_infos, oleItems, vtableItems)
0741         oleItems[newItem.clsid] = newItem
0742       else:
0743         self.progress.LogWarning("Unknown TKIND found: %d" % infotype)
0744   
0745     return oleItems, enumItems, recordItems, vtableItems
0746 
0747   def generate(self, file, is_for_demand = 0):
0748     if is_for_demand:
0749       self.generate_type = GEN_DEMAND_BASE
0750     else:
0751       self.generate_type = GEN_FULL
0752     self.file = file
0753     self.do_generate()
0754     self.file = None
0755     self.progress.Finished()
0756 
0757   def do_gen_file_header(self):
0758     la = self.typelib.GetLibAttr()
0759     moduleDoc = self.typelib.GetDocumentation(-1)
0760     docDesc = ""
0761     if moduleDoc[1]:
0762       docDesc = moduleDoc[1]
0763 
0764     # Reset all the 'per file' state
0765     self.bHaveWrittenDispatchBaseClass = 0
0766     self.bHaveWrittenCoClassBaseClass = 0
0767     self.bHaveWrittenEventBaseClass = 0
0768 
0769     # encodings were giving me grief with McMillan's Installer
0770     # until I get to the bottom of this, don't generate
0771     # a coding line when frozen.
0772     if not hasattr(sys, "frozen") and sys.platform.startswith("win"):
0773         print >> self.file, '# -*- coding: mbcs -*-' # Is this always correct?
0774     print >> self.file, '# Created by makepy.py version %s' % (makepy_version,)
0775     print >> self.file, '# By python version %s' % \
0776                         (sys.version.replace("\n", "-"),)
0777     if self.sourceFilename:
0778         print >> self.file, "# From type library '%s'" % (os.path.split(self.sourceFilename)[1],)
0779     print >> self.file, '# On %s' % time.ctime(time.time())
0780 
0781     print >> self.file, '"""' + docDesc + '"""'
0782 
0783     print >> self.file, 'makepy_version =', `makepy_version`
0784     try:
0785         print >> self.file, 'python_version = 0x%x' % (sys.hexversion,)
0786     except AttributeError:
0787         print >> self.file, 'python_version = 0x0 # Presumably Python 1.5.2 - 0x0 is not a problem'
0788     print >> self.file
0789     print >> self.file, 'import win32com.client.CLSIDToClass, pythoncom'
0790     print >> self.file, 'import win32com.client.util'
0791     print >> self.file, 'from pywintypes import IID'
0792     print >> self.file, 'from win32com.client import Dispatch'
0793     print >> self.file
0794     print >> self.file, '# The following 3 lines may need tweaking for the particular server'
0795     print >> self.file, '# Candidates are pythoncom.Missing and pythoncom.Empty'
0796     print >> self.file, 'defaultNamedOptArg=pythoncom.Empty'
0797     print >> self.file, 'defaultNamedNotOptArg=pythoncom.Empty'
0798     print >> self.file, 'defaultUnnamedArg=pythoncom.Empty'
0799     print >> self.file
0800     print >> self.file, 'CLSID = ' + repr(la[0])
0801     print >> self.file, 'MajorVersion = ' + str(la[3])
0802     print >> self.file, 'MinorVersion = ' + str(la[4])
0803     print >> self.file, 'LibraryFlags = ' + str(la[5])
0804     print >> self.file, 'LCID = ' + hex(la[1])
0805     print >> self.file
0806 
0807   def do_generate(self):
0808     moduleDoc = self.typelib.GetDocumentation(-1)
0809     stream = self.file
0810     docDesc = ""
0811     if moduleDoc[1]:
0812       docDesc = moduleDoc[1]
0813     self.progress.Starting(docDesc)
0814     self.progress.SetDescription("Building definitions from type library...")
0815 
0816     self.do_gen_file_header()
0817 
0818     oleItems, enumItems, recordItems, vtableItems = self.BuildOleItemsFromType()
0819 
0820     self.progress.SetDescription("Generating...", len(oleItems)+len(enumItems)+len(vtableItems))
0821 
0822     # Generate the constants and their support.
0823     if enumItems:
0824         print >> stream, "class constants:"
0825         list = enumItems.values()
0826         list.sort()
0827         for oleitem in list:
0828             oleitem.WriteEnumerationItems(stream)
0829             self.progress.Tick()
0830         print >> stream
0831 
0832     if self.generate_type == GEN_FULL:
0833       list = oleItems.values()
0834       list = filter(lambda l: l is not None, list)
0835       list.sort()
0836       for oleitem in list:
0837         self.progress.Tick()
0838         oleitem.WriteClass(self)
0839 
0840       list = vtableItems.values()
0841       list.sort()
0842       for oleitem in list:
0843         self.progress.Tick()
0844         oleitem.WriteClass(self)
0845     else:
0846         self.progress.Tick(len(oleItems)+len(vtableItems))
0847 
0848     print >> stream, 'RecordMap = {'
0849     list = recordItems.values()
0850     for record in list:
0851         if str(record.clsid) == pythoncom.IID_NULL:
0852             print >> stream, "\t###%s: %s, # Typedef disabled because it doesn't have a non-null GUID" % (`record.doc[0]`, `str(record.clsid)`)
0853         else:
0854             print >> stream, "\t%s: %s," % (`record.doc[0]`, `str(record.clsid)`)
0855     print >> stream, "}"
0856     print >> stream
0857 
0858     # Write out _all_ my generated CLSID's in the map
0859     if self.generate_type == GEN_FULL:
0860       print >> stream, 'CLSIDToClassMap = {'
0861       for item in oleItems.values():
0862           if item is not None and item.bWritten:
0863               print >> stream, "\t'%s' : %s," % (str(item.clsid), item.python_name)
0864       print >> stream, '}'
0865       print >> stream, 'CLSIDToPackageMap = {}'
0866       print >> stream, 'win32com.client.CLSIDToClass.RegisterCLSIDsFromDict( CLSIDToClassMap )'
0867       print >> stream, "VTablesToPackageMap = {}"
0868       print >> stream, "VTablesToClassMap = {"
0869       for item in vtableItems.values():
0870         print >> stream, "\t'%s' : '%s'," % (item.clsid,item.python_name)
0871       print >> stream, '}'
0872       print >> stream
0873 
0874     else:
0875       print >> stream, 'CLSIDToClassMap = {}'
0876       print >> stream, 'CLSIDToPackageMap = {'
0877       for item in oleItems.values():
0878         if item is not None:
0879           print >> stream, "\t'%s' : %s," % (str(item.clsid), `item.python_name`)
0880       print >> stream, '}'
0881       print >> stream, "VTablesToClassMap = {}"
0882       print >> stream, "VTablesToPackageMap = {"
0883       for item in vtableItems.values():
0884         print >> stream, "\t'%s' : '%s'," % (item.clsid,item.python_name)
0885       print >> stream, '}'
0886       print >> stream
0887 
0888     print >> stream
0889     # Bit of a hack - build a temp map of iteItems + vtableItems - coClasses
0890     map = {}
0891     for item in oleItems.values():
0892         if item is not None and not isinstance(item, CoClassItem):
0893             map[item.python_name] = item.clsid
0894     for item in vtableItems.values(): # No nones or CoClasses in this map
0895         map[item.python_name] = item.clsid
0896             
0897     print >> stream, "NamesToIIDMap = {"
0898     for name, iid in map.items():
0899         print >> stream, "\t'%s' : '%s'," % (name, iid)
0900     print >> stream, '}'
0901     print >> stream
0902 
0903     if enumItems:
0904       print >> stream, 'win32com.client.constants.__dicts__.append(constants.__dict__)'
0905     print >> stream
0906 
0907   def generate_child(self, child, dir):
0908     "Generate a single child.  May force a few children to be built as we generate deps"
0909     self.generate_type = GEN_DEMAND_CHILD
0910 
0911     la = self.typelib.GetLibAttr()
0912     lcid = la[1]
0913     clsid = la[0]
0914     major=la[3]
0915     minor=la[4]
0916     self.base_mod_name = "win32com.gen_py." + str(clsid)[1:-1] + "x%sx%sx%s" % (lcid, major, minor)
0917     try:
0918       # Process the type library's CoClass objects, looking for the
0919       # specified name, or where a child has the specified name.
0920       # This ensures that all interesting things (including event interfaces)
0921       # are generated correctly.
0922       oleItems = {}
0923       vtableItems = {}
0924       infos = self.CollectOleItemInfosFromType()
0925       found = 0
0926       for type_info_tuple in infos:
0927         info, infotype, doc, attr = type_info_tuple
0928         if infotype == pythoncom.TKIND_COCLASS:
0929             coClassItem, child_infos = self._Build_CoClass(type_info_tuple)
0930             found = build.MakePublicAttributeName(doc[0])==child
0931             if not found:
0932                 # OK, check the child interfaces
0933                 for info, info_type, refType, doc, refAttr, flags in child_infos:
0934                     if build.MakePublicAttributeName(doc[0]) == child:
0935                         found = 1
0936                         break
0937             if found:
0938                 oleItems[coClassItem.clsid] = coClassItem
0939                 self._Build_CoClassChildren(coClassItem, child_infos, oleItems, vtableItems)
0940                 break
0941       if not found:
0942         # Doesn't appear in a class defn - look in the interface objects for it
0943         for type_info_tuple in infos:
0944           info, infotype, doc, attr = type_info_tuple
0945           if infotype in [pythoncom.TKIND_INTERFACE, pythoncom.TKIND_DISPATCH]:
0946             if build.MakePublicAttributeName(doc[0]) == child:
0947               found = 1
0948               oleItem, vtableItem = self._Build_Interface(type_info_tuple)
0949               oleItems[clsid] = oleItem # Even "None" goes in here.
0950               if vtableItem is not None:
0951                 vtableItems[clsid] = vtableItem
0952                 
0953       assert found, "Cant find the '%s' interface in the CoClasses, or the interfaces" % (child,)
0954       # Make a map of iid: dispitem, vtableitem)
0955       items = {}
0956       for key, value in oleItems.items():
0957           items[key] = (value,None)
0958       for key, value in vtableItems.items():
0959           existing = items.get(key, None)
0960           if existing is not None:
0961               new_val = existing[0], value
0962           else:
0963               new_val = None, value
0964           items[key] = new_val
0965 
0966       self.progress.SetDescription("Generating...", len(items))
0967       for oleitem, vtableitem in items.values():
0968         an_item = oleitem or vtableitem
0969         assert not self.file, "already have a file?"
0970         self.file = open(os.path.join(dir, an_item.python_name) + ".py", "w")
0971         try:
0972           if oleitem is not None:
0973             self.do_gen_child_item(oleitem)
0974           if vtableitem is not None:
0975             self.do_gen_child_item(vtableitem)
0976           self.progress.Tick()
0977         finally:
0978           self.file.close()
0979           self.file = None
0980     finally:
0981       self.progress.Finished()
0982 
0983   def do_gen_child_item(self, oleitem):
0984     moduleDoc = self.typelib.GetDocumentation(-1)
0985     docDesc = ""
0986     if moduleDoc[1]:
0987       docDesc = moduleDoc[1]
0988     self.progress.Starting(docDesc)
0989     self.progress.SetDescription("Building definitions from type library...")
0990     self.do_gen_file_header()
0991     oleitem.WriteClass(self)
0992     if oleitem.bWritten:
0993         print >> self.file, 'win32com.client.CLSIDToClass.RegisterCLSID( "%s", %s )' % (oleitem.clsid, oleitem.python_name)
0994 
0995   def checkWriteDispatchBaseClass(self):
0996     if not self.bHaveWrittenDispatchBaseClass:
0997       print >> self.file, "from win32com.client import DispatchBaseClass"
0998       self.bHaveWrittenDispatchBaseClass = 1
0999 
1000   def checkWriteCoClassBaseClass(self):
1001     if not self.bHaveWrittenCoClassBaseClass:
1002       print >> self.file, "from win32com.client import CoClassBaseClass"
1003       self.bHaveWrittenCoClassBaseClass = 1
1004 
1005   def checkWriteEventBaseClass(self):
1006     # Not a base class as such...
1007       if not self.bHaveWrittenEventBaseClass:
1008         # Nothing to do any more!
1009         self.bHaveWrittenEventBaseClass = 1
1010 
1011 if __name__=='__main__':
1012   print "This is a worker module.  Please use makepy to generate Python files."
1013 

Generated by PyXR 0.9.4
SourceForge.net Logo