PageRenderTime 53ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/External.LCA_RESTRICTED/Languages/IronPython/27/Lib/site-packages/win32com/client/build.py

http://github.com/IronLanguages/main
Python | 630 lines | 562 code | 33 blank | 35 comment | 68 complexity | 71b03f181aa68f1ddff85fb0a5113586 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
  1. """Contains knowledge to build a COM object definition.
  2. This module is used by both the @dynamic@ and @makepy@ modules to build
  3. all knowledge of a COM object.
  4. This module contains classes which contain the actual knowledge of the object.
  5. This include parameter and return type information, the COM dispid and CLSID, etc.
  6. Other modules may use this information to generate .py files, use the information
  7. dynamically, or possibly even generate .html documentation for objects.
  8. """
  9. #
  10. # NOTES: DispatchItem and MapEntry used by dynamic.py.
  11. # the rest is used by makepy.py
  12. #
  13. # OleItem, DispatchItem, MapEntry, BuildCallList() is used by makepy
  14. import sys
  15. import string
  16. from keyword import iskeyword
  17. import pythoncom
  18. from pywintypes import TimeType
  19. import winerror
  20. import datetime
  21. # A string ending with a quote can not be safely triple-quoted.
  22. def _safeQuotedString(s):
  23. if s[-1]=='"': s = s[:-1]+'\\"'
  24. return '"""%s"""' % s
  25. error = "PythonCOM.Client.Build error"
  26. class NotSupportedException(Exception): pass # Raised when we cant support a param type.
  27. DropIndirection="DropIndirection"
  28. NoTranslateTypes = [
  29. pythoncom.VT_BOOL, pythoncom.VT_CLSID, pythoncom.VT_CY,
  30. pythoncom.VT_DATE, pythoncom.VT_DECIMAL, pythoncom.VT_EMPTY,
  31. pythoncom.VT_ERROR, pythoncom.VT_FILETIME, pythoncom.VT_HRESULT,
  32. pythoncom.VT_I1, pythoncom.VT_I2, pythoncom.VT_I4,
  33. pythoncom.VT_I8, pythoncom.VT_INT, pythoncom.VT_NULL,
  34. pythoncom.VT_R4, pythoncom.VT_R8, pythoncom.VT_NULL,
  35. pythoncom.VT_STREAM,
  36. pythoncom.VT_UI1, pythoncom.VT_UI2, pythoncom.VT_UI4,
  37. pythoncom.VT_UI8, pythoncom.VT_UINT, pythoncom.VT_VOID,
  38. ]
  39. NoTranslateMap = {}
  40. for v in NoTranslateTypes:
  41. NoTranslateMap[v] = None
  42. class MapEntry:
  43. "Simple holder for named attibutes - items in a map."
  44. def __init__(self, desc_or_id, names=None, doc=None, resultCLSID=pythoncom.IID_NULL, resultDoc = None, hidden=0):
  45. if type(desc_or_id)==type(0):
  46. self.dispid = desc_or_id
  47. self.desc = None
  48. else:
  49. self.dispid = desc_or_id[0]
  50. self.desc = desc_or_id
  51. self.names = names
  52. self.doc = doc
  53. self.resultCLSID = resultCLSID
  54. self.resultDocumentation = resultDoc
  55. self.wasProperty = 0 # Have I been transformed into a function so I can pass args?
  56. self.hidden = hidden
  57. def GetResultCLSID(self):
  58. rc = self.resultCLSID
  59. if rc == pythoncom.IID_NULL: return None
  60. return rc
  61. # Return a string, suitable for output - either "'{...}'" or "None"
  62. def GetResultCLSIDStr(self):
  63. rc = self.GetResultCLSID()
  64. if rc is None: return "None"
  65. return repr(str(rc)) # Convert the IID object to a string, then to a string in a string.
  66. def GetResultName(self):
  67. if self.resultDocumentation is None:
  68. return None
  69. return self.resultDocumentation[0]
  70. class OleItem:
  71. typename = "OleItem"
  72. def __init__(self, doc=None):
  73. self.doc = doc
  74. if self.doc:
  75. self.python_name = MakePublicAttributeName(self.doc[0])
  76. else:
  77. self.python_name = None
  78. self.bWritten = 0
  79. self.bIsDispatch = 0
  80. self.bIsSink = 0
  81. self.clsid = None
  82. self.co_class = None
  83. class DispatchItem(OleItem):
  84. typename = "DispatchItem"
  85. def __init__(self, typeinfo=None, attr=None, doc=None, bForUser=1):
  86. OleItem.__init__(self,doc)
  87. self.propMap = {}
  88. self.propMapGet = {}
  89. self.propMapPut = {}
  90. self.mapFuncs = {}
  91. self.defaultDispatchName = None
  92. self.hidden = 0
  93. if typeinfo:
  94. self.Build(typeinfo, attr, bForUser)
  95. def _propMapPutCheck_(self,key,item):
  96. ins, outs, opts = self.CountInOutOptArgs(item.desc[2])
  97. if ins>1: # if a Put property takes more than 1 arg:
  98. if opts+1==ins or ins==item.desc[6]+1:
  99. newKey = "Set" + key
  100. deleteExisting = 0 # This one is still OK
  101. else:
  102. deleteExisting = 1 # No good to us
  103. if key in self.mapFuncs or key in self.propMapGet:
  104. newKey = "Set" + key
  105. else:
  106. newKey = key
  107. item.wasProperty = 1
  108. self.mapFuncs[newKey] = item
  109. if deleteExisting:
  110. del self.propMapPut[key]
  111. def _propMapGetCheck_(self,key,item):
  112. ins, outs, opts = self.CountInOutOptArgs(item.desc[2])
  113. if ins > 0: # if a Get property takes _any_ in args:
  114. if item.desc[6]==ins or ins==opts:
  115. newKey = "Get" + key
  116. deleteExisting = 0 # This one is still OK
  117. else:
  118. deleteExisting = 1 # No good to us
  119. if key in self.mapFuncs:
  120. newKey = "Get" + key
  121. else:
  122. newKey = key
  123. item.wasProperty = 1
  124. self.mapFuncs[newKey] = item
  125. if deleteExisting:
  126. del self.propMapGet[key]
  127. def _AddFunc_(self,typeinfo,fdesc,bForUser):
  128. id = fdesc.memid
  129. funcflags = fdesc.wFuncFlags
  130. try:
  131. names = typeinfo.GetNames(id)
  132. name=names[0]
  133. except pythoncom.ole_error:
  134. name = ""
  135. names = None
  136. doc = None
  137. try:
  138. if bForUser:
  139. doc = typeinfo.GetDocumentation(id)
  140. except pythoncom.ole_error:
  141. pass
  142. if id==0 and name:
  143. self.defaultDispatchName = name
  144. invkind = fdesc.invkind
  145. # We need to translate any Alias', Enums, structs etc in result and args
  146. typerepr, flag, defval = fdesc.rettype
  147. # sys.stderr.write("%s result - %s -> " % (name, typerepr))
  148. typerepr, resultCLSID, resultDoc = _ResolveType(typerepr, typeinfo)
  149. # sys.stderr.write("%s\n" % (typerepr,))
  150. fdesc.rettype = typerepr, flag, defval, resultCLSID
  151. # Translate any Alias or Enums in argument list.
  152. argList = []
  153. for argDesc in fdesc.args:
  154. typerepr, flag, defval = argDesc
  155. # sys.stderr.write("%s arg - %s -> " % (name, typerepr))
  156. arg_type, arg_clsid, arg_doc = _ResolveType(typerepr, typeinfo)
  157. argDesc = arg_type, flag, defval, arg_clsid
  158. # sys.stderr.write("%s\n" % (argDesc[0],))
  159. argList.append(argDesc)
  160. fdesc.args = tuple(argList)
  161. hidden = (funcflags & pythoncom.FUNCFLAG_FHIDDEN) != 0
  162. if invkind == pythoncom.INVOKE_PROPERTYGET:
  163. map = self.propMapGet
  164. # This is not the best solution, but I dont think there is
  165. # one without specific "set" syntax.
  166. # If there is a single PUT or PUTREF, it will function as a property.
  167. # If there are both, then the PUT remains a property, and the PUTREF
  168. # gets transformed into a function.
  169. # (in vb, PUT=="obj=other_obj", PUTREF="set obj=other_obj
  170. elif invkind in (pythoncom.INVOKE_PROPERTYPUT, pythoncom.INVOKE_PROPERTYPUTREF):
  171. # Special case
  172. existing = self.propMapPut.get(name, None)
  173. if existing is not None:
  174. if existing.desc[4]==pythoncom.INVOKE_PROPERTYPUT: # Keep this one
  175. map = self.mapFuncs
  176. name = "Set"+name
  177. else: # Existing becomes a func.
  178. existing.wasProperty = 1
  179. self.mapFuncs["Set"+name]=existing
  180. map = self.propMapPut # existing gets overwritten below.
  181. else:
  182. map = self.propMapPut # first time weve seen it.
  183. elif invkind == pythoncom.INVOKE_FUNC:
  184. map = self.mapFuncs
  185. else:
  186. map = None
  187. if not map is None:
  188. # if map.has_key(name):
  189. # sys.stderr.write("Warning - overwriting existing method/attribute %s\n" % name)
  190. map[name] = MapEntry(tuple(fdesc), names, doc, resultCLSID, resultDoc, hidden)
  191. # any methods that can't be reached via DISPATCH we return None
  192. # for, so dynamic dispatch doesnt see it.
  193. if fdesc.funckind != pythoncom.FUNC_DISPATCH:
  194. return None
  195. return (name,map)
  196. return None
  197. def _AddVar_(self,typeinfo,fdesc,bForUser):
  198. ### need pythoncom.VARFLAG_FRESTRICTED ...
  199. ### then check it
  200. if fdesc.varkind == pythoncom.VAR_DISPATCH:
  201. id = fdesc.memid
  202. names = typeinfo.GetNames(id)
  203. # Translate any Alias or Enums in result.
  204. typerepr, flags, defval = fdesc.elemdescVar
  205. typerepr, resultCLSID, resultDoc = _ResolveType(typerepr, typeinfo)
  206. fdesc.elemdescVar = typerepr, flags, defval
  207. doc = None
  208. try:
  209. if bForUser: doc = typeinfo.GetDocumentation(id)
  210. except pythoncom.ole_error:
  211. pass
  212. # handle the enumerator specially
  213. map = self.propMap
  214. # Check if the element is hidden.
  215. hidden = 0
  216. if hasattr(fdesc,"wVarFlags"):
  217. hidden = (fdesc.wVarFlags & 0x40) != 0 # VARFLAG_FHIDDEN
  218. map[names[0]] = MapEntry(tuple(fdesc), names, doc, resultCLSID, resultDoc, hidden)
  219. return (names[0],map)
  220. else:
  221. return None
  222. def Build(self, typeinfo, attr, bForUser = 1):
  223. self.clsid = attr[0]
  224. self.bIsDispatch = (attr.wTypeFlags & pythoncom.TYPEFLAG_FDISPATCHABLE) != 0
  225. if typeinfo is None: return
  226. # Loop over all methods
  227. for j in range(attr[6]):
  228. fdesc = typeinfo.GetFuncDesc(j)
  229. self._AddFunc_(typeinfo,fdesc,bForUser)
  230. # Loop over all variables (ie, properties)
  231. for j in range(attr[7]):
  232. fdesc = typeinfo.GetVarDesc(j)
  233. self._AddVar_(typeinfo,fdesc,bForUser)
  234. # Now post-process the maps. For any "Get" or "Set" properties
  235. # that have arguments, we must turn them into methods. If a method
  236. # of the same name already exists, change the name.
  237. for key, item in list(self.propMapGet.items()):
  238. self._propMapGetCheck_(key,item)
  239. for key, item in list(self.propMapPut.items()):
  240. self._propMapPutCheck_(key,item)
  241. def CountInOutOptArgs(self, argTuple):
  242. "Return tuple counting in/outs/OPTS. Sum of result may not be len(argTuple), as some args may be in/out."
  243. ins = out = opts = 0
  244. for argCheck in argTuple:
  245. inOut = argCheck[1]
  246. if inOut==0:
  247. ins = ins + 1
  248. out = out + 1
  249. else:
  250. if inOut & pythoncom.PARAMFLAG_FIN:
  251. ins = ins + 1
  252. if inOut & pythoncom.PARAMFLAG_FOPT:
  253. opts = opts + 1
  254. if inOut & pythoncom.PARAMFLAG_FOUT:
  255. out = out + 1
  256. return ins, out, opts
  257. def MakeFuncMethod(self, entry, name, bMakeClass = 1):
  258. # If we have a type description, and not varargs...
  259. if entry.desc is not None and (len(entry.desc) < 6 or entry.desc[6]!=-1):
  260. return self.MakeDispatchFuncMethod(entry, name, bMakeClass)
  261. else:
  262. return self.MakeVarArgsFuncMethod(entry, name, bMakeClass)
  263. def MakeDispatchFuncMethod(self, entry, name, bMakeClass = 1):
  264. fdesc = entry.desc
  265. doc = entry.doc
  266. names = entry.names
  267. ret = []
  268. if bMakeClass:
  269. linePrefix = "\t"
  270. defNamedOptArg = "defaultNamedOptArg"
  271. defNamedNotOptArg = "defaultNamedNotOptArg"
  272. defUnnamedArg = "defaultUnnamedArg"
  273. else:
  274. linePrefix = ""
  275. defNamedOptArg = "pythoncom.Missing"
  276. defNamedNotOptArg = "pythoncom.Missing"
  277. defUnnamedArg = "pythoncom.Missing"
  278. defOutArg = "pythoncom.Missing"
  279. id = fdesc[0]
  280. s = linePrefix + 'def ' + name + '(self' + BuildCallList(fdesc, names, defNamedOptArg, defNamedNotOptArg, defUnnamedArg, defOutArg) + '):'
  281. ret.append(s)
  282. if doc and doc[1]:
  283. ret.append(linePrefix + '\t' + _safeQuotedString(doc[1]))
  284. # print "fdesc is ", fdesc
  285. resclsid = entry.GetResultCLSID()
  286. if resclsid:
  287. resclsid = "'%s'" % resclsid
  288. else:
  289. resclsid = 'None'
  290. # Strip the default values from the arg desc
  291. retDesc = fdesc[8][:2]
  292. argsDesc = tuple([what[:2] for what in fdesc[2]])
  293. # The runtime translation of the return types is expensive, so when we know the
  294. # return type of the function, there is no need to check the type at runtime.
  295. # To qualify, this function must return a "simple" type, and have no byref args.
  296. # Check if we have byrefs or anything in the args which mean we still need a translate.
  297. param_flags = [what[1] for what in fdesc[2]]
  298. bad_params = [flag for flag in param_flags if flag & (pythoncom.PARAMFLAG_FOUT | pythoncom.PARAMFLAG_FRETVAL)!=0]
  299. s = None
  300. if len(bad_params)==0 and len(retDesc)==2 and retDesc[1]==0:
  301. rd = retDesc[0]
  302. if rd in NoTranslateMap:
  303. s = '%s\treturn self._oleobj_.InvokeTypes(%d, LCID, %s, %s, %s%s)' % (linePrefix, id, fdesc[4], retDesc, argsDesc, _BuildArgList(fdesc, names))
  304. elif rd in [pythoncom.VT_DISPATCH, pythoncom.VT_UNKNOWN]:
  305. s = '%s\tret = self._oleobj_.InvokeTypes(%d, LCID, %s, %s, %s%s)\n' % (linePrefix, id, fdesc[4], retDesc, repr(argsDesc), _BuildArgList(fdesc, names))
  306. s = s + '%s\tif ret is not None:\n' % (linePrefix,)
  307. if rd == pythoncom.VT_UNKNOWN:
  308. s = s + "%s\t\t# See if this IUnknown is really an IDispatch\n" % (linePrefix,)
  309. s = s + "%s\t\ttry:\n" % (linePrefix,)
  310. s = s + "%s\t\t\tret = ret.QueryInterface(pythoncom.IID_IDispatch)\n" % (linePrefix,)
  311. s = s + "%s\t\texcept pythoncom.error:\n" % (linePrefix,)
  312. s = s + "%s\t\t\treturn ret\n" % (linePrefix,)
  313. s = s + '%s\t\tret = Dispatch(ret, %s, %s)\n' % (linePrefix,repr(name), resclsid)
  314. s = s + '%s\treturn ret' % (linePrefix)
  315. elif rd == pythoncom.VT_BSTR:
  316. s = "%s\t# Result is a Unicode object\n" % (linePrefix,)
  317. s = s + '%s\treturn self._oleobj_.InvokeTypes(%d, LCID, %s, %s, %s%s)' % (linePrefix, id, fdesc[4], retDesc, repr(argsDesc), _BuildArgList(fdesc, names))
  318. # else s remains None
  319. if s is None:
  320. s = '%s\treturn self._ApplyTypes_(%d, %s, %s, %s, %s, %s%s)' % (linePrefix, id, fdesc[4], retDesc, argsDesc, repr(name), resclsid, _BuildArgList(fdesc, names))
  321. ret.append(s)
  322. ret.append("")
  323. return ret
  324. def MakeVarArgsFuncMethod(self, entry, name, bMakeClass = 1):
  325. fdesc = entry.desc
  326. names = entry.names
  327. doc = entry.doc
  328. ret = []
  329. argPrefix = "self"
  330. if bMakeClass:
  331. linePrefix = "\t"
  332. else:
  333. linePrefix = ""
  334. ret.append(linePrefix + 'def ' + name + '(' + argPrefix + ', *args):')
  335. if doc and doc[1]: ret.append(linePrefix + '\t' + _safeQuotedString(doc[1]))
  336. if fdesc:
  337. invoketype = fdesc[4]
  338. else:
  339. invoketype = pythoncom.DISPATCH_METHOD
  340. s = linePrefix + '\treturn self._get_good_object_(self._oleobj_.Invoke(*(('
  341. ret.append(s + str(entry.dispid) + ",0,%d,1)+args)),'%s')" % (invoketype, names[0]))
  342. ret.append("")
  343. return ret
  344. # Note - "DispatchItem" poorly named - need a new intermediate class.
  345. class VTableItem(DispatchItem):
  346. def Build(self, typeinfo, attr, bForUser = 1):
  347. DispatchItem.Build(self, typeinfo, attr, bForUser)
  348. assert typeinfo is not None, "Cant build vtables without type info!"
  349. meth_list = list(self.mapFuncs.values()) + list(self.propMapGet.values()) + list(self.propMapPut.values())
  350. if sys.version_info < (2,4):
  351. def cmp_vtable_off(m1, m2):
  352. return cmp(m1.desc[7], m2.desc[7])
  353. meth_list.sort(cmp_vtable_off)
  354. else:
  355. meth_list.sort(key=lambda m: m.desc[7])
  356. # Now turn this list into the run-time representation
  357. # (ready for immediate use or writing to gencache)
  358. self.vtableFuncs = []
  359. for entry in meth_list:
  360. self.vtableFuncs.append( (entry.names, entry.dispid, entry.desc) )
  361. # A Lazy dispatch item - builds an item on request using info from
  362. # an ITypeComp. The dynamic module makes the called to build each item,
  363. # and also holds the references to the typeinfo and typecomp.
  364. class LazyDispatchItem(DispatchItem):
  365. typename = "LazyDispatchItem"
  366. def __init__(self, attr, doc):
  367. self.clsid = attr[0]
  368. DispatchItem.__init__(self, None, attr, doc, 0)
  369. typeSubstMap = {
  370. pythoncom.VT_INT: pythoncom.VT_I4,
  371. pythoncom.VT_UINT: pythoncom.VT_I4,
  372. pythoncom.VT_HRESULT: pythoncom.VT_I4,
  373. }
  374. def _ResolveType(typerepr, itypeinfo):
  375. # Resolve VT_USERDEFINED (often aliases or typed IDispatches)
  376. if type(typerepr)==tuple:
  377. indir_vt, subrepr = typerepr
  378. if indir_vt == pythoncom.VT_PTR:
  379. # If it is a VT_PTR to a VT_USERDEFINED that is an IDispatch/IUnknown,
  380. # then it resolves to simply the object.
  381. # Otherwise, it becomes a ByRef of the resolved type
  382. # We need to drop an indirection level on pointer to user defined interfaces.
  383. # eg, (VT_PTR, (VT_USERDEFINED, somehandle)) needs to become VT_DISPATCH
  384. # only when "somehandle" is an object.
  385. # but (VT_PTR, (VT_USERDEFINED, otherhandle)) doesnt get the indirection dropped.
  386. was_user = type(subrepr)==tuple and subrepr[0]==pythoncom.VT_USERDEFINED
  387. subrepr, sub_clsid, sub_doc = _ResolveType(subrepr, itypeinfo)
  388. if was_user and subrepr in [pythoncom.VT_DISPATCH, pythoncom.VT_UNKNOWN, pythoncom.VT_RECORD]:
  389. # Drop the VT_PTR indirection
  390. return subrepr, sub_clsid, sub_doc
  391. # Change PTR indirection to byref
  392. return subrepr | pythoncom.VT_BYREF, sub_clsid, sub_doc
  393. if indir_vt == pythoncom.VT_SAFEARRAY:
  394. # resolve the array element, and convert to VT_ARRAY
  395. subrepr, sub_clsid, sub_doc = _ResolveType(subrepr, itypeinfo)
  396. return pythoncom.VT_ARRAY | subrepr, sub_clsid, sub_doc
  397. if indir_vt == pythoncom.VT_CARRAY: # runtime has no support for this yet.
  398. # resolve the array element, and convert to VT_CARRAY
  399. # sheesh - return _something_
  400. return pythoncom.VT_CARRAY, None, None
  401. if indir_vt == pythoncom.VT_USERDEFINED:
  402. try:
  403. resultTypeInfo = itypeinfo.GetRefTypeInfo(subrepr)
  404. except pythoncom.com_error, details:
  405. if details.hresult in [winerror.TYPE_E_CANTLOADLIBRARY, winerror.TYPE_E_LIBNOTREGISTERED]:
  406. # an unregistered interface
  407. return pythoncom.VT_UNKNOWN, None, None
  408. raise
  409. resultAttr = resultTypeInfo.GetTypeAttr()
  410. typeKind = resultAttr.typekind
  411. if typeKind == pythoncom.TKIND_ALIAS:
  412. tdesc = resultAttr.tdescAlias
  413. return _ResolveType(tdesc, resultTypeInfo)
  414. elif typeKind in [pythoncom.TKIND_ENUM, pythoncom.TKIND_MODULE]:
  415. # For now, assume Long
  416. return pythoncom.VT_I4, None, None
  417. elif typeKind == pythoncom.TKIND_DISPATCH:
  418. clsid = resultTypeInfo.GetTypeAttr()[0]
  419. retdoc = resultTypeInfo.GetDocumentation(-1)
  420. return pythoncom.VT_DISPATCH, clsid, retdoc
  421. elif typeKind in [pythoncom.TKIND_INTERFACE,
  422. pythoncom.TKIND_COCLASS]:
  423. # XXX - should probably get default interface for CO_CLASS???
  424. clsid = resultTypeInfo.GetTypeAttr()[0]
  425. retdoc = resultTypeInfo.GetDocumentation(-1)
  426. return pythoncom.VT_UNKNOWN, clsid, retdoc
  427. elif typeKind == pythoncom.TKIND_RECORD:
  428. return pythoncom.VT_RECORD, None, None
  429. raise NotSupportedException("Can not resolve alias or user-defined type")
  430. return typeSubstMap.get(typerepr,typerepr), None, None
  431. def _BuildArgList(fdesc, names):
  432. "Builds list of args to the underlying Invoke method."
  433. # Word has TypeInfo for Insert() method, but says "no args"
  434. numArgs = max(fdesc[6], len(fdesc[2]))
  435. names = list(names)
  436. while None in names:
  437. i = names.index(None)
  438. names[i] = "arg%d" % (i,)
  439. names = list(map(MakePublicAttributeName, names[1:]))
  440. name_num = 0
  441. while len(names) < numArgs:
  442. names.append("arg%d" % (len(names),))
  443. # As per BuildCallList(), avoid huge lines.
  444. # Hack a "\n" at the end of every 5th name - "strides" would be handy
  445. # here but don't exist in 2.2
  446. for i in range(0, len(names), 5):
  447. names[i] = names[i] + "\n\t\t\t"
  448. return "," + ", ".join(names)
  449. valid_identifier_chars = string.ascii_letters + string.digits + "_"
  450. def demunge_leading_underscores(className):
  451. i = 0
  452. while className[i] == "_":
  453. i += 1
  454. assert i >= 2, "Should only be here with names starting with '__'"
  455. return className[i-1:] + className[:i-1]
  456. # Given a "public name" (eg, the name of a class, function, etc)
  457. # make sure it is a legal (and reasonable!) Python name.
  458. def MakePublicAttributeName(className, is_global = False):
  459. # Given a class attribute that needs to be public, convert it to a
  460. # reasonable name.
  461. # Also need to be careful that the munging doesnt
  462. # create duplicates - eg, just removing a leading "_" is likely to cause
  463. # a clash.
  464. # if is_global is True, then the name is a global variable that may
  465. # overwrite a builtin - eg, "None"
  466. if className[:2]=='__':
  467. return demunge_leading_underscores(className)
  468. elif className == 'None':
  469. # assign to None is evil (and SyntaxError in 2.4, even though
  470. # iskeyword says False there) - note that if it was a global
  471. # it would get picked up below
  472. className = 'NONE'
  473. elif iskeyword(className):
  474. # most keywords are lower case (except True, False etc in py3k)
  475. ret = className.capitalize()
  476. # but those which aren't get forced upper.
  477. if ret == className:
  478. ret = ret.upper()
  479. return ret
  480. elif is_global and hasattr(__builtins__, className):
  481. # builtins may be mixed case. If capitalizing it doesn't change it,
  482. # force to all uppercase (eg, "None", "True" become "NONE", "TRUE"
  483. ret = className.capitalize()
  484. if ret==className: # didn't change - force all uppercase.
  485. ret = ret.upper()
  486. return ret
  487. # Strip non printable chars
  488. return ''.join([char for char in className if char in valid_identifier_chars])
  489. # Given a default value passed by a type library, return a string with
  490. # an appropriate repr() for the type.
  491. # Takes a raw ELEMDESC and returns a repr string, or None
  492. # (NOTE: The string itself may be '"None"', which is valid, and different to None.
  493. # XXX - To do: Dates are probably screwed, but can they come in?
  494. def MakeDefaultArgRepr(defArgVal):
  495. try:
  496. inOut = defArgVal[1]
  497. except IndexError:
  498. # something strange - assume is in param.
  499. inOut = pythoncom.PARAMFLAG_FIN
  500. if inOut & pythoncom.PARAMFLAG_FHASDEFAULT:
  501. # times need special handling...
  502. val = defArgVal[2]
  503. if isinstance(val, datetime.datetime):
  504. # VARIANT <-> SYSTEMTIME conversions always lose any sub-second
  505. # resolution, so just use a 'timetuple' here.
  506. return repr(tuple(val.utctimetuple()))
  507. if type(val) is TimeType:
  508. # must be the 'old' pywintypes time object...
  509. year=val.year; month=val.month; day=val.day; hour=val.hour; minute=val.minute; second=val.second; msec=val.msec
  510. return "pywintypes.Time((%(year)d, %(month)d, %(day)d, %(hour)d, %(minute)d, %(second)d,0,0,0,%(msec)d))" % locals()
  511. return repr(val)
  512. return None
  513. def BuildCallList(fdesc, names, defNamedOptArg, defNamedNotOptArg, defUnnamedArg, defOutArg, is_comment = False):
  514. "Builds a Python declaration for a method."
  515. # Names[0] is the func name - param names are from 1.
  516. numArgs = len(fdesc[2])
  517. numOptArgs = fdesc[6]
  518. strval = ''
  519. if numOptArgs==-1: # Special value that says "var args after here"
  520. firstOptArg = numArgs
  521. numArgs = numArgs - 1
  522. else:
  523. firstOptArg = numArgs - numOptArgs
  524. for arg in xrange(numArgs):
  525. try:
  526. argName = names[arg+1]
  527. namedArg = argName is not None
  528. except IndexError:
  529. namedArg = 0
  530. if not namedArg: argName = "arg%d" % (arg)
  531. thisdesc = fdesc[2][arg]
  532. # See if the IDL specified a default value
  533. defArgVal = MakeDefaultArgRepr(thisdesc)
  534. if defArgVal is None:
  535. # Out params always get their special default
  536. if thisdesc[1] & (pythoncom.PARAMFLAG_FOUT | pythoncom.PARAMFLAG_FIN) == pythoncom.PARAMFLAG_FOUT:
  537. defArgVal = defOutArg
  538. else:
  539. # Unnamed arg - always allow default values.
  540. if namedArg:
  541. # Is a named argument
  542. if arg >= firstOptArg:
  543. defArgVal = defNamedOptArg
  544. else:
  545. defArgVal = defNamedNotOptArg
  546. else:
  547. defArgVal = defUnnamedArg
  548. argName = MakePublicAttributeName(argName)
  549. # insanely long lines with an 'encoding' flag crashes python 2.4.0
  550. # keep 5 args per line
  551. # This may still fail if the arg names are insane, but that seems
  552. # unlikely. See also _BuildArgList()
  553. if (arg+1) % 5 == 0:
  554. strval = strval + "\n"
  555. if is_comment:
  556. strval = strval + "#"
  557. strval = strval + "\t\t\t"
  558. strval = strval + ", " + argName
  559. if defArgVal:
  560. strval = strval + "=" + defArgVal
  561. if numOptArgs==-1:
  562. strval = strval + ", *" + names[-1]
  563. return strval
  564. if __name__=='__main__':
  565. print "Use 'makepy.py' to generate Python code - this module is just a helper"