Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
build.py790 linesDownload Raw Back to client
1"""Contains knowledge to build a COM object definition.2 3This module is used by both the @dynamic@ and @makepy@ modules to build4all knowledge of a COM object.5 6This module contains classes which contain the actual knowledge of the object.7This include parameter and return type information, the COM dispid and CLSID, etc.8 9Other modules may use this information to generate .py files, use the information10dynamically, or possibly even generate .html documentation for objects.11"""12 13#14# NOTES: DispatchItem and MapEntry used by dynamic.py.15#        the rest is used by makepy.py16#17#        OleItem, DispatchItem, MapEntry, BuildCallList() is used by makepy18 19import datetime20import string21import sys22from keyword import iskeyword23 24import pythoncom25import winerror26from pywintypes import TimeType27 28 29# It isn't really clear what the quoting rules are in a C/IDL string and30# literals like a quote char and backslashes makes life a little painful to31# always render the string perfectly - so just punt and fall-back to a repr()32def _makeDocString(s):33    if sys.version_info < (3,):34        s = s.encode("mbcs")35    return repr(s)36 37 38error = "PythonCOM.Client.Build error"39 40 41class NotSupportedException(Exception):42    pass  # Raised when we cant support a param type.43 44 45DropIndirection = "DropIndirection"46 47NoTranslateTypes = [48    pythoncom.VT_BOOL,49    pythoncom.VT_CLSID,50    pythoncom.VT_CY,51    pythoncom.VT_DATE,52    pythoncom.VT_DECIMAL,53    pythoncom.VT_EMPTY,54    pythoncom.VT_ERROR,55    pythoncom.VT_FILETIME,56    pythoncom.VT_HRESULT,57    pythoncom.VT_I1,58    pythoncom.VT_I2,59    pythoncom.VT_I4,60    pythoncom.VT_I8,61    pythoncom.VT_INT,62    pythoncom.VT_NULL,63    pythoncom.VT_R4,64    pythoncom.VT_R8,65    pythoncom.VT_NULL,66    pythoncom.VT_STREAM,67    pythoncom.VT_UI1,68    pythoncom.VT_UI2,69    pythoncom.VT_UI4,70    pythoncom.VT_UI8,71    pythoncom.VT_UINT,72    pythoncom.VT_VOID,73]74 75NoTranslateMap = {}76for v in NoTranslateTypes:77    NoTranslateMap[v] = None78 79 80class MapEntry:81    "Simple holder for named attibutes - items in a map."82 83    def __init__(84        self,85        desc_or_id,86        names=None,87        doc=None,88        resultCLSID=pythoncom.IID_NULL,89        resultDoc=None,90        hidden=0,91    ):92        if type(desc_or_id) == type(0):93            self.dispid = desc_or_id94            self.desc = None95        else:96            self.dispid = desc_or_id[0]97            self.desc = desc_or_id98 99        self.names = names100        self.doc = doc101        self.resultCLSID = resultCLSID102        self.resultDocumentation = resultDoc103        self.wasProperty = (104            0  # Have I been transformed into a function so I can pass args?105        )106        self.hidden = hidden107 108    def __repr__(self):109        return (110            "MapEntry(dispid={s.dispid}, desc={s.desc}, names={s.names}, doc={s.doc!r}, "111            "resultCLSID={s.resultCLSID}, resultDocumentation={s.resultDocumentation}, "112            "wasProperty={s.wasProperty}, hidden={s.hidden}"113        ).format(s=self)114 115    def GetResultCLSID(self):116        rc = self.resultCLSID117        if rc == pythoncom.IID_NULL:118            return None119        return rc120 121    # Return a string, suitable for output - either "'{...}'" or "None"122    def GetResultCLSIDStr(self):123        rc = self.GetResultCLSID()124        if rc is None:125            return "None"126        return repr(127            str(rc)128        )  # Convert the IID object to a string, then to a string in a string.129 130    def GetResultName(self):131        if self.resultDocumentation is None:132            return None133        return self.resultDocumentation[0]134 135 136class OleItem:137    typename = "OleItem"138 139    def __init__(self, doc=None):140        self.doc = doc141        if self.doc:142            self.python_name = MakePublicAttributeName(self.doc[0])143        else:144            self.python_name = None145        self.bWritten = 0146        self.bIsDispatch = 0147        self.bIsSink = 0148        self.clsid = None149        self.co_class = None150 151 152class DispatchItem(OleItem):153    typename = "DispatchItem"154 155    def __init__(self, typeinfo=None, attr=None, doc=None, bForUser=1):156        OleItem.__init__(self, doc)157        self.propMap = {}158        self.propMapGet = {}159        self.propMapPut = {}160        self.mapFuncs = {}161        self.defaultDispatchName = None162        self.hidden = 0163 164        if typeinfo:165            self.Build(typeinfo, attr, bForUser)166 167    def _propMapPutCheck_(self, key, item):168        ins, outs, opts = self.CountInOutOptArgs(item.desc[2])169        if ins > 1:  # if a Put property takes more than 1 arg:170            if opts + 1 == ins or ins == item.desc[6] + 1:171                newKey = "Set" + key172                deleteExisting = 0  # This one is still OK173            else:174                deleteExisting = 1  # No good to us175                if key in self.mapFuncs or key in self.propMapGet:176                    newKey = "Set" + key177                else:178                    newKey = key179            item.wasProperty = 1180            self.mapFuncs[newKey] = item181            if deleteExisting:182                del self.propMapPut[key]183 184    def _propMapGetCheck_(self, key, item):185        ins, outs, opts = self.CountInOutOptArgs(item.desc[2])186        if ins > 0:  # if a Get property takes _any_ in args:187            if item.desc[6] == ins or ins == opts:188                newKey = "Get" + key189                deleteExisting = 0  # This one is still OK190            else:191                deleteExisting = 1  # No good to us192                if key in self.mapFuncs:193                    newKey = "Get" + key194                else:195                    newKey = key196            item.wasProperty = 1197            self.mapFuncs[newKey] = item198            if deleteExisting:199                del self.propMapGet[key]200 201    def _AddFunc_(self, typeinfo, fdesc, bForUser):202        assert fdesc.desckind == pythoncom.DESCKIND_FUNCDESC203        id = fdesc.memid204        funcflags = fdesc.wFuncFlags205        try:206            names = typeinfo.GetNames(id)207            name = names[0]208        except pythoncom.ole_error:209            name = ""210            names = None211 212        doc = None213        try:214            if bForUser:215                doc = typeinfo.GetDocumentation(id)216        except pythoncom.ole_error:217            pass218 219        if id == 0 and name:220            self.defaultDispatchName = name221 222        invkind = fdesc.invkind223 224        # We need to translate any Alias', Enums, structs etc in result and args225        typerepr, flag, defval = fdesc.rettype226        # 		sys.stderr.write("%s result - %s -> " % (name, typerepr))227        typerepr, resultCLSID, resultDoc = _ResolveType(typerepr, typeinfo)228        # 		sys.stderr.write("%s\n" % (typerepr,))229        fdesc.rettype = typerepr, flag, defval, resultCLSID230        # Translate any Alias or Enums in argument list.231        argList = []232        for argDesc in fdesc.args:233            typerepr, flag, defval = argDesc234            # 			sys.stderr.write("%s arg - %s -> " % (name, typerepr))235            arg_type, arg_clsid, arg_doc = _ResolveType(typerepr, typeinfo)236            argDesc = arg_type, flag, defval, arg_clsid237            # 			sys.stderr.write("%s\n" % (argDesc[0],))238            argList.append(argDesc)239        fdesc.args = tuple(argList)240 241        hidden = (funcflags & pythoncom.FUNCFLAG_FHIDDEN) != 0242        if invkind == pythoncom.INVOKE_PROPERTYGET:243            map = self.propMapGet244        # This is not the best solution, but I dont think there is245        # one without specific "set" syntax.246        # If there is a single PUT or PUTREF, it will function as a property.247        # If there are both, then the PUT remains a property, and the PUTREF248        # gets transformed into a function.249        # (in vb, PUT=="obj=other_obj", PUTREF="set obj=other_obj250        elif invkind in (pythoncom.INVOKE_PROPERTYPUT, pythoncom.INVOKE_PROPERTYPUTREF):251            # Special case252            existing = self.propMapPut.get(name, None)253            if existing is not None:254                if existing.desc[4] == pythoncom.INVOKE_PROPERTYPUT:  # Keep this one255                    map = self.mapFuncs256                    name = "Set" + name257                else:  # Existing becomes a func.258                    existing.wasProperty = 1259                    self.mapFuncs["Set" + name] = existing260                    map = self.propMapPut  # existing gets overwritten below.261            else:262                map = self.propMapPut  # first time weve seen it.263 264        elif invkind == pythoncom.INVOKE_FUNC:265            map = self.mapFuncs266        else:267            map = None268        if not map is None:269            # 				if map.has_key(name):270            # 					sys.stderr.write("Warning - overwriting existing method/attribute %s\n" % name)271            map[name] = MapEntry(fdesc, names, doc, resultCLSID, resultDoc, hidden)272            # any methods that can't be reached via DISPATCH we return None273            # for, so dynamic dispatch doesnt see it.274            if fdesc.funckind != pythoncom.FUNC_DISPATCH:275                return None276            return (name, map)277        return None278 279    def _AddVar_(self, typeinfo, vardesc, bForUser):280        ### need pythoncom.VARFLAG_FRESTRICTED ...281        ### then check it282        assert vardesc.desckind == pythoncom.DESCKIND_VARDESC283 284        if vardesc.varkind == pythoncom.VAR_DISPATCH:285            id = vardesc.memid286            names = typeinfo.GetNames(id)287            # Translate any Alias or Enums in result.288            typerepr, flags, defval = vardesc.elemdescVar289            typerepr, resultCLSID, resultDoc = _ResolveType(typerepr, typeinfo)290            vardesc.elemdescVar = typerepr, flags, defval291            doc = None292            try:293                if bForUser:294                    doc = typeinfo.GetDocumentation(id)295            except pythoncom.ole_error:296                pass297 298            # handle the enumerator specially299            map = self.propMap300            # Check if the element is hidden.301            hidden = (vardesc.wVarFlags & 0x40) != 0  # VARFLAG_FHIDDEN302            map[names[0]] = MapEntry(303                vardesc, names, doc, resultCLSID, resultDoc, hidden304            )305            return (names[0], map)306        else:307            return None308 309    def Build(self, typeinfo, attr, bForUser=1):310        self.clsid = attr[0]311        self.bIsDispatch = (attr.wTypeFlags & pythoncom.TYPEFLAG_FDISPATCHABLE) != 0312        if typeinfo is None:313            return314        # Loop over all methods315        for j in range(attr[6]):316            fdesc = typeinfo.GetFuncDesc(j)317            self._AddFunc_(typeinfo, fdesc, bForUser)318 319        # Loop over all variables (ie, properties)320        for j in range(attr[7]):321            fdesc = typeinfo.GetVarDesc(j)322            self._AddVar_(typeinfo, fdesc, bForUser)323 324        # Now post-process the maps.  For any "Get" or "Set" properties325        # that have arguments, we must turn them into methods.  If a method326        # of the same name already exists, change the name.327        for key, item in list(self.propMapGet.items()):328            self._propMapGetCheck_(key, item)329 330        for key, item in list(self.propMapPut.items()):331            self._propMapPutCheck_(key, item)332 333    def CountInOutOptArgs(self, argTuple):334        "Return tuple counting in/outs/OPTS.  Sum of result may not be len(argTuple), as some args may be in/out."335        ins = out = opts = 0336        for argCheck in argTuple:337            inOut = argCheck[1]338            if inOut == 0:339                ins = ins + 1340                out = out + 1341            else:342                if inOut & pythoncom.PARAMFLAG_FIN:343                    ins = ins + 1344                if inOut & pythoncom.PARAMFLAG_FOPT:345                    opts = opts + 1346                if inOut & pythoncom.PARAMFLAG_FOUT:347                    out = out + 1348        return ins, out, opts349 350    def MakeFuncMethod(self, entry, name, bMakeClass=1):351        # If we have a type description, and not varargs...352        if entry.desc is not None and (len(entry.desc) < 6 or entry.desc[6] != -1):353            return self.MakeDispatchFuncMethod(entry, name, bMakeClass)354        else:355            return self.MakeVarArgsFuncMethod(entry, name, bMakeClass)356 357    def MakeDispatchFuncMethod(self, entry, name, bMakeClass=1):358        fdesc = entry.desc359        doc = entry.doc360        names = entry.names361        ret = []362        if bMakeClass:363            linePrefix = "\t"364            defNamedOptArg = "defaultNamedOptArg"365            defNamedNotOptArg = "defaultNamedNotOptArg"366            defUnnamedArg = "defaultUnnamedArg"367        else:368            linePrefix = ""369            defNamedOptArg = "pythoncom.Missing"370            defNamedNotOptArg = "pythoncom.Missing"371            defUnnamedArg = "pythoncom.Missing"372        defOutArg = "pythoncom.Missing"373        id = fdesc[0]374 375        s = (376            linePrefix377            + "def "378            + name379            + "(self"380            + BuildCallList(381                fdesc,382                names,383                defNamedOptArg,384                defNamedNotOptArg,385                defUnnamedArg,386                defOutArg,387            )388            + "):"389        )390        ret.append(s)391        if doc and doc[1]:392            ret.append(linePrefix + "\t" + _makeDocString(doc[1]))393 394        resclsid = entry.GetResultCLSID()395        if resclsid:396            resclsid = "'%s'" % resclsid397        else:398            resclsid = "None"399        # Strip the default values from the arg desc400        retDesc = fdesc[8][:2]401        argsDesc = tuple([what[:2] for what in fdesc[2]])402        # The runtime translation of the return types is expensive, so when we know the403        # return type of the function, there is no need to check the type at runtime.404        # To qualify, this function must return a "simple" type, and have no byref args.405        # Check if we have byrefs or anything in the args which mean we still need a translate.406        param_flags = [what[1] for what in fdesc[2]]407        bad_params = [408            flag409            for flag in param_flags410            if flag & (pythoncom.PARAMFLAG_FOUT | pythoncom.PARAMFLAG_FRETVAL) != 0411        ]412        s = None413        if len(bad_params) == 0 and len(retDesc) == 2 and retDesc[1] == 0:414            rd = retDesc[0]415            if rd in NoTranslateMap:416                s = "%s\treturn self._oleobj_.InvokeTypes(%d, LCID, %s, %s, %s%s)" % (417                    linePrefix,418                    id,419                    fdesc[4],420                    retDesc,421                    argsDesc,422                    _BuildArgList(fdesc, names),423                )424            elif rd in [pythoncom.VT_DISPATCH, pythoncom.VT_UNKNOWN]:425                s = "%s\tret = self._oleobj_.InvokeTypes(%d, LCID, %s, %s, %s%s)\n" % (426                    linePrefix,427                    id,428                    fdesc[4],429                    retDesc,430                    repr(argsDesc),431                    _BuildArgList(fdesc, names),432                )433                s = s + "%s\tif ret is not None:\n" % (linePrefix,)434                if rd == pythoncom.VT_UNKNOWN:435                    s = s + "%s\t\t# See if this IUnknown is really an IDispatch\n" % (436                        linePrefix,437                    )438                    s = s + "%s\t\ttry:\n" % (linePrefix,)439                    s = (440                        s441                        + "%s\t\t\tret = ret.QueryInterface(pythoncom.IID_IDispatch)\n"442                        % (linePrefix,)443                    )444                    s = s + "%s\t\texcept pythoncom.error:\n" % (linePrefix,)445                    s = s + "%s\t\t\treturn ret\n" % (linePrefix,)446                s = s + "%s\t\tret = Dispatch(ret, %s, %s)\n" % (447                    linePrefix,448                    repr(name),449                    resclsid,450                )451                s = s + "%s\treturn ret" % (linePrefix)452            elif rd == pythoncom.VT_BSTR:453                s = "%s\t# Result is a Unicode object\n" % (linePrefix,)454                s = (455                    s456                    + "%s\treturn self._oleobj_.InvokeTypes(%d, LCID, %s, %s, %s%s)"457                    % (458                        linePrefix,459                        id,460                        fdesc[4],461                        retDesc,462                        repr(argsDesc),463                        _BuildArgList(fdesc, names),464                    )465                )466            # else s remains None467        if s is None:468            s = "%s\treturn self._ApplyTypes_(%d, %s, %s, %s, %s, %s%s)" % (469                linePrefix,470                id,471                fdesc[4],472                retDesc,473                argsDesc,474                repr(name),475                resclsid,476                _BuildArgList(fdesc, names),477            )478 479        ret.append(s)480        ret.append("")481        return ret482 483    def MakeVarArgsFuncMethod(self, entry, name, bMakeClass=1):484        fdesc = entry.desc485        names = entry.names486        doc = entry.doc487        ret = []488        argPrefix = "self"489        if bMakeClass:490            linePrefix = "\t"491        else:492            linePrefix = ""493        ret.append(linePrefix + "def " + name + "(" + argPrefix + ", *args):")494        if doc and doc[1]:495            ret.append(linePrefix + "\t" + _makeDocString(doc[1]))496        if fdesc:497            invoketype = fdesc[4]498        else:499            invoketype = pythoncom.DISPATCH_METHOD500        s = linePrefix + "\treturn self._get_good_object_(self._oleobj_.Invoke(*(("501        ret.append(502            s + str(entry.dispid) + ",0,%d,1)+args)),'%s')" % (invoketype, names[0])503        )504        ret.append("")505        return ret506 507 508# Note - "DispatchItem" poorly named - need a new intermediate class.509class VTableItem(DispatchItem):510    def Build(self, typeinfo, attr, bForUser=1):511        DispatchItem.Build(self, typeinfo, attr, bForUser)512        assert typeinfo is not None, "Cant build vtables without type info!"513 514        meth_list = (515            list(self.mapFuncs.values())516            + list(self.propMapGet.values())517            + list(self.propMapPut.values())518        )519        meth_list.sort(key=lambda m: m.desc[7])520 521        # Now turn this list into the run-time representation522        # (ready for immediate use or writing to gencache)523        self.vtableFuncs = []524        for entry in meth_list:525            self.vtableFuncs.append((entry.names, entry.dispid, entry.desc))526 527 528# A Lazy dispatch item - builds an item on request using info from529# an ITypeComp.  The dynamic module makes the called to build each item,530# and also holds the references to the typeinfo and typecomp.531class LazyDispatchItem(DispatchItem):532    typename = "LazyDispatchItem"533 534    def __init__(self, attr, doc):535        self.clsid = attr[0]536        DispatchItem.__init__(self, None, attr, doc, 0)537 538 539typeSubstMap = {540    pythoncom.VT_INT: pythoncom.VT_I4,541    pythoncom.VT_UINT: pythoncom.VT_UI4,542    pythoncom.VT_HRESULT: pythoncom.VT_I4,543}544 545 546def _ResolveType(typerepr, itypeinfo):547    # Resolve VT_USERDEFINED (often aliases or typed IDispatches)548 549    if type(typerepr) == tuple:550        indir_vt, subrepr = typerepr551        if indir_vt == pythoncom.VT_PTR:552            # If it is a VT_PTR to a VT_USERDEFINED that is an IDispatch/IUnknown,553            # then it resolves to simply the object.554            # Otherwise, it becomes a ByRef of the resolved type555            # We need to drop an indirection level on pointer to user defined interfaces.556            # eg, (VT_PTR, (VT_USERDEFINED, somehandle)) needs to become VT_DISPATCH557            # only when "somehandle" is an object.558            # but (VT_PTR, (VT_USERDEFINED, otherhandle)) doesnt get the indirection dropped.559            was_user = type(subrepr) == tuple and subrepr[0] == pythoncom.VT_USERDEFINED560            subrepr, sub_clsid, sub_doc = _ResolveType(subrepr, itypeinfo)561            if was_user and subrepr in [562                pythoncom.VT_DISPATCH,563                pythoncom.VT_UNKNOWN,564                pythoncom.VT_RECORD,565            ]:566                # Drop the VT_PTR indirection567                return subrepr, sub_clsid, sub_doc568            # Change PTR indirection to byref569            return subrepr | pythoncom.VT_BYREF, sub_clsid, sub_doc570        if indir_vt == pythoncom.VT_SAFEARRAY:571            # resolve the array element, and convert to VT_ARRAY572            subrepr, sub_clsid, sub_doc = _ResolveType(subrepr, itypeinfo)573            return pythoncom.VT_ARRAY | subrepr, sub_clsid, sub_doc574        if indir_vt == pythoncom.VT_CARRAY:  # runtime has no support for this yet.575            # resolve the array element, and convert to VT_CARRAY576            # sheesh - return _something_577            return pythoncom.VT_CARRAY, None, None578        if indir_vt == pythoncom.VT_USERDEFINED:579            try:580                resultTypeInfo = itypeinfo.GetRefTypeInfo(subrepr)581            except pythoncom.com_error as details:582                if details.hresult in [583                    winerror.TYPE_E_CANTLOADLIBRARY,584                    winerror.TYPE_E_LIBNOTREGISTERED,585                ]:586                    # an unregistered interface587                    return pythoncom.VT_UNKNOWN, None, None588                raise589 590            resultAttr = resultTypeInfo.GetTypeAttr()591            typeKind = resultAttr.typekind592            if typeKind == pythoncom.TKIND_ALIAS:593                tdesc = resultAttr.tdescAlias594                return _ResolveType(tdesc, resultTypeInfo)595            elif typeKind in [pythoncom.TKIND_ENUM, pythoncom.TKIND_MODULE]:596                # For now, assume Long597                return pythoncom.VT_I4, None, None598 599            elif typeKind == pythoncom.TKIND_DISPATCH:600                clsid = resultTypeInfo.GetTypeAttr()[0]601                retdoc = resultTypeInfo.GetDocumentation(-1)602                return pythoncom.VT_DISPATCH, clsid, retdoc603 604            elif typeKind in [pythoncom.TKIND_INTERFACE, pythoncom.TKIND_COCLASS]:605                # XXX - should probably get default interface for CO_CLASS???606                clsid = resultTypeInfo.GetTypeAttr()[0]607                retdoc = resultTypeInfo.GetDocumentation(-1)608                return pythoncom.VT_UNKNOWN, clsid, retdoc609 610            elif typeKind == pythoncom.TKIND_RECORD:611                return pythoncom.VT_RECORD, None, None612            raise NotSupportedException("Can not resolve alias or user-defined type")613    return typeSubstMap.get(typerepr, typerepr), None, None614 615 616def _BuildArgList(fdesc, names):617    "Builds list of args to the underlying Invoke method."618    # Word has TypeInfo for Insert() method, but says "no args"619    numArgs = max(fdesc[6], len(fdesc[2]))620    names = list(names)621    while None in names:622        i = names.index(None)623        names[i] = "arg%d" % (i,)624    # We've seen 'source safe' libraries offer the name of 'ret' params in625    # 'names' - although we can't reproduce this, it would be insane to offer626    # more args than we have arg infos for - hence the upper limit on names...627    names = list(map(MakePublicAttributeName, names[1 : (numArgs + 1)]))628    name_num = 0629    while len(names) < numArgs:630        names.append("arg%d" % (len(names),))631    # As per BuildCallList(), avoid huge lines.632    # Hack a "\n" at the end of every 5th name - "strides" would be handy633    # here but don't exist in 2.2634    for i in range(0, len(names), 5):635        names[i] = names[i] + "\n\t\t\t"636    return "," + ", ".join(names)637 638 639valid_identifier_chars = string.ascii_letters + string.digits + "_"640 641 642def demunge_leading_underscores(className):643    i = 0644    while className[i] == "_":645        i += 1646    assert i >= 2, "Should only be here with names starting with '__'"647    return className[i - 1 :] + className[: i - 1]648 649 650# Given a "public name" (eg, the name of a class, function, etc)651# make sure it is a legal (and reasonable!) Python name.652def MakePublicAttributeName(className, is_global=False):653    # Given a class attribute that needs to be public, convert it to a654    # reasonable name.655    # Also need to be careful that the munging doesnt656    # create duplicates - eg, just removing a leading "_" is likely to cause657    # a clash.658    # if is_global is True, then the name is a global variable that may659    # overwrite a builtin - eg, "None"660    if className[:2] == "__":661        return demunge_leading_underscores(className)662    elif className == "None":663        # assign to None is evil (and SyntaxError in 2.4, even though664        # iskeyword says False there) - note that if it was a global665        # it would get picked up below666        className = "NONE"667    elif iskeyword(className):668        # most keywords are lower case (except True, False etc in py3k)669        ret = className.capitalize()670        # but those which aren't get forced upper.671        if ret == className:672            ret = ret.upper()673        return ret674    elif is_global and hasattr(__builtins__, className):675        # builtins may be mixed case.  If capitalizing it doesn't change it,676        # force to all uppercase (eg, "None", "True" become "NONE", "TRUE"677        ret = className.capitalize()678        if ret == className:  # didn't change - force all uppercase.679            ret = ret.upper()680        return ret681    # Strip non printable chars682    return "".join([char for char in className if char in valid_identifier_chars])683 684 685# Given a default value passed by a type library, return a string with686# an appropriate repr() for the type.687# Takes a raw ELEMDESC and returns a repr string, or None688# (NOTE: The string itself may be '"None"', which is valid, and different to None.689# XXX - To do: Dates are probably screwed, but can they come in?690def MakeDefaultArgRepr(defArgVal):691    try:692        inOut = defArgVal[1]693    except IndexError:694        # something strange - assume is in param.695        inOut = pythoncom.PARAMFLAG_FIN696 697    if inOut & pythoncom.PARAMFLAG_FHASDEFAULT:698        # times need special handling...699        val = defArgVal[2]700        if isinstance(val, datetime.datetime):701            # VARIANT <-> SYSTEMTIME conversions always lose any sub-second702            # resolution, so just use a 'timetuple' here.703            return repr(tuple(val.utctimetuple()))704        if type(val) is TimeType:705            # must be the 'old' pywintypes time object...706            year = val.year707            month = val.month708            day = val.day709            hour = val.hour710            minute = val.minute711            second = val.second712            msec = val.msec713            return (714                "pywintypes.Time((%(year)d, %(month)d, %(day)d, %(hour)d, %(minute)d, %(second)d,0,0,0,%(msec)d))"715                % locals()716            )717        return repr(val)718    return None719 720 721def BuildCallList(722    fdesc,723    names,724    defNamedOptArg,725    defNamedNotOptArg,726    defUnnamedArg,727    defOutArg,728    is_comment=False,729):730    "Builds a Python declaration for a method."731    # Names[0] is the func name - param names are from 1.732    numArgs = len(fdesc[2])733    numOptArgs = fdesc[6]734    strval = ""735    if numOptArgs == -1:  # Special value that says "var args after here"736        firstOptArg = numArgs737        numArgs = numArgs - 1738    else:739        firstOptArg = numArgs - numOptArgs740    for arg in range(numArgs):741        try:742            argName = names[arg + 1]743            namedArg = argName is not None744        except IndexError:745            namedArg = 0746        if not namedArg:747            argName = "arg%d" % (arg)748        thisdesc = fdesc[2][arg]749        # See if the IDL specified a default value750        defArgVal = MakeDefaultArgRepr(thisdesc)751        if defArgVal is None:752            # Out params always get their special default753            if (754                thisdesc[1] & (pythoncom.PARAMFLAG_FOUT | pythoncom.PARAMFLAG_FIN)755                == pythoncom.PARAMFLAG_FOUT756            ):757                defArgVal = defOutArg758            else:759                # Unnamed arg - always allow default values.760                if namedArg:761                    # Is a named argument762                    if arg >= firstOptArg:763                        defArgVal = defNamedOptArg764                    else:765                        defArgVal = defNamedNotOptArg766                else:767                    defArgVal = defUnnamedArg768 769        argName = MakePublicAttributeName(argName)770        # insanely long lines with an 'encoding' flag crashes python 2.4.0771        # keep 5 args per line772        # This may still fail if the arg names are insane, but that seems773        # unlikely.  See also _BuildArgList()774        if (arg + 1) % 5 == 0:775            strval = strval + "\n"776            if is_comment:777                strval = strval + "#"778            strval = strval + "\t\t\t"779        strval = strval + ", " + argName780        if defArgVal:781            strval = strval + "=" + defArgVal782    if numOptArgs == -1:783        strval = strval + ", *" + names[-1]784 785    return strval786 787 788if __name__ == "__main__":789    print("Use 'makepy.py' to generate Python code - this module is just a helper")790 
codekingpro/portable-devtools · Team Ai