Embed pywin32, new version of package control broke the plugin
This commit is contained in:
636
Pywin32/lib/x32/win32com/client/build.py
Normal file
636
Pywin32/lib/x32/win32com/client/build.py
Normal file
@@ -0,0 +1,636 @@
|
||||
"""Contains knowledge to build a COM object definition.
|
||||
|
||||
This module is used by both the @dynamic@ and @makepy@ modules to build
|
||||
all knowledge of a COM object.
|
||||
|
||||
This module contains classes which contain the actual knowledge of the object.
|
||||
This include parameter and return type information, the COM dispid and CLSID, etc.
|
||||
|
||||
Other modules may use this information to generate .py files, use the information
|
||||
dynamically, or possibly even generate .html documentation for objects.
|
||||
"""
|
||||
|
||||
#
|
||||
# NOTES: DispatchItem and MapEntry used by dynamic.py.
|
||||
# the rest is used by makepy.py
|
||||
#
|
||||
# OleItem, DispatchItem, MapEntry, BuildCallList() is used by makepy
|
||||
|
||||
import sys
|
||||
import string
|
||||
from keyword import iskeyword
|
||||
|
||||
import pythoncom
|
||||
from pywintypes import TimeType
|
||||
import winerror
|
||||
import datetime
|
||||
|
||||
# It isn't really clear what the quoting rules are in a C/IDL string and
|
||||
# literals like a quote char and backslashes makes life a little painful to
|
||||
# always render the string perfectly - so just punt and fall-back to a repr()
|
||||
def _makeDocString(s):
|
||||
if sys.version_info < (3,):
|
||||
s = s.encode("mbcs")
|
||||
return repr(s)
|
||||
|
||||
error = "PythonCOM.Client.Build error"
|
||||
class NotSupportedException(Exception): pass # Raised when we cant support a param type.
|
||||
DropIndirection="DropIndirection"
|
||||
|
||||
NoTranslateTypes = [
|
||||
pythoncom.VT_BOOL, pythoncom.VT_CLSID, pythoncom.VT_CY,
|
||||
pythoncom.VT_DATE, pythoncom.VT_DECIMAL, pythoncom.VT_EMPTY,
|
||||
pythoncom.VT_ERROR, pythoncom.VT_FILETIME, pythoncom.VT_HRESULT,
|
||||
pythoncom.VT_I1, pythoncom.VT_I2, pythoncom.VT_I4,
|
||||
pythoncom.VT_I8, pythoncom.VT_INT, pythoncom.VT_NULL,
|
||||
pythoncom.VT_R4, pythoncom.VT_R8, pythoncom.VT_NULL,
|
||||
pythoncom.VT_STREAM,
|
||||
pythoncom.VT_UI1, pythoncom.VT_UI2, pythoncom.VT_UI4,
|
||||
pythoncom.VT_UI8, pythoncom.VT_UINT, pythoncom.VT_VOID,
|
||||
]
|
||||
|
||||
NoTranslateMap = {}
|
||||
for v in NoTranslateTypes:
|
||||
NoTranslateMap[v] = None
|
||||
|
||||
class MapEntry:
|
||||
"Simple holder for named attibutes - items in a map."
|
||||
def __init__(self, desc_or_id, names=None, doc=None, resultCLSID=pythoncom.IID_NULL, resultDoc = None, hidden=0):
|
||||
if type(desc_or_id)==type(0):
|
||||
self.dispid = desc_or_id
|
||||
self.desc = None
|
||||
else:
|
||||
self.dispid = desc_or_id[0]
|
||||
self.desc = desc_or_id
|
||||
|
||||
self.names = names
|
||||
self.doc = doc
|
||||
self.resultCLSID = resultCLSID
|
||||
self.resultDocumentation = resultDoc
|
||||
self.wasProperty = 0 # Have I been transformed into a function so I can pass args?
|
||||
self.hidden = hidden
|
||||
def GetResultCLSID(self):
|
||||
rc = self.resultCLSID
|
||||
if rc == pythoncom.IID_NULL: return None
|
||||
return rc
|
||||
# Return a string, suitable for output - either "'{...}'" or "None"
|
||||
def GetResultCLSIDStr(self):
|
||||
rc = self.GetResultCLSID()
|
||||
if rc is None: return "None"
|
||||
return repr(str(rc)) # Convert the IID object to a string, then to a string in a string.
|
||||
|
||||
def GetResultName(self):
|
||||
if self.resultDocumentation is None:
|
||||
return None
|
||||
return self.resultDocumentation[0]
|
||||
|
||||
class OleItem:
|
||||
typename = "OleItem"
|
||||
|
||||
def __init__(self, doc=None):
|
||||
self.doc = doc
|
||||
if self.doc:
|
||||
self.python_name = MakePublicAttributeName(self.doc[0])
|
||||
else:
|
||||
self.python_name = None
|
||||
self.bWritten = 0
|
||||
self.bIsDispatch = 0
|
||||
self.bIsSink = 0
|
||||
self.clsid = None
|
||||
self.co_class = None
|
||||
|
||||
class DispatchItem(OleItem):
|
||||
typename = "DispatchItem"
|
||||
|
||||
def __init__(self, typeinfo=None, attr=None, doc=None, bForUser=1):
|
||||
OleItem.__init__(self,doc)
|
||||
self.propMap = {}
|
||||
self.propMapGet = {}
|
||||
self.propMapPut = {}
|
||||
self.mapFuncs = {}
|
||||
self.defaultDispatchName = None
|
||||
self.hidden = 0
|
||||
|
||||
if typeinfo:
|
||||
self.Build(typeinfo, attr, bForUser)
|
||||
|
||||
def _propMapPutCheck_(self,key,item):
|
||||
ins, outs, opts = self.CountInOutOptArgs(item.desc[2])
|
||||
if ins>1: # if a Put property takes more than 1 arg:
|
||||
if opts+1==ins or ins==item.desc[6]+1:
|
||||
newKey = "Set" + key
|
||||
deleteExisting = 0 # This one is still OK
|
||||
else:
|
||||
deleteExisting = 1 # No good to us
|
||||
if key in self.mapFuncs or key in self.propMapGet:
|
||||
newKey = "Set" + key
|
||||
else:
|
||||
newKey = key
|
||||
item.wasProperty = 1
|
||||
self.mapFuncs[newKey] = item
|
||||
if deleteExisting:
|
||||
del self.propMapPut[key]
|
||||
|
||||
def _propMapGetCheck_(self,key,item):
|
||||
ins, outs, opts = self.CountInOutOptArgs(item.desc[2])
|
||||
if ins > 0: # if a Get property takes _any_ in args:
|
||||
if item.desc[6]==ins or ins==opts:
|
||||
newKey = "Get" + key
|
||||
deleteExisting = 0 # This one is still OK
|
||||
else:
|
||||
deleteExisting = 1 # No good to us
|
||||
if key in self.mapFuncs:
|
||||
newKey = "Get" + key
|
||||
else:
|
||||
newKey = key
|
||||
item.wasProperty = 1
|
||||
self.mapFuncs[newKey] = item
|
||||
if deleteExisting:
|
||||
del self.propMapGet[key]
|
||||
|
||||
def _AddFunc_(self,typeinfo,fdesc,bForUser):
|
||||
id = fdesc.memid
|
||||
funcflags = fdesc.wFuncFlags
|
||||
try:
|
||||
names = typeinfo.GetNames(id)
|
||||
name=names[0]
|
||||
except pythoncom.ole_error:
|
||||
name = ""
|
||||
names = None
|
||||
|
||||
doc = None
|
||||
try:
|
||||
if bForUser:
|
||||
doc = typeinfo.GetDocumentation(id)
|
||||
except pythoncom.ole_error:
|
||||
pass
|
||||
|
||||
if id==0 and name:
|
||||
self.defaultDispatchName = name
|
||||
|
||||
invkind = fdesc.invkind
|
||||
|
||||
# We need to translate any Alias', Enums, structs etc in result and args
|
||||
typerepr, flag, defval = fdesc.rettype
|
||||
# sys.stderr.write("%s result - %s -> " % (name, typerepr))
|
||||
typerepr, resultCLSID, resultDoc = _ResolveType(typerepr, typeinfo)
|
||||
# sys.stderr.write("%s\n" % (typerepr,))
|
||||
fdesc.rettype = typerepr, flag, defval, resultCLSID
|
||||
# Translate any Alias or Enums in argument list.
|
||||
argList = []
|
||||
for argDesc in fdesc.args:
|
||||
typerepr, flag, defval = argDesc
|
||||
# sys.stderr.write("%s arg - %s -> " % (name, typerepr))
|
||||
arg_type, arg_clsid, arg_doc = _ResolveType(typerepr, typeinfo)
|
||||
argDesc = arg_type, flag, defval, arg_clsid
|
||||
# sys.stderr.write("%s\n" % (argDesc[0],))
|
||||
argList.append(argDesc)
|
||||
fdesc.args = tuple(argList)
|
||||
|
||||
hidden = (funcflags & pythoncom.FUNCFLAG_FHIDDEN) != 0
|
||||
if invkind == pythoncom.INVOKE_PROPERTYGET:
|
||||
map = self.propMapGet
|
||||
# This is not the best solution, but I dont think there is
|
||||
# one without specific "set" syntax.
|
||||
# If there is a single PUT or PUTREF, it will function as a property.
|
||||
# If there are both, then the PUT remains a property, and the PUTREF
|
||||
# gets transformed into a function.
|
||||
# (in vb, PUT=="obj=other_obj", PUTREF="set obj=other_obj
|
||||
elif invkind in (pythoncom.INVOKE_PROPERTYPUT, pythoncom.INVOKE_PROPERTYPUTREF):
|
||||
# Special case
|
||||
existing = self.propMapPut.get(name, None)
|
||||
if existing is not None:
|
||||
if existing.desc[4]==pythoncom.INVOKE_PROPERTYPUT: # Keep this one
|
||||
map = self.mapFuncs
|
||||
name = "Set"+name
|
||||
else: # Existing becomes a func.
|
||||
existing.wasProperty = 1
|
||||
self.mapFuncs["Set"+name]=existing
|
||||
map = self.propMapPut # existing gets overwritten below.
|
||||
else:
|
||||
map = self.propMapPut # first time weve seen it.
|
||||
|
||||
elif invkind == pythoncom.INVOKE_FUNC:
|
||||
map = self.mapFuncs
|
||||
else:
|
||||
map = None
|
||||
if not map is None:
|
||||
# if map.has_key(name):
|
||||
# sys.stderr.write("Warning - overwriting existing method/attribute %s\n" % name)
|
||||
map[name] = MapEntry(tuple(fdesc), names, doc, resultCLSID, resultDoc, hidden)
|
||||
# any methods that can't be reached via DISPATCH we return None
|
||||
# for, so dynamic dispatch doesnt see it.
|
||||
if fdesc.funckind != pythoncom.FUNC_DISPATCH:
|
||||
return None
|
||||
return (name,map)
|
||||
return None
|
||||
|
||||
def _AddVar_(self,typeinfo,fdesc,bForUser):
|
||||
### need pythoncom.VARFLAG_FRESTRICTED ...
|
||||
### then check it
|
||||
|
||||
if fdesc.varkind == pythoncom.VAR_DISPATCH:
|
||||
id = fdesc.memid
|
||||
names = typeinfo.GetNames(id)
|
||||
# Translate any Alias or Enums in result.
|
||||
typerepr, flags, defval = fdesc.elemdescVar
|
||||
typerepr, resultCLSID, resultDoc = _ResolveType(typerepr, typeinfo)
|
||||
fdesc.elemdescVar = typerepr, flags, defval
|
||||
doc = None
|
||||
try:
|
||||
if bForUser: doc = typeinfo.GetDocumentation(id)
|
||||
except pythoncom.ole_error:
|
||||
pass
|
||||
|
||||
# handle the enumerator specially
|
||||
map = self.propMap
|
||||
# Check if the element is hidden.
|
||||
hidden = 0
|
||||
if hasattr(fdesc,"wVarFlags"):
|
||||
hidden = (fdesc.wVarFlags & 0x40) != 0 # VARFLAG_FHIDDEN
|
||||
map[names[0]] = MapEntry(tuple(fdesc), names, doc, resultCLSID, resultDoc, hidden)
|
||||
return (names[0],map)
|
||||
else:
|
||||
return None
|
||||
|
||||
def Build(self, typeinfo, attr, bForUser = 1):
|
||||
self.clsid = attr[0]
|
||||
self.bIsDispatch = (attr.wTypeFlags & pythoncom.TYPEFLAG_FDISPATCHABLE) != 0
|
||||
if typeinfo is None: return
|
||||
# Loop over all methods
|
||||
for j in range(attr[6]):
|
||||
fdesc = typeinfo.GetFuncDesc(j)
|
||||
self._AddFunc_(typeinfo,fdesc,bForUser)
|
||||
|
||||
# Loop over all variables (ie, properties)
|
||||
for j in range(attr[7]):
|
||||
fdesc = typeinfo.GetVarDesc(j)
|
||||
self._AddVar_(typeinfo,fdesc,bForUser)
|
||||
|
||||
# Now post-process the maps. For any "Get" or "Set" properties
|
||||
# that have arguments, we must turn them into methods. If a method
|
||||
# of the same name already exists, change the name.
|
||||
for key, item in list(self.propMapGet.items()):
|
||||
self._propMapGetCheck_(key,item)
|
||||
|
||||
for key, item in list(self.propMapPut.items()):
|
||||
self._propMapPutCheck_(key,item)
|
||||
|
||||
def CountInOutOptArgs(self, argTuple):
|
||||
"Return tuple counting in/outs/OPTS. Sum of result may not be len(argTuple), as some args may be in/out."
|
||||
ins = out = opts = 0
|
||||
for argCheck in argTuple:
|
||||
inOut = argCheck[1]
|
||||
if inOut==0:
|
||||
ins = ins + 1
|
||||
out = out + 1
|
||||
else:
|
||||
if inOut & pythoncom.PARAMFLAG_FIN:
|
||||
ins = ins + 1
|
||||
if inOut & pythoncom.PARAMFLAG_FOPT:
|
||||
opts = opts + 1
|
||||
if inOut & pythoncom.PARAMFLAG_FOUT:
|
||||
out = out + 1
|
||||
return ins, out, opts
|
||||
|
||||
def MakeFuncMethod(self, entry, name, bMakeClass = 1):
|
||||
# If we have a type description, and not varargs...
|
||||
if entry.desc is not None and (len(entry.desc) < 6 or entry.desc[6]!=-1):
|
||||
return self.MakeDispatchFuncMethod(entry, name, bMakeClass)
|
||||
else:
|
||||
return self.MakeVarArgsFuncMethod(entry, name, bMakeClass)
|
||||
|
||||
def MakeDispatchFuncMethod(self, entry, name, bMakeClass = 1):
|
||||
fdesc = entry.desc
|
||||
doc = entry.doc
|
||||
names = entry.names
|
||||
ret = []
|
||||
if bMakeClass:
|
||||
linePrefix = "\t"
|
||||
defNamedOptArg = "defaultNamedOptArg"
|
||||
defNamedNotOptArg = "defaultNamedNotOptArg"
|
||||
defUnnamedArg = "defaultUnnamedArg"
|
||||
else:
|
||||
linePrefix = ""
|
||||
defNamedOptArg = "pythoncom.Missing"
|
||||
defNamedNotOptArg = "pythoncom.Missing"
|
||||
defUnnamedArg = "pythoncom.Missing"
|
||||
defOutArg = "pythoncom.Missing"
|
||||
id = fdesc[0]
|
||||
|
||||
s = linePrefix + 'def ' + name + '(self' + BuildCallList(fdesc, names, defNamedOptArg, defNamedNotOptArg, defUnnamedArg, defOutArg) + '):'
|
||||
ret.append(s)
|
||||
if doc and doc[1]:
|
||||
ret.append(linePrefix + '\t' + _makeDocString(doc[1]))
|
||||
|
||||
# print "fdesc is ", fdesc
|
||||
|
||||
resclsid = entry.GetResultCLSID()
|
||||
if resclsid:
|
||||
resclsid = "'%s'" % resclsid
|
||||
else:
|
||||
resclsid = 'None'
|
||||
# Strip the default values from the arg desc
|
||||
retDesc = fdesc[8][:2]
|
||||
argsDesc = tuple([what[:2] for what in fdesc[2]])
|
||||
# The runtime translation of the return types is expensive, so when we know the
|
||||
# return type of the function, there is no need to check the type at runtime.
|
||||
# To qualify, this function must return a "simple" type, and have no byref args.
|
||||
# Check if we have byrefs or anything in the args which mean we still need a translate.
|
||||
param_flags = [what[1] for what in fdesc[2]]
|
||||
bad_params = [flag for flag in param_flags if flag & (pythoncom.PARAMFLAG_FOUT | pythoncom.PARAMFLAG_FRETVAL)!=0]
|
||||
s = None
|
||||
if len(bad_params)==0 and len(retDesc)==2 and retDesc[1]==0:
|
||||
rd = retDesc[0]
|
||||
if rd in NoTranslateMap:
|
||||
s = '%s\treturn self._oleobj_.InvokeTypes(%d, LCID, %s, %s, %s%s)' % (linePrefix, id, fdesc[4], retDesc, argsDesc, _BuildArgList(fdesc, names))
|
||||
elif rd in [pythoncom.VT_DISPATCH, pythoncom.VT_UNKNOWN]:
|
||||
s = '%s\tret = self._oleobj_.InvokeTypes(%d, LCID, %s, %s, %s%s)\n' % (linePrefix, id, fdesc[4], retDesc, repr(argsDesc), _BuildArgList(fdesc, names))
|
||||
s = s + '%s\tif ret is not None:\n' % (linePrefix,)
|
||||
if rd == pythoncom.VT_UNKNOWN:
|
||||
s = s + "%s\t\t# See if this IUnknown is really an IDispatch\n" % (linePrefix,)
|
||||
s = s + "%s\t\ttry:\n" % (linePrefix,)
|
||||
s = s + "%s\t\t\tret = ret.QueryInterface(pythoncom.IID_IDispatch)\n" % (linePrefix,)
|
||||
s = s + "%s\t\texcept pythoncom.error:\n" % (linePrefix,)
|
||||
s = s + "%s\t\t\treturn ret\n" % (linePrefix,)
|
||||
s = s + '%s\t\tret = Dispatch(ret, %s, %s)\n' % (linePrefix,repr(name), resclsid)
|
||||
s = s + '%s\treturn ret' % (linePrefix)
|
||||
elif rd == pythoncom.VT_BSTR:
|
||||
s = "%s\t# Result is a Unicode object\n" % (linePrefix,)
|
||||
s = s + '%s\treturn self._oleobj_.InvokeTypes(%d, LCID, %s, %s, %s%s)' % (linePrefix, id, fdesc[4], retDesc, repr(argsDesc), _BuildArgList(fdesc, names))
|
||||
# else s remains None
|
||||
if s is None:
|
||||
s = '%s\treturn self._ApplyTypes_(%d, %s, %s, %s, %s, %s%s)' % (linePrefix, id, fdesc[4], retDesc, argsDesc, repr(name), resclsid, _BuildArgList(fdesc, names))
|
||||
|
||||
ret.append(s)
|
||||
ret.append("")
|
||||
return ret
|
||||
|
||||
def MakeVarArgsFuncMethod(self, entry, name, bMakeClass = 1):
|
||||
fdesc = entry.desc
|
||||
names = entry.names
|
||||
doc = entry.doc
|
||||
ret = []
|
||||
argPrefix = "self"
|
||||
if bMakeClass:
|
||||
linePrefix = "\t"
|
||||
else:
|
||||
linePrefix = ""
|
||||
ret.append(linePrefix + 'def ' + name + '(' + argPrefix + ', *args):')
|
||||
if doc and doc[1]: ret.append(linePrefix + '\t' + _makeDocString(doc[1]))
|
||||
if fdesc:
|
||||
invoketype = fdesc[4]
|
||||
else:
|
||||
invoketype = pythoncom.DISPATCH_METHOD
|
||||
s = linePrefix + '\treturn self._get_good_object_(self._oleobj_.Invoke(*(('
|
||||
ret.append(s + str(entry.dispid) + ",0,%d,1)+args)),'%s')" % (invoketype, names[0]))
|
||||
ret.append("")
|
||||
return ret
|
||||
|
||||
# Note - "DispatchItem" poorly named - need a new intermediate class.
|
||||
class VTableItem(DispatchItem):
|
||||
def Build(self, typeinfo, attr, bForUser = 1):
|
||||
DispatchItem.Build(self, typeinfo, attr, bForUser)
|
||||
assert typeinfo is not None, "Cant build vtables without type info!"
|
||||
|
||||
meth_list = list(self.mapFuncs.values()) + list(self.propMapGet.values()) + list(self.propMapPut.values())
|
||||
|
||||
if sys.version_info < (2,4):
|
||||
def cmp_vtable_off(m1, m2):
|
||||
return cmp(m1.desc[7], m2.desc[7])
|
||||
meth_list.sort(cmp_vtable_off)
|
||||
else:
|
||||
meth_list.sort(key=lambda m: m.desc[7])
|
||||
|
||||
# Now turn this list into the run-time representation
|
||||
# (ready for immediate use or writing to gencache)
|
||||
self.vtableFuncs = []
|
||||
for entry in meth_list:
|
||||
self.vtableFuncs.append( (entry.names, entry.dispid, entry.desc) )
|
||||
|
||||
# A Lazy dispatch item - builds an item on request using info from
|
||||
# an ITypeComp. The dynamic module makes the called to build each item,
|
||||
# and also holds the references to the typeinfo and typecomp.
|
||||
class LazyDispatchItem(DispatchItem):
|
||||
typename = "LazyDispatchItem"
|
||||
def __init__(self, attr, doc):
|
||||
self.clsid = attr[0]
|
||||
DispatchItem.__init__(self, None, attr, doc, 0)
|
||||
|
||||
typeSubstMap = {
|
||||
pythoncom.VT_INT: pythoncom.VT_I4,
|
||||
pythoncom.VT_UINT: pythoncom.VT_UI4,
|
||||
pythoncom.VT_HRESULT: pythoncom.VT_I4,
|
||||
}
|
||||
|
||||
def _ResolveType(typerepr, itypeinfo):
|
||||
# Resolve VT_USERDEFINED (often aliases or typed IDispatches)
|
||||
|
||||
if type(typerepr)==tuple:
|
||||
indir_vt, subrepr = typerepr
|
||||
if indir_vt == pythoncom.VT_PTR:
|
||||
# If it is a VT_PTR to a VT_USERDEFINED that is an IDispatch/IUnknown,
|
||||
# then it resolves to simply the object.
|
||||
# Otherwise, it becomes a ByRef of the resolved type
|
||||
# We need to drop an indirection level on pointer to user defined interfaces.
|
||||
# eg, (VT_PTR, (VT_USERDEFINED, somehandle)) needs to become VT_DISPATCH
|
||||
# only when "somehandle" is an object.
|
||||
# but (VT_PTR, (VT_USERDEFINED, otherhandle)) doesnt get the indirection dropped.
|
||||
was_user = type(subrepr)==tuple and subrepr[0]==pythoncom.VT_USERDEFINED
|
||||
subrepr, sub_clsid, sub_doc = _ResolveType(subrepr, itypeinfo)
|
||||
if was_user and subrepr in [pythoncom.VT_DISPATCH, pythoncom.VT_UNKNOWN, pythoncom.VT_RECORD]:
|
||||
# Drop the VT_PTR indirection
|
||||
return subrepr, sub_clsid, sub_doc
|
||||
# Change PTR indirection to byref
|
||||
return subrepr | pythoncom.VT_BYREF, sub_clsid, sub_doc
|
||||
if indir_vt == pythoncom.VT_SAFEARRAY:
|
||||
# resolve the array element, and convert to VT_ARRAY
|
||||
subrepr, sub_clsid, sub_doc = _ResolveType(subrepr, itypeinfo)
|
||||
return pythoncom.VT_ARRAY | subrepr, sub_clsid, sub_doc
|
||||
if indir_vt == pythoncom.VT_CARRAY: # runtime has no support for this yet.
|
||||
# resolve the array element, and convert to VT_CARRAY
|
||||
# sheesh - return _something_
|
||||
return pythoncom.VT_CARRAY, None, None
|
||||
if indir_vt == pythoncom.VT_USERDEFINED:
|
||||
try:
|
||||
resultTypeInfo = itypeinfo.GetRefTypeInfo(subrepr)
|
||||
except pythoncom.com_error as details:
|
||||
if details.hresult in [winerror.TYPE_E_CANTLOADLIBRARY, winerror.TYPE_E_LIBNOTREGISTERED]:
|
||||
# an unregistered interface
|
||||
return pythoncom.VT_UNKNOWN, None, None
|
||||
raise
|
||||
|
||||
resultAttr = resultTypeInfo.GetTypeAttr()
|
||||
typeKind = resultAttr.typekind
|
||||
if typeKind == pythoncom.TKIND_ALIAS:
|
||||
tdesc = resultAttr.tdescAlias
|
||||
return _ResolveType(tdesc, resultTypeInfo)
|
||||
elif typeKind in [pythoncom.TKIND_ENUM, pythoncom.TKIND_MODULE]:
|
||||
# For now, assume Long
|
||||
return pythoncom.VT_I4, None, None
|
||||
|
||||
elif typeKind == pythoncom.TKIND_DISPATCH:
|
||||
clsid = resultTypeInfo.GetTypeAttr()[0]
|
||||
retdoc = resultTypeInfo.GetDocumentation(-1)
|
||||
return pythoncom.VT_DISPATCH, clsid, retdoc
|
||||
|
||||
elif typeKind in [pythoncom.TKIND_INTERFACE,
|
||||
pythoncom.TKIND_COCLASS]:
|
||||
# XXX - should probably get default interface for CO_CLASS???
|
||||
clsid = resultTypeInfo.GetTypeAttr()[0]
|
||||
retdoc = resultTypeInfo.GetDocumentation(-1)
|
||||
return pythoncom.VT_UNKNOWN, clsid, retdoc
|
||||
|
||||
elif typeKind == pythoncom.TKIND_RECORD:
|
||||
return pythoncom.VT_RECORD, None, None
|
||||
raise NotSupportedException("Can not resolve alias or user-defined type")
|
||||
return typeSubstMap.get(typerepr,typerepr), None, None
|
||||
|
||||
def _BuildArgList(fdesc, names):
|
||||
"Builds list of args to the underlying Invoke method."
|
||||
# Word has TypeInfo for Insert() method, but says "no args"
|
||||
numArgs = max(fdesc[6], len(fdesc[2]))
|
||||
names = list(names)
|
||||
while None in names:
|
||||
i = names.index(None)
|
||||
names[i] = "arg%d" % (i,)
|
||||
# We've seen 'source safe' libraries offer the name of 'ret' params in
|
||||
# 'names' - although we can't reproduce this, it would be insane to offer
|
||||
# more args than we have arg infos for - hence the upper limit on names...
|
||||
names = list(map(MakePublicAttributeName, names[1:(numArgs + 1)]))
|
||||
name_num = 0
|
||||
while len(names) < numArgs:
|
||||
names.append("arg%d" % (len(names),))
|
||||
# As per BuildCallList(), avoid huge lines.
|
||||
# Hack a "\n" at the end of every 5th name - "strides" would be handy
|
||||
# here but don't exist in 2.2
|
||||
for i in range(0, len(names), 5):
|
||||
names[i] = names[i] + "\n\t\t\t"
|
||||
return "," + ", ".join(names)
|
||||
|
||||
valid_identifier_chars = string.ascii_letters + string.digits + "_"
|
||||
|
||||
def demunge_leading_underscores(className):
|
||||
i = 0
|
||||
while className[i] == "_":
|
||||
i += 1
|
||||
assert i >= 2, "Should only be here with names starting with '__'"
|
||||
return className[i-1:] + className[:i-1]
|
||||
|
||||
# Given a "public name" (eg, the name of a class, function, etc)
|
||||
# make sure it is a legal (and reasonable!) Python name.
|
||||
def MakePublicAttributeName(className, is_global = False):
|
||||
# Given a class attribute that needs to be public, convert it to a
|
||||
# reasonable name.
|
||||
# Also need to be careful that the munging doesnt
|
||||
# create duplicates - eg, just removing a leading "_" is likely to cause
|
||||
# a clash.
|
||||
# if is_global is True, then the name is a global variable that may
|
||||
# overwrite a builtin - eg, "None"
|
||||
if className[:2]=='__':
|
||||
return demunge_leading_underscores(className)
|
||||
elif className == 'None':
|
||||
# assign to None is evil (and SyntaxError in 2.4, even though
|
||||
# iskeyword says False there) - note that if it was a global
|
||||
# it would get picked up below
|
||||
className = 'NONE'
|
||||
elif iskeyword(className):
|
||||
# most keywords are lower case (except True, False etc in py3k)
|
||||
ret = className.capitalize()
|
||||
# but those which aren't get forced upper.
|
||||
if ret == className:
|
||||
ret = ret.upper()
|
||||
return ret
|
||||
elif is_global and hasattr(__builtins__, className):
|
||||
# builtins may be mixed case. If capitalizing it doesn't change it,
|
||||
# force to all uppercase (eg, "None", "True" become "NONE", "TRUE"
|
||||
ret = className.capitalize()
|
||||
if ret==className: # didn't change - force all uppercase.
|
||||
ret = ret.upper()
|
||||
return ret
|
||||
# Strip non printable chars
|
||||
return ''.join([char for char in className if char in valid_identifier_chars])
|
||||
|
||||
# Given a default value passed by a type library, return a string with
|
||||
# an appropriate repr() for the type.
|
||||
# Takes a raw ELEMDESC and returns a repr string, or None
|
||||
# (NOTE: The string itself may be '"None"', which is valid, and different to None.
|
||||
# XXX - To do: Dates are probably screwed, but can they come in?
|
||||
def MakeDefaultArgRepr(defArgVal):
|
||||
try:
|
||||
inOut = defArgVal[1]
|
||||
except IndexError:
|
||||
# something strange - assume is in param.
|
||||
inOut = pythoncom.PARAMFLAG_FIN
|
||||
|
||||
if inOut & pythoncom.PARAMFLAG_FHASDEFAULT:
|
||||
# times need special handling...
|
||||
val = defArgVal[2]
|
||||
if isinstance(val, datetime.datetime):
|
||||
# VARIANT <-> SYSTEMTIME conversions always lose any sub-second
|
||||
# resolution, so just use a 'timetuple' here.
|
||||
return repr(tuple(val.utctimetuple()))
|
||||
if type(val) is TimeType:
|
||||
# must be the 'old' pywintypes time object...
|
||||
year=val.year; month=val.month; day=val.day; hour=val.hour; minute=val.minute; second=val.second; msec=val.msec
|
||||
return "pywintypes.Time((%(year)d, %(month)d, %(day)d, %(hour)d, %(minute)d, %(second)d,0,0,0,%(msec)d))" % locals()
|
||||
return repr(val)
|
||||
return None
|
||||
|
||||
def BuildCallList(fdesc, names, defNamedOptArg, defNamedNotOptArg, defUnnamedArg, defOutArg, is_comment = False):
|
||||
"Builds a Python declaration for a method."
|
||||
# Names[0] is the func name - param names are from 1.
|
||||
numArgs = len(fdesc[2])
|
||||
numOptArgs = fdesc[6]
|
||||
strval = ''
|
||||
if numOptArgs==-1: # Special value that says "var args after here"
|
||||
firstOptArg = numArgs
|
||||
numArgs = numArgs - 1
|
||||
else:
|
||||
firstOptArg = numArgs - numOptArgs
|
||||
for arg in range(numArgs):
|
||||
try:
|
||||
argName = names[arg+1]
|
||||
namedArg = argName is not None
|
||||
except IndexError:
|
||||
namedArg = 0
|
||||
if not namedArg: argName = "arg%d" % (arg)
|
||||
thisdesc = fdesc[2][arg]
|
||||
# See if the IDL specified a default value
|
||||
defArgVal = MakeDefaultArgRepr(thisdesc)
|
||||
if defArgVal is None:
|
||||
# Out params always get their special default
|
||||
if thisdesc[1] & (pythoncom.PARAMFLAG_FOUT | pythoncom.PARAMFLAG_FIN) == pythoncom.PARAMFLAG_FOUT:
|
||||
defArgVal = defOutArg
|
||||
else:
|
||||
# Unnamed arg - always allow default values.
|
||||
if namedArg:
|
||||
# Is a named argument
|
||||
if arg >= firstOptArg:
|
||||
defArgVal = defNamedOptArg
|
||||
else:
|
||||
defArgVal = defNamedNotOptArg
|
||||
else:
|
||||
defArgVal = defUnnamedArg
|
||||
|
||||
argName = MakePublicAttributeName(argName)
|
||||
# insanely long lines with an 'encoding' flag crashes python 2.4.0
|
||||
# keep 5 args per line
|
||||
# This may still fail if the arg names are insane, but that seems
|
||||
# unlikely. See also _BuildArgList()
|
||||
if (arg+1) % 5 == 0:
|
||||
strval = strval + "\n"
|
||||
if is_comment:
|
||||
strval = strval + "#"
|
||||
strval = strval + "\t\t\t"
|
||||
strval = strval + ", " + argName
|
||||
if defArgVal:
|
||||
strval = strval + "=" + defArgVal
|
||||
if numOptArgs==-1:
|
||||
strval = strval + ", *" + names[-1]
|
||||
|
||||
return strval
|
||||
|
||||
|
||||
if __name__=='__main__':
|
||||
print("Use 'makepy.py' to generate Python code - this module is just a helper")
|
||||
Reference in New Issue
Block a user