[pywin32-checkins] pywin32/com/win32com/client gencache.py,1.20,1.21
OLD project page for the Python extensions for Windows
Brought to you by:
mhammond
|
From: <mha...@us...> - 2003-09-16 04:55:34
|
Update of /cvsroot/pywin32/pywin32/com/win32com/client
In directory sc8-pr-cvs1:/tmp/cvs-serv27520
Modified Files:
gencache.py
Log Message:
* Support the gencache being in a .zip file.
* If the gencache is readonly and we are requesting a typelib version
we don't currently have, check if we have an earlier minor version.
* Don't load the same typelib twice when checking version.
Index: gencache.py
===================================================================
RCS file: /cvsroot/pywin32/pywin32/com/win32com/client/gencache.py,v
retrieving revision 1.20
retrieving revision 1.21
diff -C2 -d -r1.20 -r1.21
*** gencache.py 2 Sep 2003 00:18:40 -0000 1.20
--- gencache.py 16 Sep 2003 04:55:27 -0000 1.21
***************
*** 33,36 ****
--- 33,44 ----
clsidToTypelib = {}
+ # If we have a different version of the typelib generated, this
+ # maps the "requested version" to the "generated version".
+ versionRedirectMap = {}
+
+ # There is no reason we *must* be readonly in a .zip, but we are now,
+ # and we really do need a "read-only" concept anyway.
+ is_readonly = not os.path.isdir(os.path.dirname(win32com.__gen_path__))
+
# A dictionary of ITypeLibrary objects for demand generation explicitly handed to us
# Keyed by usual clsid, lcid, major, minor
***************
*** 46,49 ****
--- 54,60 ----
pickleVersion = 1
def _SaveDicts():
+ if is_readonly:
+ raise RuntimeError, "Trying to write to a readonly gencache ('%s')!" \
+ % win32com.__gen_path__
import cPickle
f = open(os.path.join(GetGeneratePath(), "dicts.dat"), "wb")
***************
*** 57,65 ****
def _LoadDicts():
import cPickle
! try:
# NOTE: IOError on file open must be caught by caller.
f = open(os.path.join(win32com.__gen_path__, "dicts.dat"), "rb")
- except AttributeError: # no __gen_path__
- return
try:
p = cPickle.Unpickler(f)
--- 68,84 ----
def _LoadDicts():
import cPickle
! # Load the dictionary from a .zip file if that is where we live.
! zip_pos = win32com.__gen_path__.find(".zip\\")
! if zip_pos >= 0:
! import zipfile, cStringIO
! zip_file = win32com.__gen_path__[:zip_pos+4]
! zip_path = win32com.__gen_path__[zip_pos+5:]
! zip_path = os.path.join(zip_path, "dicts.dat").replace("\\", "/")
! zf = zipfile.ZipFile(zip_file)
! f = cStringIO.StringIO(zf.read(zip_path))
! zf.close()
! else:
# NOTE: IOError on file open must be caught by caller.
f = open(os.path.join(win32com.__gen_path__, "dicts.dat"), "rb")
try:
p = cPickle.Unpickler(f)
***************
*** 67,70 ****
--- 86,90 ----
global clsidToTypelib
clsidToTypelib = p.load()
+ versionRedirectMap.clear()
finally:
f.close()
***************
*** 212,215 ****
--- 232,256 ----
modName = GetGeneratedFileName(typelibCLSID, lcid, major, minor)
return _GetModule(modName)
+ ##############
+ typelibCLSID = str(typelibCLSID)
+ args = typelibCLSID, lcid, major, minor
+ args = versionRedirectMap.get(args, args)
+ modName = GetGeneratedFileName(*args)
+ try:
+ return _GetModule(modName)
+ except ImportError:
+ # See if we can find a module with a different minor version.
+ items = []
+ for desc in GetGeneratedInfos():
+ if str(desc[0])==typelibCLSID and desc[1]==lcid and desc[2]==major:
+ items.append(desc)
+ if not items:
+ raise
+ # Items are all identical, except for last tuple element
+ # We want the latest minor version we have - so just sort and grab last
+ items.sort()
+ new_minor = items[-1][3]
+ versionRedirectMap[args] = typelibCLSID, lcid, major, new_minor
+ return GetModuleForTypelib(typelibCLSID, lcid, major, new_minor)
def MakeModuleForTypelib(typelibCLSID, lcid, major, minor, progressInstance = None, bGUIProgress = None, bForDemand = bForDemandDefault, bBuildHidden = 1):
***************
*** 310,317 ****
# Not worth raising an exception - maybe they dont know we only remember for demand generated, etc.
print "ForgetAboutTypelibInterface:: Warning - type library with info %s is not being remembered!" % (info,)
!
!
! def EnsureModule(typelibCLSID, lcid, major, minor, progressInstance = None, bValidateFile=1, bForDemand = bForDemandDefault, bBuildHidden = 1):
"""Ensure Python support is loaded for a type library, generating if necessary.
--- 351,360 ----
# Not worth raising an exception - maybe they dont know we only remember for demand generated, etc.
print "ForgetAboutTypelibInterface:: Warning - type library with info %s is not being remembered!" % (info,)
+ # and drop any version redirects to it
+ for key, val in versionRedirectMap.items():
+ if val==info:
+ del versionRedirectMap[key]
! def EnsureModule(typelibCLSID, lcid, major, minor, progressInstance = None, bValidateFile=not is_readonly, bForDemand = bForDemandDefault, bBuildHidden = 1):
"""Ensure Python support is loaded for a type library, generating if necessary.
***************
*** 338,358 ****
try:
try:
- #print "Try specified typelib"
module = GetModuleForTypelib(typelibCLSID, lcid, major, minor)
- #print module
except ImportError:
# If we get an ImportError
# We may still find a valid cache file under a different MinorVersion #
! #print "Loading reg typelib"
! tlbAttr = pythoncom.LoadRegTypeLib(typelibCLSID, major, minor, lcid).GetLibAttr()
! # if the above line doesn't throw a pythoncom.com_error
! # Let's suck it in
! #print "Trying 2nd minor #", tlbAttr[1], tlbAttr[3], tlbAttr[4]
try:
! module = GetModuleForTypelib(typelibCLSID, tlbAttr[1], tlbAttr[3], tlbAttr[4])
! except ImportError:
! module = None
! minor = tlbAttr[4]
if module is not None and bValidateFile:
try:
typLibPath = pythoncom.QueryPathOfRegTypeLib(typelibCLSID, major, minor, lcid)
--- 381,409 ----
try:
try:
module = GetModuleForTypelib(typelibCLSID, lcid, major, minor)
except ImportError:
# If we get an ImportError
# We may still find a valid cache file under a different MinorVersion #
! # (which windows will search out for us)
! #print "Loading reg typelib", typelibCLSID, major, minor, lcid
! module = None
try:
! tlbAttr = pythoncom.LoadRegTypeLib(typelibCLSID, major, minor, lcid).GetLibAttr()
! # if the above line doesn't throw a pythoncom.com_error, check if
! # it is actually a different lib than we requested, and if so, suck it in
! if tlbAttr[1] != lcid or tlbAttr[4]!=minor:
! #print "Trying 2nd minor #", tlbAttr[1], tlbAttr[3], tlbAttr[4]
! try:
! module = GetModuleForTypelib(typelibCLSID, tlbAttr[1], tlbAttr[3], tlbAttr[4])
! except ImportError:
! # We don't have a module, but we do have a better minor
! # version - remember that.
! minor = tlbAttr[4]
! # else module remains None
! except pythoncom.com_error:
! # couldn't load any typelib - mod remains None
! pass
if module is not None and bValidateFile:
+ assert not is_readonly, "Can't validate in a read-only gencache"
try:
typLibPath = pythoncom.QueryPathOfRegTypeLib(typelibCLSID, major, minor, lcid)
***************
*** 364,367 ****
--- 415,419 ----
bValidateFile = 0
if module is not None and bValidateFile:
+ assert not is_readonly, "Can't validate in a read-only gencache"
filePathPrefix = "%s\\%s" % (GetGeneratePath(), GetGeneratedFileName(typelibCLSID, lcid, major, minor))
filePath = filePathPrefix + ".py"
***************
*** 417,421 ****
#print "Trying stat typelib", pyModTime
#print str(typLibPath)
! typLibModTime = os.stat(typLibPath[:-1])[8]
if fModTimeSet and (typLibModTime > pyModTime):
bReloadNeeded = 1
--- 469,473 ----
#print "Trying stat typelib", pyModTime
#print str(typLibPath)
! typLibModTime = os.stat(str(typLibPath[:-1]))[8]
if fModTimeSet and (typLibModTime > pyModTime):
bReloadNeeded = 1
***************
*** 424,427 ****
--- 476,505 ----
module = None
if module is None:
+ # We need to build an item. If we are in a read-only cache, we
+ # can't/don't want to do this - so before giving up, check for
+ # a different minor version in our cache - according to COM, this is OK
+ if is_readonly:
+ key = str(typelibCLSID), lcid, major, minor
+ # If we have been asked before, get last result.
+ try:
+ return versionRedirectMap[key]
+ except KeyError:
+ pass
+ # Find other candidates.
+ items = []
+ for desc in GetGeneratedInfos():
+ if key[0]==desc[0] and key[1]==desc[1] and key[2]==desc[2]:
+ items.append(desc)
+ if items:
+ # Items are all identical, except for last tuple element
+ # We want the latest minor version we have - so just sort and grab last
+ items.sort()
+ new_minor = items[-1][3]
+ ret = GetModuleForTypelib(typelibCLSID, lcid, major, new_minor)
+ else:
+ ret = None
+ # remember and return
+ versionRedirectMap[key] = ret
+ return ret
#print "Rebuilding: ", major, minor
module = MakeModuleForTypelib(typelibCLSID, lcid, major, minor, progressInstance, bForDemand = bForDemand, bBuildHidden = bBuildHidden)
***************
*** 451,455 ****
return disp
! def AddModuleToCache(typelibclsid, lcid, major, minor, verbose = 1, bFlushNow = 1):
"""Add a newly generated file to the cache dictionary.
"""
--- 529,533 ----
return disp
! def AddModuleToCache(typelibclsid, lcid, major, minor, verbose = 1, bFlushNow = not is_readonly):
"""Add a newly generated file to the cache dictionary.
"""
***************
*** 457,515 ****
mod = _GetModule(fname)
dict = mod.CLSIDToClassMap
for clsid, cls in dict.items():
! clsidToTypelib[clsid] = (str(typelibclsid), mod.LCID, mod.MajorVersion, mod.MinorVersion)
dict = mod.CLSIDToPackageMap
for clsid, name in dict.items():
! clsidToTypelib[clsid] = (str(typelibclsid), mod.LCID, mod.MajorVersion, mod.MinorVersion)
dict = mod.VTablesToClassMap
for clsid, cls in dict.items():
! clsidToTypelib[clsid] = (str(typelibclsid), mod.LCID, mod.MajorVersion, mod.MinorVersion)
dict = mod.VTablesToPackageMap
for clsid, cls in dict.items():
! clsidToTypelib[clsid] = (str(typelibclsid), mod.LCID, mod.MajorVersion, mod.MinorVersion)
!
if bFlushNow:
_SaveDicts()
def _GetModule(fname):
"""Given the name of a module in the gen_py directory, import and return it.
"""
! mod = __import__("win32com.gen_py.%s" % fname)
! return getattr( getattr(mod, "gen_py"), fname)
!
def Rebuild(verbose = 1):
"""Rebuild the cache indexes from the file system.
"""
clsidToTypelib.clear()
! files = glob.glob(win32com.__gen_path__+ "\\*.py")
! if verbose and len(files): # Dont bother reporting this when directory is empty!
print "Rebuilding cache of generated files for COM support..."
! for file in files:
! name = os.path.splitext(os.path.split(file)[1])[0]
try:
! iid, lcid, major, minor = string.split(name, "x")
! ok = 1
! except ValueError:
! ok = 0
! if ok:
! try:
! iid = pywintypes.IID("{" + iid + "}")
! except pywintypes.com_error:
! ok = 0
! if ok:
! if verbose:
! print "Checking", name
! try:
! AddModuleToCache(iid, lcid, major, minor, verbose, 0)
! except:
! print "Could not add module %s - %s: %s" % (name, sys.exc_info()[0],sys.exc_info()[1])
! else:
! if verbose and name[0] != '_':
! print "Skipping module", name
! if verbose and len(files): # Dont bother reporting this when directory is empty!
print "Done."
_SaveDicts()
--- 535,631 ----
mod = _GetModule(fname)
dict = mod.CLSIDToClassMap
+ info = str(typelibclsid), lcid, major, minor
for clsid, cls in dict.items():
! clsidToTypelib[clsid] = info
dict = mod.CLSIDToPackageMap
for clsid, name in dict.items():
! clsidToTypelib[clsid] = info
dict = mod.VTablesToClassMap
for clsid, cls in dict.items():
! clsidToTypelib[clsid] = info
dict = mod.VTablesToPackageMap
for clsid, cls in dict.items():
! clsidToTypelib[clsid] = info
+ # If this lib was previously redirected, drop it
+ if versionRedirectMap.has_key(info):
+ del versionRedirectMap[info]
if bFlushNow:
_SaveDicts()
+ def GetGeneratedInfos():
+ zip_pos = win32com.__gen_path__.find(".zip\\")
+ if zip_pos >= 0:
+ import zipfile, cStringIO
+ zip_file = win32com.__gen_path__[:zip_pos+4]
+ zip_path = win32com.__gen_path__[zip_pos+5:].replace("\\", "/")
+ zf = zipfile.ZipFile(zip_file)
+ infos = {}
+ for n in zf.namelist():
+ if not n.startswith(zip_path):
+ continue
+ base = n[len(zip_path)+1:].split("/")[0]
+ try:
+ iid, lcid, major, minor = base.split("x")
+ lcid = int(lcid)
+ major = int(major)
+ minor = int(minor)
+ iid = pywintypes.IID("{" + iid + "}")
+ except ValueError:
+ continue
+ except pywintypes.com_error:
+ # invalid IID
+ continue
+ infos[(iid, lcid, major, minor)] = 1
+ zf.close()
+ return infos.keys()
+ else:
+ # on the file system
+ files = glob.glob(win32com.__gen_path__+ "\\*")
+ ret = []
+ for file in files:
+ if not os.path.isdir(file) and not os.path.splitext(file)==".py":
+ continue
+ name = os.path.splitext(os.path.split(file)[1])[0]
+ try:
+ iid, lcid, major, minor = string.split(name, "x")
+ iid = pywintypes.IID("{" + iid + "}")
+ lcid = int(lcid)
+ major = int(major)
+ minor = int(minor)
+ except ValueError:
+ continue
+ except pywintypes.com_error:
+ # invalid IID
+ continue
+ ret.append((iid, lcid, major, minor))
+ return ret
+
def _GetModule(fname):
"""Given the name of a module in the gen_py directory, import and return it.
"""
! mod_name = "win32com.gen_py.%s" % fname
! mod = __import__(mod_name)
! return sys.modules[mod_name]
!
def Rebuild(verbose = 1):
"""Rebuild the cache indexes from the file system.
"""
clsidToTypelib.clear()
! infos = GetGeneratedInfos()
! if verbose and len(infos): # Dont bother reporting this when directory is empty!
print "Rebuilding cache of generated files for COM support..."
! for info in infos:
! iid, lcid, major, minor = info
! if verbose:
! print "Checking", GetGeneratedFileName(*info)
try:
! AddModuleToCache(iid, lcid, major, minor, verbose, 0)
! except:
! print "Could not add module %s - %s: %s" % (name, sys.exc_info()[0],sys.exc_info()[1])
! if verbose and len(infos): # Dont bother reporting this when directory is empty!
print "Done."
_SaveDicts()
|