0001 """Manages the cache of generated Python code. 0002 0003 Description 0004 This file manages the cache of generated Python code. When run from the 0005 command line, it also provides a number of options for managing that cache. 0006 0007 Implementation 0008 Each typelib is generated into a filename of format "{guid}x{lcid}x{major}x{minor}.py" 0009 0010 An external persistant dictionary maps from all known IIDs in all known type libraries 0011 to the type library itself. 0012 0013 Thus, whenever Python code knows the IID of an object, it can find the IID, LCID and version of 0014 the type library which supports it. Given this information, it can find the Python module 0015 with the support. 0016 0017 If necessary, this support can be generated on the fly. 0018 0019 Hacks, to do, etc 0020 Currently just uses a pickled dictionary, but should used some sort of indexed file. 0021 Maybe an OLE2 compound file, or a bsddb file? 0022 """ 0023 import pywintypes, os, string, sys 0024 import pythoncom 0025 import win32com, win32com.client 0026 import glob 0027 import traceback 0028 import CLSIDToClass 0029 import operator 0030 0031 bForDemandDefault = 0 # Default value of bForDemand - toggle this to change the world - see also makepy.py 0032 0033 # The global dictionary 0034 clsidToTypelib = {} 0035 0036 # If we have a different version of the typelib generated, this 0037 # maps the "requested version" to the "generated version". 0038 versionRedirectMap = {} 0039 0040 # There is no reason we *must* be readonly in a .zip, but we are now, 0041 # Rather than check for ".zip" or other tricks, PEP302 defines 0042 # a "__loader__" attribute, so we use that. 0043 # (Later, it may become necessary to check if the __loader__ can update files, 0044 # as a .zip loader potentially could - but punt all that until a need arises) 0045 is_readonly = hasattr(win32com, "__loader__") 0046 0047 # A dictionary of ITypeLibrary objects for demand generation explicitly handed to us 0048 # Keyed by usual clsid, lcid, major, minor 0049 demandGeneratedTypeLibraries = {} 0050 0051 def __init__(): 0052 # Initialize the module. Called once explicitly at module import below. 0053 try: 0054 _LoadDicts() 0055 except IOError: 0056 Rebuild() 0057 0058 pickleVersion = 1 0059 def _SaveDicts(): 0060 if is_readonly: 0061 raise RuntimeError, "Trying to write to a readonly gencache ('%s')!" \ 0062 % win32com.__gen_path__ 0063 import cPickle 0064 f = open(os.path.join(GetGeneratePath(), "dicts.dat"), "wb") 0065 try: 0066 p = cPickle.Pickler(f) 0067 p.dump(pickleVersion) 0068 p.dump(clsidToTypelib) 0069 finally: 0070 f.close() 0071 0072 def _LoadDicts(): 0073 import cPickle 0074 # Load the dictionary from a .zip file if that is where we live. 0075 if hasattr(win32com, "__loader__"): 0076 import cStringIO 0077 loader = win32com.__loader__ 0078 arc_path = loader.archive 0079 dicts_path = os.path.join(win32com.__gen_path__, "dicts.dat") 0080 if dicts_path.startswith(arc_path): 0081 dicts_path = dicts_path[len(arc_path)+1:] 0082 else: 0083 # Hm. See below. 0084 return 0085 try: 0086 data = loader.get_data(dicts_path) 0087 except AttributeError: 0088 # The __loader__ has no get_data method. See below. 0089 return 0090 except IOError: 0091 # Our gencache is in a .zip file (and almost certainly readonly) 0092 # but no dicts file. That actually needn't be fatal for a frozen 0093 # application. Assuming they call "EnsureModule" with the same 0094 # typelib IDs they have been frozen with, that EnsureModule will 0095 # correctly re-build the dicts on the fly. However, objects that 0096 # rely on the gencache but have not done an EnsureModule will 0097 # fail (but their apps are likely to fail running from source 0098 # with a clean gencache anyway, as then they would be getting 0099 # Dynamic objects until the cache is built - so the best answer 0100 # for these apps is to call EnsureModule, rather than freezing 0101 # the dict) 0102 return 0103 f = cStringIO.StringIO(data) 0104 else: 0105 # NOTE: IOError on file open must be caught by caller. 0106 f = open(os.path.join(win32com.__gen_path__, "dicts.dat"), "rb") 0107 try: 0108 p = cPickle.Unpickler(f) 0109 version = p.load() 0110 global clsidToTypelib 0111 clsidToTypelib = p.load() 0112 versionRedirectMap.clear() 0113 finally: 0114 f.close() 0115 0116 def GetGeneratedFileName(clsid, lcid, major, minor): 0117 """Given the clsid, lcid, major and minor for a type lib, return 0118 the file name (no extension) providing this support. 0119 """ 0120 return string.upper(str(clsid))[1:-1] + "x%sx%sx%s" % (lcid, major, minor) 0121 0122 def SplitGeneratedFileName(fname): 0123 """Reverse of GetGeneratedFileName() 0124 """ 0125 return tuple(string.split(fname,'x',4)) 0126 0127 def GetGeneratePath(): 0128 """Returns the name of the path to generate to. 0129 Checks the directory is OK. 0130 """ 0131 assert not is_readonly, "Why do you want the genpath for a readonly store?" 0132 try: 0133 os.makedirs(win32com.__gen_path__) 0134 #os.mkdir(win32com.__gen_path__) 0135 except os.error: 0136 pass 0137 try: 0138 fname = os.path.join(win32com.__gen_path__, "__init__.py") 0139 os.stat(fname) 0140 except os.error: 0141 f = open(fname,"w") 0142 f.write('# Generated file - this directory may be deleted to reset the COM cache...\n') 0143 f.write('import win32com\n') 0144 f.write('if __path__[:-1] != win32com.__gen_path__: __path__.append(win32com.__gen_path__)\n') 0145 f.close() 0146 0147 return win32com.__gen_path__ 0148 0149 # 0150 # The helpers for win32com.client.Dispatch and OCX clients. 0151 # 0152 def GetClassForProgID(progid): 0153 """Get a Python class for a Program ID 0154 0155 Given a Program ID, return a Python class which wraps the COM object 0156 0157 Returns the Python class, or None if no module is available. 0158 0159 Params 0160 progid -- A COM ProgramID or IID (eg, "Word.Application") 0161 """ 0162 clsid = pywintypes.IID(progid) # This auto-converts named to IDs. 0163 return GetClassForCLSID(clsid) 0164 0165 def GetClassForCLSID(clsid): 0166 """Get a Python class for a CLSID 0167 0168 Given a CLSID, return a Python class which wraps the COM object 0169 0170 Returns the Python class, or None if no module is available. 0171 0172 Params 0173 clsid -- A COM CLSID (or string repr of one) 0174 """ 0175 # first, take a short-cut - we may already have generated support ready-to-roll. 0176 clsid = str(clsid) 0177 if CLSIDToClass.HasClass(clsid): 0178 return CLSIDToClass.GetClass(clsid) 0179 mod = GetModuleForCLSID(clsid) 0180 if mod is None: 0181 return None 0182 try: 0183 return CLSIDToClass.GetClass(clsid) 0184 except KeyError: 0185 return None 0186 0187 def GetModuleForProgID(progid): 0188 """Get a Python module for a Program ID 0189 0190 Given a Program ID, return a Python module which contains the 0191 class which wraps the COM object. 0192 0193 Returns the Python module, or None if no module is available. 0194 0195 Params 0196 progid -- A COM ProgramID or IID (eg, "Word.Application") 0197 """ 0198 try: 0199 iid = pywintypes.IID(progid) 0200 except pywintypes.com_error: 0201 return None 0202 return GetModuleForCLSID(iid) 0203 0204 def GetModuleForCLSID(clsid): 0205 """Get a Python module for a CLSID 0206 0207 Given a CLSID, return a Python module which contains the 0208 class which wraps the COM object. 0209 0210 Returns the Python module, or None if no module is available. 0211 0212 Params 0213 progid -- A COM CLSID (ie, not the description) 0214 """ 0215 clsid_str = str(clsid) 0216 try: 0217 typelibCLSID, lcid, major, minor = clsidToTypelib[clsid_str] 0218 except KeyError: 0219 return None 0220 0221 try: 0222 mod = GetModuleForTypelib(typelibCLSID, lcid, major, minor) 0223 except ImportError: 0224 mod = None 0225 if mod is not None: 0226 sub_mod = mod.CLSIDToPackageMap.get(clsid_str) 0227 if sub_mod is None: 0228 sub_mod = mod.VTablesToPackageMap.get(clsid_str) 0229 if sub_mod is not None: 0230 sub_mod_name = mod.__name__ + "." + sub_mod 0231 try: 0232 __import__(sub_mod_name) 0233 except ImportError: 0234 info = typelibCLSID, lcid, major, minor 0235 # Force the generation. If this typelibrary has explicitly been added, 0236 # use it (it may not be registered, causing a lookup by clsid to fail) 0237 if demandGeneratedTypeLibraries.has_key(info): 0238 info = demandGeneratedTypeLibraries[info] 0239 import makepy 0240 makepy.GenerateChildFromTypeLibSpec(sub_mod, info) 0241 # Generate does an import... 0242 mod = sys.modules[sub_mod_name] 0243 return mod 0244 0245 def GetModuleForTypelib(typelibCLSID, lcid, major, minor): 0246 """Get a Python module for a type library ID 0247 0248 Given the CLSID of a typelibrary, return an imported Python module, 0249 else None 0250 0251 Params 0252 typelibCLSID -- IID of the type library. 0253 major -- Integer major version. 0254 minor -- Integer minor version 0255 lcid -- Integer LCID for the library. 0256 """ 0257 modName = GetGeneratedFileName(typelibCLSID, lcid, major, minor) 0258 mod = _GetModule(modName) 0259 # If the import worked, it doesn't mean we have actually added this 0260 # module to our cache though - check that here. 0261 if not mod.__dict__.has_key("_in_gencache_"): 0262 AddModuleToCache(typelibCLSID, lcid, major, minor) 0263 assert mod.__dict__.has_key("_in_gencache_") 0264 return mod 0265 0266 def MakeModuleForTypelib(typelibCLSID, lcid, major, minor, progressInstance = None, bGUIProgress = None, bForDemand = bForDemandDefault, bBuildHidden = 1): 0267 """Generate support for a type library. 0268 0269 Given the IID, LCID and version information for a type library, generate 0270 and import the necessary support files. 0271 0272 Returns the Python module. No exceptions are caught. 0273 0274 Params 0275 typelibCLSID -- IID of the type library. 0276 major -- Integer major version. 0277 minor -- Integer minor version. 0278 lcid -- Integer LCID for the library. 0279 progressInstance -- Instance to use as progress indicator, or None to 0280 use the GUI progress bar. 0281 """ 0282 if bGUIProgress is not None: 0283 print "The 'bGuiProgress' param to 'MakeModuleForTypelib' is obsolete." 0284 0285 import makepy 0286 try: 0287 makepy.GenerateFromTypeLibSpec( (typelibCLSID, lcid, major, minor), progressInstance=progressInstance, bForDemand = bForDemand, bBuildHidden = bBuildHidden) 0288 except pywintypes.com_error: 0289 return None 0290 return GetModuleForTypelib(typelibCLSID, lcid, major, minor) 0291 0292 def MakeModuleForTypelibInterface(typelib_ob, progressInstance = None, bForDemand = bForDemandDefault, bBuildHidden = 1): 0293 """Generate support for a type library. 0294 0295 Given a PyITypeLib interface generate and import the necessary support files. This is useful 0296 for getting makepy support for a typelibrary that is not registered - the caller can locate 0297 and load the type library itself, rather than relying on COM to find it. 0298 0299 Returns the Python module. 0300 0301 Params 0302 typelib_ob -- The type library itself 0303 progressInstance -- Instance to use as progress indicator, or None to 0304 use the GUI progress bar. 0305 """ 0306 import makepy 0307 try: 0308 makepy.GenerateFromTypeLibSpec( typelib_ob, progressInstance=progressInstance, bForDemand = bForDemandDefault, bBuildHidden = bBuildHidden) 0309 except pywintypes.com_error: 0310 return None 0311 tla = typelib_ob.GetLibAttr() 0312 guid = tla[0] 0313 lcid = tla[1] 0314 major = tla[3] 0315 minor = tla[4] 0316 return GetModuleForTypelib(guid, lcid, major, minor) 0317 0318 def EnsureModuleForTypelibInterface(typelib_ob, progressInstance = None, bForDemand = bForDemandDefault, bBuildHidden = 1): 0319 """Check we have support for a type library, generating if not. 0320 0321 Given a PyITypeLib interface generate and import the necessary 0322 support files if necessary. This is useful for getting makepy support 0323 for a typelibrary that is not registered - the caller can locate and 0324 load the type library itself, rather than relying on COM to find it. 0325 0326 Returns the Python module. 0327 0328 Params 0329 typelib_ob -- The type library itself 0330 progressInstance -- Instance to use as progress indicator, or None to 0331 use the GUI progress bar. 0332 """ 0333 tla = typelib_ob.GetLibAttr() 0334 guid = tla[0] 0335 lcid = tla[1] 0336 major = tla[3] 0337 minor = tla[4] 0338 0339 #If demand generated, save the typelib interface away for later use 0340 if bForDemand: 0341 demandGeneratedTypeLibraries[(str(guid), lcid, major, minor)] = typelib_ob 0342 0343 try: 0344 return GetModuleForTypelib(guid, lcid, major, minor) 0345 except ImportError: 0346 pass 0347 # Generate it. 0348 return MakeModuleForTypelibInterface(typelib_ob, progressInstance, bForDemand, bBuildHidden) 0349 0350 def ForgetAboutTypelibInterface(typelib_ob): 0351 """Drop any references to a typelib previously added with EnsureModuleForTypelibInterface and forDemand""" 0352 tla = typelib_ob.GetLibAttr() 0353 guid = tla[0] 0354 lcid = tla[1] 0355 major = tla[3] 0356 minor = tla[4] 0357 info = str(guid), lcid, major, minor 0358 try: 0359 del demandGeneratedTypeLibraries[info] 0360 except KeyError: 0361 # Not worth raising an exception - maybe they dont know we only remember for demand generated, etc. 0362 print "ForgetAboutTypelibInterface:: Warning - type library with info %s is not being remembered!" % (info,) 0363 # and drop any version redirects to it 0364 for key, val in versionRedirectMap.items(): 0365 if val==info: 0366 del versionRedirectMap[key] 0367 0368 def EnsureModule(typelibCLSID, lcid, major, minor, progressInstance = None, bValidateFile=not is_readonly, bForDemand = bForDemandDefault, bBuildHidden = 1): 0369 """Ensure Python support is loaded for a type library, generating if necessary. 0370 0371 Given the IID, LCID and version information for a type library, check and if 0372 necessary (re)generate, then import the necessary support files. If we regenerate the file, there 0373 is no way to totally snuff out all instances of the old module in Python, and thus we will regenerate the file more than necessary, 0374 unless makepy/genpy is modified accordingly. 0375 0376 0377 Returns the Python module. No exceptions are caught during the generate process. 0378 0379 Params 0380 typelibCLSID -- IID of the type library. 0381 major -- Integer major version. 0382 minor -- Integer minor version 0383 lcid -- Integer LCID for the library. 0384 progressInstance -- Instance to use as progress indicator, or None to 0385 use the GUI progress bar. 0386 bValidateFile -- Whether or not to perform cache validation or not 0387 bForDemand -- Should a complete generation happen now, or on demand? 0388 bBuildHidden -- Should hidden members/attributes etc be generated? 0389 """ 0390 bReloadNeeded = 0 0391 try: 0392 try: 0393 module = GetModuleForTypelib(typelibCLSID, lcid, major, minor) 0394 except ImportError: 0395 # If we get an ImportError 0396 # We may still find a valid cache file under a different MinorVersion # 0397 # (which windows will search out for us) 0398 #print "Loading reg typelib", typelibCLSID, major, minor, lcid 0399 module = None 0400 try: 0401 tlbAttr = pythoncom.LoadRegTypeLib(typelibCLSID, major, minor, lcid).GetLibAttr() 0402 # if the above line doesn't throw a pythoncom.com_error, check if 0403 # it is actually a different lib than we requested, and if so, suck it in 0404 if tlbAttr[1] != lcid or tlbAttr[4]!=minor: 0405 #print "Trying 2nd minor #", tlbAttr[1], tlbAttr[3], tlbAttr[4] 0406 try: 0407 module = GetModuleForTypelib(typelibCLSID, tlbAttr[1], tlbAttr[3], tlbAttr[4]) 0408 except ImportError: 0409 # We don't have a module, but we do have a better minor 0410 # version - remember that. 0411 minor = tlbAttr[4] 0412 # else module remains None 0413 except pythoncom.com_error: 0414 # couldn't load any typelib - mod remains None 0415 pass 0416 if module is not None and bValidateFile: 0417 assert not is_readonly, "Can't validate in a read-only gencache" 0418 try: 0419 typLibPath = pythoncom.QueryPathOfRegTypeLib(typelibCLSID, major, minor, lcid) 0420 # windows seems to add an extra \0 (via the underlying BSTR) 0421 # The mainwin toolkit does not add this erroneous \0 0422 if typLibPath[-1]=='\0': 0423 typLibPath=typLibPath[:-1] 0424 suf = getattr(os.path, "supports_unicode_filenames", 0) 0425 if not suf: 0426 # can't pass unicode filenames directly - convert 0427 try: 0428 typLibPath=typLibPath.encode(sys.getfilesystemencoding()) 0429 except AttributeError: # no sys.getfilesystemencoding 0430 typLibPath=str(typLibPath) 0431 tlbAttributes = pythoncom.LoadRegTypeLib(typelibCLSID, major, minor, lcid).GetLibAttr() 0432 except pythoncom.com_error: 0433 # We have a module, but no type lib - we should still 0434 # run with what we have though - the typelib may not be 0435 # deployed here. 0436 bValidateFile = 0 0437 if module is not None and bValidateFile: 0438 assert not is_readonly, "Can't validate in a read-only gencache" 0439 filePathPrefix = "%s\\%s" % (GetGeneratePath(), GetGeneratedFileName(typelibCLSID, lcid, major, minor)) 0440 filePath = filePathPrefix + ".py" 0441 filePathPyc = filePathPrefix + ".py" 0442 if __debug__: 0443 filePathPyc = filePathPyc + "c" 0444 else: 0445 filePathPyc = filePathPyc + "o" 0446 # Verify that type library is up to date. 0447 # If we have a differing MinorVersion or genpy has bumped versions, update the file 0448 import genpy 0449 if module.MinorVersion != tlbAttributes[4] or genpy.makepy_version != module.makepy_version: 0450 #print "Version skew: %d, %d" % (module.MinorVersion, tlbAttributes[4]) 0451 # try to erase the bad file from the cache 0452 try: 0453 os.unlink(filePath) 0454 except os.error: 0455 pass 0456 try: 0457 os.unlink(filePathPyc) 0458 except os.error: 0459 pass 0460 if os.path.isdir(filePathPrefix): 0461 import shutil 0462 shutil.rmtree(filePathPrefix) 0463 minor = tlbAttributes[4] 0464 module = None 0465 bReloadNeeded = 1 0466 else: 0467 minor = module.MinorVersion 0468 filePathPrefix = "%s\\%s" % (GetGeneratePath(), GetGeneratedFileName(typelibCLSID, lcid, major, minor)) 0469 filePath = filePathPrefix + ".py" 0470 filePathPyc = filePathPrefix + ".pyc" 0471 #print "Trying py stat: ", filePath 0472 fModTimeSet = 0 0473 try: 0474 pyModTime = os.stat(filePath)[8] 0475 fModTimeSet = 1 0476 except os.error, e: 0477 # If .py file fails, try .pyc file 0478 #print "Trying pyc stat", filePathPyc 0479 try: 0480 pyModTime = os.stat(filePathPyc)[8] 0481 fModTimeSet = 1 0482 except os.error, e: 0483 pass 0484 #print "Trying stat typelib", pyModTime 0485 #print str(typLibPath) 0486 typLibModTime = os.stat(typLibPath)[8] 0487 if fModTimeSet and (typLibModTime > pyModTime): 0488 bReloadNeeded = 1 0489 module = None 0490 except (ImportError, os.error): 0491 module = None 0492 if module is None: 0493 # We need to build an item. If we are in a read-only cache, we 0494 # can't/don't want to do this - so before giving up, check for 0495 # a different minor version in our cache - according to COM, this is OK 0496 if is_readonly: 0497 key = str(typelibCLSID), lcid, major, minor 0498 # If we have been asked before, get last result. 0499 try: 0500 return versionRedirectMap[key] 0501 except KeyError: 0502 pass 0503 # Find other candidates. 0504 items = [] 0505 for desc in GetGeneratedInfos(): 0506 if key[0]==desc[0] and key[1]==desc[1] and key[2]==desc[2]: 0507 items.append(desc) 0508 if items: 0509 # Items are all identical, except for last tuple element 0510 # We want the latest minor version we have - so just sort and grab last 0511 items.sort() 0512 new_minor = items[-1][3] 0513 ret = GetModuleForTypelib(typelibCLSID, lcid, major, new_minor) 0514 else: 0515 ret = None 0516 # remember and return 0517 versionRedirectMap[key] = ret 0518 return ret 0519 #print "Rebuilding: ", major, minor 0520 module = MakeModuleForTypelib(typelibCLSID, lcid, major, minor, progressInstance, bForDemand = bForDemand, bBuildHidden = bBuildHidden) 0521 # If we replaced something, reload it 0522 if bReloadNeeded: 0523 module = reload(module) 0524 AddModuleToCache(typelibCLSID, lcid, major, minor) 0525 return module 0526 0527 def EnsureDispatch(prog_id, bForDemand = 1): # New fn, so we default the new demand feature to on! 0528 """Given a COM prog_id, return an object that is using makepy support, building if necessary""" 0529 disp = win32com.client.Dispatch(prog_id) 0530 if not disp.__dict__.get("CLSID"): # Eeek - no makepy support - try and build it. 0531 try: 0532 ti = disp._oleobj_.GetTypeInfo() 0533 disp_clsid = ti.GetTypeAttr()[0] 0534 tlb, index = ti.GetContainingTypeLib() 0535 tla = tlb.GetLibAttr() 0536 mod = EnsureModule(tla[0], tla[1], tla[3], tla[4], bForDemand=bForDemand) 0537 GetModuleForCLSID(disp_clsid) 0538 # Get the class from the module. 0539 import CLSIDToClass 0540 disp_class = CLSIDToClass.GetClass(str(disp_clsid)) 0541 disp = disp_class(disp._oleobj_) 0542 except pythoncom.com_error: 0543 raise TypeError, "This COM object can not automate the makepy process - please run makepy manually for this object" 0544 return disp 0545 0546 def AddModuleToCache(typelibclsid, lcid, major, minor, verbose = 1, bFlushNow = not is_readonly): 0547 """Add a newly generated file to the cache dictionary. 0548 """ 0549 fname = GetGeneratedFileName(typelibclsid, lcid, major, minor) 0550 mod = _GetModule(fname) 0551 # if mod._in_gencache_ is already true, then we are reloading this 0552 # module - this doesn't mean anything special though! 0553 mod._in_gencache_ = 1 0554 dict = mod.CLSIDToClassMap 0555 info = str(typelibclsid), lcid, major, minor 0556 for clsid, cls in dict.items(): 0557 clsidToTypelib[clsid] = info 0558 0559 dict = mod.CLSIDToPackageMap 0560 for clsid, name in dict.items(): 0561 clsidToTypelib[clsid] = info 0562 0563 dict = mod.VTablesToClassMap 0564 for clsid, cls in dict.items(): 0565 clsidToTypelib[clsid] = info 0566 0567 dict = mod.VTablesToPackageMap 0568 for clsid, cls in dict.items(): 0569 clsidToTypelib[clsid] = info 0570 0571 # If this lib was previously redirected, drop it 0572 if versionRedirectMap.has_key(info): 0573 del versionRedirectMap[info] 0574 if bFlushNow: 0575 _SaveDicts() 0576 0577 def GetGeneratedInfos(): 0578 zip_pos = win32com.__gen_path__.find(".zip\\") 0579 if zip_pos >= 0: 0580 import zipfile, cStringIO 0581 zip_file = win32com.__gen_path__[:zip_pos+4] 0582 zip_path = win32com.__gen_path__[zip_pos+5:].replace("\\", "/") 0583 zf = zipfile.ZipFile(zip_file) 0584 infos = {} 0585 for n in zf.namelist(): 0586 if not n.startswith(zip_path): 0587 continue 0588 base = n[len(zip_path)+1:].split("/")[0] 0589 try: 0590 iid, lcid, major, minor = base.split("x") 0591 lcid = int(lcid) 0592 major = int(major) 0593 minor = int(minor) 0594 iid = pywintypes.IID("{" + iid + "}") 0595 except ValueError: 0596 continue 0597 except pywintypes.com_error: 0598 # invalid IID 0599 continue 0600 infos[(iid, lcid, major, minor)] = 1 0601 zf.close() 0602 return infos.keys() 0603 else: 0604 # on the file system 0605 files = glob.glob(win32com.__gen_path__+ "\\*") 0606 ret = [] 0607 for file in files: 0608 if not os.path.isdir(file) and not os.path.splitext(file)==".py": 0609 continue 0610 name = os.path.splitext(os.path.split(file)[1])[0] 0611 try: 0612 iid, lcid, major, minor = string.split(name, "x") 0613 iid = pywintypes.IID("{" + iid + "}") 0614 lcid = int(lcid) 0615 major = int(major) 0616 minor = int(minor) 0617 except ValueError: 0618 continue 0619 except pywintypes.com_error: 0620 # invalid IID 0621 continue 0622 ret.append((iid, lcid, major, minor)) 0623 return ret 0624 0625 def _GetModule(fname): 0626 """Given the name of a module in the gen_py directory, import and return it. 0627 """ 0628 mod_name = "win32com.gen_py.%s" % fname 0629 mod = __import__(mod_name) 0630 return sys.modules[mod_name] 0631 0632 def Rebuild(verbose = 1): 0633 """Rebuild the cache indexes from the file system. 0634 """ 0635 clsidToTypelib.clear() 0636 infos = GetGeneratedInfos() 0637 if verbose and len(infos): # Dont bother reporting this when directory is empty! 0638 print "Rebuilding cache of generated files for COM support..." 0639 for info in infos: 0640 iid, lcid, major, minor = info 0641 if verbose: 0642 print "Checking", GetGeneratedFileName(*info) 0643 try: 0644 AddModuleToCache(iid, lcid, major, minor, verbose, 0) 0645 except: 0646 print "Could not add module %s - %s: %s" % (info, sys.exc_info()[0],sys.exc_info()[1]) 0647 if verbose and len(infos): # Dont bother reporting this when directory is empty! 0648 print "Done." 0649 _SaveDicts() 0650 0651 def _Dump(): 0652 print "Cache is in directory", win32com.__gen_path__ 0653 # Build a unique dir 0654 d = {} 0655 for clsid, (typelibCLSID, lcid, major, minor) in clsidToTypelib.items(): 0656 d[typelibCLSID, lcid, major, minor] = None 0657 for typelibCLSID, lcid, major, minor in d.keys(): 0658 mod = GetModuleForTypelib(typelibCLSID, lcid, major, minor) 0659 print "%s - %s" % (mod.__doc__, typelibCLSID) 0660 0661 # Boot up 0662 __init__() 0663 0664 def usage(): 0665 usageString = """\ 0666 Usage: gencache [-q] [-d] [-r] 0667 0668 -q - Quiet 0669 -d - Dump the cache (typelibrary description and filename). 0670 -r - Rebuild the cache dictionary from the existing .py files 0671 """ 0672 print usageString 0673 sys.exit(1) 0674 0675 if __name__=='__main__': 0676 import getopt 0677 try: 0678 opts, args = getopt.getopt(sys.argv[1:], "qrd") 0679 except getopt.error, message: 0680 print message 0681 usage() 0682 0683 # we only have options - complain about real args, or none at all! 0684 if len(sys.argv)==1 or args: 0685 print usage() 0686 0687 verbose = 1 0688 for opt, val in opts: 0689 if opt=='-d': # Dump 0690 _Dump() 0691 if opt=='-r': 0692 Rebuild(verbose) 0693 if opt=='-q': 0694 verbose = 0 0695
Generated by PyXR 0.9.4