def WriteEnumerationItems(self, stream): num = 0 enumName = self.doc[0] # Write in name alpha order names = list(self.mapVars.keys()) names.sort() for name in names: entry = self.mapVars[name] vdesc = entry.desc if vdesc[4] == pythoncom.VAR_CONST: val = vdesc[1] if sys.version_info <= (2, 4) and (isinstance(val, int) or isinstance(val, long)): # in python 2.3, 0x80000000L == 2147483648 if val == 2147483648: # == 0x80000000L - special case for 2.3... use = "0x80000000L" # 'L' for future warning elif val > 2147483648 or val < 0: # avoid a FutureWarning use = long(val) else: use = hex(val) else: use = repr(val) print >> stream, "\t%-30s=%-10s # from enum %s" % \ (build.MakePublicAttributeName(name, True), use, enumName) num += 1 return num
def _make_method_(self, name): "Make a method object - Assumes in olerepr funcmap" methodName = build.MakePublicAttributeName( name) # translate keywords etc. methodCodeList = self._olerepr_.MakeFuncMethod( self._olerepr_.mapFuncs[name], methodName, 0) methodCode = "\n".join(methodCodeList) try: # print "Method code for %s is:\n" % self._username_, methodCode # self._print_details_() codeObject = compile(methodCode, "<COMObject %s>" % self._username_, "exec") # Exec the code object tempNameSpace = {} # "Dispatch" in the exec'd code is win32com.client.Dispatch, not ours. globNameSpace = globals().copy() globNameSpace["Dispatch"] = win32com.client.Dispatch exec codeObject in globNameSpace, tempNameSpace # self.__dict__, self.__dict__ name = methodName # Save the function in map. fn = self._builtMethods_[name] = tempNameSpace[name] newMeth = MakeMethod(fn, self, self.__class__) return newMeth except: debug_print("Error building OLE definition for code ", methodCode) traceback.print_exc() return None
def WriteEnumerationItems(self, stream): num = 0 enumName = self.doc[0] # Write in name alpha order names = list(self.mapVars.keys()) names.sort() for name in names: entry = self.mapVars[name] vdesc = entry.desc if vdesc[4] == pythoncom.VAR_CONST: val = vdesc[1] if sys.version_info <= (2,4) and (isinstance(val, int) or isinstance(val, long)): # in python 2.3, 0x80000000L == 2147483648 if val==2147483648: # == 0x80000000L - special case for 2.3... use = "0x80000000L" # 'L' for future warning elif val > 2147483648 or val < 0: # avoid a FutureWarning use = long(val) else: use = hex(val) else: use = repr(val) # Make sure the repr of the value is valid python syntax # still could cause an error on import if it contains a module or type name # not available in the global namespace try: compile(use, '<makepy>', 'eval') except SyntaxError: # At least add the repr as a string, so it can be investigated further # Sanitize it, in case the repr contains its own quotes. (??? line breaks too ???) use = use.replace('"',"'") use = '"' + use + '"' + ' # This VARIANT type cannot be converted automatically' print >> stream, "\t%-30s=%-10s # from enum %s" % \ (build.MakePublicAttributeName(name, True), use, enumName) num += 1 return num
def WriteEnumerationItems(self, stream): enumName = self.doc[0] # Write in name alpha order names = self.mapVars.keys() names.sort() for name in names: entry = self.mapVars[name] vdesc = entry.desc if vdesc[4] == pythoncom.VAR_CONST: val = vdesc[1] if type(val) in (type(0), type(0L)): if val == 0x80000000L: # special case use = "0x80000000L" # 'L' for future warning elif val > 0x80000000L or val < 0: # avoid a FutureWarning use = long(val) else: use = hex(val) else: use = repr(str(val)) print >> stream, "\t%-30s=%-10s # from enum %s" % \ (build.MakePublicAttributeName(name, True), use, enumName)
def WriteClassBody(self, generator): stream = generator.file # Write in alpha order. names = list(self.mapFuncs.keys()) names.sort() specialItems = { "count": None, "item": None, "value": None, "_newenum": None } # If found, will end up with (entry, invoke_tupe) itemCount = None for name in names: entry = self.mapFuncs[name] # skip [restricted] methods, unless it is the # enumerator (which, being part of the "system", # we know about and can use) dispid = entry.desc[0] if entry.desc[9] & pythoncom.FUNCFLAG_FRESTRICTED and \ dispid != pythoncom.DISPID_NEWENUM: continue # If not accessible via IDispatch, then we can't use it here. if entry.desc[3] != pythoncom.FUNC_DISPATCH: continue if dispid == pythoncom.DISPID_VALUE: lkey = "value" elif dispid == pythoncom.DISPID_NEWENUM: specialItems["_newenum"] = (entry, entry.desc[4], None) continue # Dont build this one now! else: lkey = name.lower() if lkey in specialItems and specialItems[ lkey] is None: # remember if a special one. specialItems[lkey] = (entry, entry.desc[4], None) if generator.bBuildHidden or not entry.hidden: if entry.GetResultName(): print >> stream, '\t# Result is of type ' + entry.GetResultName( ) if entry.wasProperty: print >> stream, '\t# The method %s is actually a property, but must be used as a method to correctly pass the arguments' % name ret = self.MakeFuncMethod(entry, build.MakePublicAttributeName(name)) for line in ret: print >> stream, line print >> stream, "\t_prop_map_get_ = {" names = self.propMap.keys() names.sort() for key in names: entry = self.propMap[key] if generator.bBuildHidden or not entry.hidden: resultName = entry.GetResultName() if resultName: print >> stream, "\t\t# Property '%s' is an object of type '%s'" % ( key, resultName) lkey = key.lower() details = entry.desc resultDesc = details[2] argDesc = () mapEntry = MakeMapLineEntry(details[0], pythoncom.DISPATCH_PROPERTYGET, resultDesc, argDesc, key, entry.GetResultCLSIDStr()) if entry.desc[0] == pythoncom.DISPID_VALUE: lkey = "value" elif entry.desc[0] == pythoncom.DISPID_NEWENUM: lkey = "_newenum" else: lkey = key.lower() if lkey in specialItems and specialItems[ lkey] is None: # remember if a special one. specialItems[lkey] = (entry, pythoncom.DISPATCH_PROPERTYGET, mapEntry) # All special methods, except _newenum, are written # "normally". This is a mess! if entry.desc[0] == pythoncom.DISPID_NEWENUM: continue print >> stream, '\t\t"%s": %s,' % ( build.MakePublicAttributeName(key), mapEntry) names = self.propMapGet.keys() names.sort() for key in names: entry = self.propMapGet[key] if generator.bBuildHidden or not entry.hidden: if entry.GetResultName(): print >> stream, "\t\t# Method '%s' returns object of type '%s'" % ( key, entry.GetResultName()) details = entry.desc lkey = key.lower() argDesc = details[2] resultDesc = details[8] mapEntry = MakeMapLineEntry(details[0], pythoncom.DISPATCH_PROPERTYGET, resultDesc, argDesc, key, entry.GetResultCLSIDStr()) if entry.desc[0] == pythoncom.DISPID_VALUE: lkey = "value" elif entry.desc[0] == pythoncom.DISPID_NEWENUM: lkey = "_newenum" else: lkey = key.lower() if lkey in specialItems and specialItems[ lkey] is None: # remember if a special one. specialItems[lkey] = (entry, pythoncom.DISPATCH_PROPERTYGET, mapEntry) # All special methods, except _newenum, are written # "normally". This is a mess! if entry.desc[0] == pythoncom.DISPID_NEWENUM: continue print >> stream, '\t\t"%s": %s,' % ( build.MakePublicAttributeName(key), mapEntry) print >> stream, "\t}" print >> stream, "\t_prop_map_put_ = {" # These are "Invoke" args names = list(self.propMap.keys()) names.sort() for key in names: entry = self.propMap[key] if generator.bBuildHidden or not entry.hidden: lkey = key.lower() details = entry.desc # If default arg is None, write an empty tuple defArgDesc = build.MakeDefaultArgRepr(details[2]) if defArgDesc is None: defArgDesc = "" else: defArgDesc = defArgDesc + "," print >> stream, '\t\t"%s" : ((%s, LCID, %d, 0),(%s)),' % ( build.MakePublicAttributeName(key), details[0], pythoncom.DISPATCH_PROPERTYPUT, defArgDesc) names = list(self.propMapPut.keys()) names.sort() for key in names: entry = self.propMapPut[key] if generator.bBuildHidden or not entry.hidden: details = entry.desc defArgDesc = MakeDefaultArgsForPropertyPut(details[2]) print >> stream, '\t\t"%s": ((%s, LCID, %d, 0),%s),' % ( build.MakePublicAttributeName(key), details[0], details[4], defArgDesc) print >> stream, "\t}" if specialItems["value"]: entry, invoketype, propArgs = specialItems["value"] if propArgs is None: typename = "method" ret = self.MakeFuncMethod(entry, '__call__') else: typename = "property" ret = [ "\tdef __call__(self):\n\t\treturn self._ApplyTypes_(*%s)" % propArgs ] print >> stream, "\t# Default %s for this class is '%s'" % ( typename, entry.names[0]) for line in ret: print >> stream, line if sys.version_info > (3, 0): print >> stream, "\tdef __str__(self, *args):" print >> stream, "\t\treturn str(self.__call__(*args))" else: print >> stream, "\tdef __unicode__(self, *args):" print >> stream, "\t\ttry:" print >> stream, "\t\t\treturn unicode(self.__call__(*args))" print >> stream, "\t\texcept pythoncom.com_error:" print >> stream, "\t\t\treturn repr(self)" print >> stream, "\tdef __str__(self, *args):" print >> stream, "\t\treturn str(self.__unicode__(*args))" print >> stream, "\tdef __int__(self, *args):" print >> stream, "\t\treturn int(self.__call__(*args))" if specialItems["_newenum"]: enumEntry, invoketype, propArgs = specialItems["_newenum"] resultCLSID = enumEntry.GetResultCLSIDStr() # If we dont have a good CLSID for the enum result, assume it is the same as the Item() method. if resultCLSID == "None" and "Item" in self.mapFuncs: resultCLSID = self.mapFuncs["Item"].GetResultCLSIDStr() # "Native" Python iterator support print >> stream, '\tdef __iter__(self):' print >> stream, '\t\t"Return a Python iterator for this object"' print >> stream, '\t\tob = self._oleobj_.InvokeTypes(%d,LCID,%d,(13, 10),())' % ( pythoncom.DISPID_NEWENUM, enumEntry.desc[4]) print >> stream, '\t\treturn win32com.client.util.Iterator(ob, %s)' % resultCLSID # And 'old style' iterator support - magically used to simulate iterators # before Python grew them print >> stream, '\tdef _NewEnum(self):' print >> stream, '\t\t"Create an enumerator from this object"' print >> stream, '\t\treturn win32com.client.util.WrapEnum(self._oleobj_.InvokeTypes(%d,LCID,%d,(13, 10),()),%s)' % ( pythoncom.DISPID_NEWENUM, enumEntry.desc[4], resultCLSID) print >> stream, '\tdef __getitem__(self, index):' print >> stream, '\t\t"Allow this class to be accessed as a collection"' print >> stream, "\t\tif '_enum_' not in self.__dict__:" print >> stream, "\t\t\tself.__dict__['_enum_'] = self._NewEnum()" print >> stream, "\t\treturn self._enum_.__getitem__(index)" else: # Not an Enumerator, but may be an "Item/Count" based collection if specialItems["item"]: entry, invoketype, propArgs = specialItems["item"] print >> stream, '\t#This class has Item property/method which may take args - allow indexed access' print >> stream, '\tdef __getitem__(self, item):' print >> stream, '\t\treturn self._get_good_object_(self._oleobj_.Invoke(*(%d, LCID, %d, 1, item)), "Item")' % ( entry.desc[0], invoketype) if specialItems["count"]: entry, invoketype, propArgs = specialItems["count"] if propArgs is None: typename = "method" ret = self.MakeFuncMethod(entry, '__len__') else: typename = "property" ret = [ "\tdef __len__(self):\n\t\treturn self._ApplyTypes_(*%s)" % propArgs ] print >> stream, "\t#This class has Count() %s - allow len(ob) to provide this" % ( typename) for line in ret: print >> stream, line # Also include a __nonzero__ print >> stream, "\t#This class has a __len__ - this is needed so 'if object:' always returns TRUE." print >> stream, "\tdef __nonzero__(self):" print >> stream, "\t\treturn True"
def generate_child(self, child, dir): "Generate a single child. May force a few children to be built as we generate deps" self.generate_type = GEN_DEMAND_CHILD la = self.typelib.GetLibAttr() lcid = la[1] clsid = la[0] major = la[3] minor = la[4] self.base_mod_name = "win32com.gen_py." + str( clsid)[1:-1] + "x%sx%sx%s" % (lcid, major, minor) try: # Process the type library's CoClass objects, looking for the # specified name, or where a child has the specified name. # This ensures that all interesting things (including event interfaces) # are generated correctly. oleItems = {} vtableItems = {} infos = self.CollectOleItemInfosFromType() found = 0 for type_info_tuple in infos: info, infotype, doc, attr = type_info_tuple if infotype == pythoncom.TKIND_COCLASS: coClassItem, child_infos = self._Build_CoClass( type_info_tuple) found = build.MakePublicAttributeName(doc[0]) == child if not found: # OK, check the child interfaces for info, info_type, refType, doc, refAttr, flags in child_infos: if build.MakePublicAttributeName(doc[0]) == child: found = 1 break if found: oleItems[coClassItem.clsid] = coClassItem self._Build_CoClassChildren(coClassItem, child_infos, oleItems, vtableItems) break if not found: # Doesn't appear in a class defn - look in the interface objects for it for type_info_tuple in infos: info, infotype, doc, attr = type_info_tuple if infotype in [ pythoncom.TKIND_INTERFACE, pythoncom.TKIND_DISPATCH ]: if build.MakePublicAttributeName(doc[0]) == child: found = 1 oleItem, vtableItem = self._Build_Interface( type_info_tuple) oleItems[ clsid] = oleItem # Even "None" goes in here. if vtableItem is not None: vtableItems[clsid] = vtableItem assert found, "Cant find the '%s' interface in the CoClasses, or the interfaces" % ( child, ) # Make a map of iid: dispitem, vtableitem) items = {} for key, value in oleItems.iteritems(): items[key] = (value, None) for key, value in vtableItems.iteritems(): existing = items.get(key, None) if existing is not None: new_val = existing[0], value else: new_val = None, value items[key] = new_val self.progress.SetDescription("Generating...", len(items)) for oleitem, vtableitem in items.itervalues(): an_item = oleitem or vtableitem assert not self.file, "already have a file?" # like makepy.py, we gen to a .temp file so failure doesn't # leave a 1/2 generated mess. out_name = os.path.join(dir, an_item.python_name) + ".py" worked = False self.file = self.open_writer(out_name) try: if oleitem is not None: self.do_gen_child_item(oleitem) if vtableitem is not None: self.do_gen_child_item(vtableitem) self.progress.Tick() worked = True finally: self.finish_writer(out_name, self.file, worked) self.file = None finally: self.progress.Finished()
def WriteClassBody(self, generator): stream = generator.file # Write in alpha order. names = list(self.mapFuncs.keys()) names.sort() specialItems = {"count":None, "item":None,"value":None,"_newenum":None} # If found, will end up with (entry, invoke_tupe) itemCount = None for name in names: entry=self.mapFuncs[name] # skip [restricted] methods, unless it is the # enumerator (which, being part of the "system", # we know about and can use) dispid = entry.desc[0] if entry.desc[9] & pythoncom.FUNCFLAG_FRESTRICTED and \ dispid != pythoncom.DISPID_NEWENUM: continue # If not accessible via IDispatch, then we can't use it here. if entry.desc[3] != pythoncom.FUNC_DISPATCH: continue if dispid==pythoncom.DISPID_VALUE: lkey = "value" elif dispid==pythoncom.DISPID_NEWENUM: specialItems["_newenum"] = (entry, entry.desc[4], None) continue # Dont build this one now! else: lkey = name.lower() if lkey in specialItems and specialItems[lkey] is None: # remember if a special one. specialItems[lkey] = (entry, entry.desc[4], None) if generator.bBuildHidden or not entry.hidden: if entry.GetResultName(): print >> stream, '\t# Result is of type ' + entry.GetResultName() if entry.wasProperty: print >> stream, '\t# The method %s is actually a property, but must be used as a method to correctly pass the arguments' % name ret = self.MakeFuncMethod(entry,build.MakePublicAttributeName(name)) for line in ret: print >> stream, line print >> stream, "\t_prop_map_get_ = {" names = self.propMap.keys(); names.sort() for key in names: entry = self.propMap[key] if generator.bBuildHidden or not entry.hidden: resultName = entry.GetResultName() if resultName: print >> stream, "\t\t# Property '%s' is an object of type '%s'" % (key, resultName) lkey = key.lower() details = entry.desc resultDesc = details[2] argDesc = () mapEntry = MakeMapLineEntry(details[0], pythoncom.DISPATCH_PROPERTYGET, resultDesc, argDesc, key, entry.GetResultCLSIDStr()) if entry.desc[0]==pythoncom.DISPID_VALUE: lkey = "value" elif entry.desc[0]==pythoncom.DISPID_NEWENUM: lkey = "_newenum" else: lkey = key.lower() if lkey in specialItems and specialItems[lkey] is None: # remember if a special one. specialItems[lkey] = (entry, pythoncom.DISPATCH_PROPERTYGET, mapEntry) # All special methods, except _newenum, are written # "normally". This is a mess! if entry.desc[0]==pythoncom.DISPID_NEWENUM: continue print >> stream, '\t\t"%s": %s,' % (build.MakePublicAttributeName(key), mapEntry) names = self.propMapGet.keys(); names.sort() for key in names: entry = self.propMapGet[key] if generator.bBuildHidden or not entry.hidden: if entry.GetResultName(): print >> stream, "\t\t# Method '%s' returns object of type '%s'" % (key, entry.GetResultName()) details = entry.desc lkey = key.lower() argDesc = details[2] resultDesc = details[8] mapEntry = MakeMapLineEntry(details[0], pythoncom.DISPATCH_PROPERTYGET, resultDesc, argDesc, key, entry.GetResultCLSIDStr()) if entry.desc[0]==pythoncom.DISPID_VALUE: lkey = "value" elif entry.desc[0]==pythoncom.DISPID_NEWENUM: lkey = "_newenum" else: lkey = key.lower() if lkey in specialItems and specialItems[lkey] is None: # remember if a special one. specialItems[lkey]=(entry, pythoncom.DISPATCH_PROPERTYGET, mapEntry) # All special methods, except _newenum, are written # "normally". This is a mess! if entry.desc[0]==pythoncom.DISPID_NEWENUM: continue print >> stream, '\t\t"%s": %s,' % (build.MakePublicAttributeName(key), mapEntry) print >> stream, "\t}" print >> stream, "\t_prop_map_put_ = {" # These are "Invoke" args names = list(self.propMap.keys()); names.sort() for key in names: entry = self.propMap[key] if generator.bBuildHidden or not entry.hidden: lkey=key.lower() details = entry.desc # If default arg is None, write an empty tuple defArgDesc = build.MakeDefaultArgRepr(details[2]) if defArgDesc is None: defArgDesc = "" else: defArgDesc = defArgDesc + "," print >> stream, '\t\t"%s" : ((%s, LCID, %d, 0),(%s)),' % (build.MakePublicAttributeName(key), details[0], pythoncom.DISPATCH_PROPERTYPUT, defArgDesc) names = list(self.propMapPut.keys()); names.sort() for key in names: entry = self.propMapPut[key] if generator.bBuildHidden or not entry.hidden: details = entry.desc defArgDesc = MakeDefaultArgsForPropertyPut(details[2]) print >> stream, '\t\t"%s": ((%s, LCID, %d, 0),%s),' % (build.MakePublicAttributeName(key), details[0], details[4], defArgDesc) print >> stream, "\t}" if specialItems["value"]: entry, invoketype, propArgs = specialItems["value"] if propArgs is None: typename = "method" ret = self.MakeFuncMethod(entry,'__call__') else: typename = "property" ret = [ "\tdef __call__(self):\n\t\treturn self._ApplyTypes_(*%s)" % propArgs] print >> stream, "\t# Default %s for this class is '%s'" % (typename, entry.names[0]) for line in ret: print >> stream, line if sys.version_info > (3,0): print >> stream, "\tdef __str__(self, *args):" print >> stream, "\t\treturn str(self.__call__(*args))" else: print >> stream, "\tdef __unicode__(self, *args):" print >> stream, "\t\ttry:" print >> stream, "\t\t\treturn unicode(self.__call__(*args))" print >> stream, "\t\texcept pythoncom.com_error:" print >> stream, "\t\t\treturn repr(self)" print >> stream, "\tdef __str__(self, *args):" print >> stream, "\t\treturn str(self.__unicode__(*args))" print >> stream, "\tdef __int__(self, *args):" print >> stream, "\t\treturn int(self.__call__(*args))" # _NewEnum (DISPID_NEWENUM) does not appear in typelib for many office objects, # but it can still be retrieved at runtime, so always create __iter__. # Also, some of those same objects use 1-based indexing, causing the old-style # __getitem__ iteration to fail for index 0 where the dynamic iteration succeeds. if specialItems["_newenum"]: enumEntry, invoketype, propArgs = specialItems["_newenum"] invkind = enumEntry.desc[4] # ??? Wouldn't this be the resultCLSID for the iterator itself, rather than the resultCLSID # for the result of each Next() call, which is what it's used for ??? resultCLSID = enumEntry.GetResultCLSIDStr() else: invkind = pythoncom.DISPATCH_METHOD | pythoncom.DISPATCH_PROPERTYGET resultCLSID = "None" # If we dont have a good CLSID for the enum result, assume it is the same as the Item() method. if resultCLSID == "None" and "Item" in self.mapFuncs: resultCLSID = self.mapFuncs["Item"].GetResultCLSIDStr() print >> stream, '\tdef __iter__(self):' print >> stream, '\t\t"Return a Python iterator for this object"' print >> stream, '\t\ttry:' print >> stream, '\t\t\tob = self._oleobj_.InvokeTypes(%d,LCID,%d,(13, 10),())' % (pythoncom.DISPID_NEWENUM, invkind) print >> stream, '\t\texcept pythoncom.error:' print >> stream, '\t\t\traise TypeError("This object does not support enumeration")' # Iterator is wrapped as PyIEnumVariant, and each result of __next__ is Dispatch'ed if necessary print >> stream, '\t\treturn win32com.client.util.Iterator(ob, %s)' %resultCLSID if specialItems["item"]: entry, invoketype, propArgs = specialItems["item"] resultCLSID = entry.GetResultCLSIDStr() print >> stream, '\t#This class has Item property/method which allows indexed access with the object[key] syntax.' print >> stream, '\t#Some objects will accept a string or other type of key in addition to integers.' print >> stream, '\t#Note that many Office objects do not use zero-based indexing.' print >> stream, '\tdef __getitem__(self, key):' print >> stream, '\t\treturn self._get_good_object_(self._oleobj_.Invoke(*(%d, LCID, %d, 1, key)), "Item", %s)' \ % (entry.desc[0], invoketype, resultCLSID) if specialItems["count"]: entry, invoketype, propArgs = specialItems["count"] if propArgs is None: typename = "method" ret = self.MakeFuncMethod(entry,'__len__') else: typename = "property" ret = [ "\tdef __len__(self):\n\t\treturn self._ApplyTypes_(*%s)" % propArgs] print >> stream, "\t#This class has Count() %s - allow len(ob) to provide this" % (typename) for line in ret: print >> stream, line # Also include a __nonzero__ print >> stream, "\t#This class has a __len__ - this is needed so 'if object:' always returns TRUE." print >> stream, "\tdef __nonzero__(self):" print >> stream, "\t\treturn True"