PyXR

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



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
SourceForge.net Logo