Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
genpy.py1412 linesDownload Raw Back to client
1"""genpy.py - The worker for makepy.  See makepy.py for more details2 3This code was moved simply to speed Python in normal circumstances.  As the makepy.py4is normally run from the command line, it reparses the code each time.  Now makepy5is nothing more than the command line handler and public interface.6 7The makepy command line etc handling is also getting large enough in its own right!8"""9 10# NOTE - now supports a "demand" mechanism - the top-level is a package, and11# each class etc can be made individually.12# This should eventually become the default.13# Then the old non-package technique should be removed.14# There should be no b/w compat issues, and will just help clean the code.15# This will be done once the new "demand" mechanism gets a good workout.16import os17import sys18import time19 20import pythoncom21import win32com22 23from . import build24 25error = "makepy.error"26makepy_version = "0.5.01"  # Written to generated file.27 28GEN_FULL = "full"29GEN_DEMAND_BASE = "demand(base)"30GEN_DEMAND_CHILD = "demand(child)"31 32# This map is used purely for the users benefit -it shows the33# raw, underlying type of Alias/Enums, etc.  The COM implementation34# does not use this map at runtime - all Alias/Enum have already35# been translated.36mapVTToTypeString = {37    pythoncom.VT_I2: "types.IntType",38    pythoncom.VT_I4: "types.IntType",39    pythoncom.VT_R4: "types.FloatType",40    pythoncom.VT_R8: "types.FloatType",41    pythoncom.VT_BSTR: "types.StringType",42    pythoncom.VT_BOOL: "types.IntType",43    pythoncom.VT_VARIANT: "types.TypeType",44    pythoncom.VT_I1: "types.IntType",45    pythoncom.VT_UI1: "types.IntType",46    pythoncom.VT_UI2: "types.IntType",47    pythoncom.VT_UI4: "types.IntType",48    pythoncom.VT_I8: "types.LongType",49    pythoncom.VT_UI8: "types.LongType",50    pythoncom.VT_INT: "types.IntType",51    pythoncom.VT_DATE: "pythoncom.PyTimeType",52    pythoncom.VT_UINT: "types.IntType",53}54 55 56# Given a propget function's arg desc, return the default parameters for all57# params bar the first.  Eg, then Python does a:58# object.Property = "foo"59# Python can only pass the "foo" value.  If the property has60# multiple args, and the rest have default values, this allows61# Python to correctly pass those defaults.62def MakeDefaultArgsForPropertyPut(argsDesc):63    ret = []64    for desc in argsDesc[1:]:65        default = build.MakeDefaultArgRepr(desc)66        if default is None:67            break68        ret.append(default)69    return tuple(ret)70 71 72def MakeMapLineEntry(dispid, wFlags, retType, argTypes, user, resultCLSID):73    # Strip the default value74    argTypes = tuple([what[:2] for what in argTypes])75    return '(%s, %d, %s, %s, "%s", %s)' % (76        dispid,77        wFlags,78        retType[:2],79        argTypes,80        user,81        resultCLSID,82    )83 84 85def MakeEventMethodName(eventName):86    if eventName[:2] == "On":87        return eventName88    else:89        return "On" + eventName90 91 92def WriteSinkEventMap(obj, stream):93    print("\t_dispid_to_func_ = {", file=stream)94    for name, entry in (95        list(obj.propMapGet.items())96        + list(obj.propMapPut.items())97        + list(obj.mapFuncs.items())98    ):99        fdesc = entry.desc100        print(101            '\t\t%9d : "%s",' % (fdesc.memid, MakeEventMethodName(entry.names[0])),102            file=stream,103        )104    print("\t\t}", file=stream)105 106 107# MI is used to join my writable helpers, and the OLE108# classes.109class WritableItem:110    # __cmp__ used for sorting in py2x...111    def __cmp__(self, other):112        "Compare for sorting"113        ret = cmp(self.order, other.order)114        if ret == 0 and self.doc:115            ret = cmp(self.doc[0], other.doc[0])116        return ret117 118    # ... but not used in py3k - __lt__ minimum needed there119    def __lt__(self, other):  # py3k variant120        if self.order == other.order:121            return self.doc < other.doc122        return self.order < other.order123 124    def __repr__(self):125        return "OleItem: doc=%s, order=%d" % (repr(self.doc), self.order)126 127 128class RecordItem(build.OleItem, WritableItem):129    order = 9130    typename = "RECORD"131 132    def __init__(self, typeInfo, typeAttr, doc=None, bForUser=1):133        ##    sys.stderr.write("Record %s: size %s\n" % (doc,typeAttr.cbSizeInstance))134        ##    sys.stderr.write(" cVars = %s\n" % (typeAttr.cVars,))135        ##    for i in range(typeAttr.cVars):136        ##        vdesc = typeInfo.GetVarDesc(i)137        ##        sys.stderr.write(" Var %d has value %s, type %d, desc=%s\n" % (i, vdesc.value, vdesc.varkind, vdesc.elemdescVar))138        ##        sys.stderr.write(" Doc is %s\n" % (typeInfo.GetDocumentation(vdesc.memid),))139 140        build.OleItem.__init__(self, doc)141        self.clsid = typeAttr[0]142 143    def WriteClass(self, generator):144        pass145 146 147# Given an enum, write all aliases for it.148# (no longer necessary for new style code, but still used for old code.149def WriteAliasesForItem(item, aliasItems, stream):150    for alias in aliasItems.values():151        if item.doc and alias.aliasDoc and (alias.aliasDoc[0] == item.doc[0]):152            alias.WriteAliasItem(aliasItems, stream)153 154 155class AliasItem(build.OleItem, WritableItem):156    order = 2157    typename = "ALIAS"158 159    def __init__(self, typeinfo, attr, doc=None, bForUser=1):160        build.OleItem.__init__(self, doc)161 162        ai = attr[14]163        self.attr = attr164        if type(ai) == type(()) and type(ai[1]) == type(165            0166        ):  # XXX - This is a hack - why tuples?  Need to resolve?167            href = ai[1]168            alinfo = typeinfo.GetRefTypeInfo(href)169            self.aliasDoc = alinfo.GetDocumentation(-1)170            self.aliasAttr = alinfo.GetTypeAttr()171        else:172            self.aliasDoc = None173            self.aliasAttr = None174 175    def WriteAliasItem(self, aliasDict, stream):176        # we could have been written as part of an alias dependency177        if self.bWritten:178            return179 180        if self.aliasDoc:181            depName = self.aliasDoc[0]182            if depName in aliasDict:183                aliasDict[depName].WriteAliasItem(aliasDict, stream)184            print(self.doc[0] + " = " + depName, file=stream)185        else:186            ai = self.attr[14]187            if type(ai) == type(0):188                try:189                    typeStr = mapVTToTypeString[ai]190                    print("# %s=%s" % (self.doc[0], typeStr), file=stream)191                except KeyError:192                    print(193                        self.doc[0] + " = None # Can't convert alias info " + str(ai),194                        file=stream,195                    )196        print(file=stream)197        self.bWritten = 1198 199 200class EnumerationItem(build.OleItem, WritableItem):201    order = 1202    typename = "ENUMERATION"203 204    def __init__(self, typeinfo, attr, doc=None, bForUser=1):205        build.OleItem.__init__(self, doc)206 207        self.clsid = attr[0]208        self.mapVars = {}209        typeFlags = attr[11]210        self.hidden = (211            typeFlags & pythoncom.TYPEFLAG_FHIDDEN212            or typeFlags & pythoncom.TYPEFLAG_FRESTRICTED213        )214 215        for j in range(attr[7]):216            vdesc = typeinfo.GetVarDesc(j)217            name = typeinfo.GetNames(vdesc[0])[0]218            self.mapVars[name] = build.MapEntry(vdesc)219 220    ##  def WriteEnumerationHeaders(self, aliasItems, stream):221    ##    enumName = self.doc[0]222    ##    print >> stream "%s=constants # Compatibility with previous versions." % (enumName)223    ##    WriteAliasesForItem(self, aliasItems)224 225    def WriteEnumerationItems(self, stream):226        num = 0227        enumName = self.doc[0]228        # Write in name alpha order229        names = list(self.mapVars.keys())230        names.sort()231        for name in names:232            entry = self.mapVars[name]233            vdesc = entry.desc234            if vdesc[4] == pythoncom.VAR_CONST:235                val = vdesc[1]236 237                use = repr(val)238                # Make sure the repr of the value is valid python syntax239                # still could cause an error on import if it contains a module or type name240                # not available in the global namespace241                try:242                    compile(use, "<makepy>", "eval")243                except SyntaxError:244                    # At least add the repr as a string, so it can be investigated further245                    # Sanitize it, in case the repr contains its own quotes.  (??? line breaks too ???)246                    use = use.replace('"', "'")247                    use = (248                        '"'249                        + use250                        + '"'251                        + " # This VARIANT type cannot be converted automatically"252                    )253                print(254                    "\t%-30s=%-10s # from enum %s"255                    % (build.MakePublicAttributeName(name, True), use, enumName),256                    file=stream,257                )258                num += 1259        return num260 261 262class VTableItem(build.VTableItem, WritableItem):263    order = 4264 265    def WriteClass(self, generator):266        self.WriteVTableMap(generator)267        self.bWritten = 1268 269    def WriteVTableMap(self, generator):270        stream = generator.file271        print(272            "%s_vtables_dispatch_ = %d" % (self.python_name, self.bIsDispatch),273            file=stream,274        )275        print("%s_vtables_ = [" % (self.python_name,), file=stream)276        for v in self.vtableFuncs:277            names, dispid, desc = v278            assert desc.desckind == pythoncom.DESCKIND_FUNCDESC279            arg_reprs = []280            # more hoops so we don't generate huge lines.281            item_num = 0282            print("\t((", end=" ", file=stream)283            for name in names:284                print(repr(name), ",", end=" ", file=stream)285                item_num = item_num + 1286                if item_num % 5 == 0:287                    print("\n\t\t\t", end=" ", file=stream)288            print(289                "), %d, (%r, %r, [" % (dispid, desc.memid, desc.scodeArray),290                end=" ",291                file=stream,292            )293            for arg in desc.args:294                item_num = item_num + 1295                if item_num % 5 == 0:296                    print("\n\t\t\t", end=" ", file=stream)297                defval = build.MakeDefaultArgRepr(arg)298                if arg[3] is None:299                    arg3_repr = None300                else:301                    arg3_repr = repr(arg[3])302                print(303                    repr((arg[0], arg[1], defval, arg3_repr)), ",", end=" ", file=stream304                )305            print("],", end=" ", file=stream)306            print(repr(desc.funckind), ",", end=" ", file=stream)307            print(repr(desc.invkind), ",", end=" ", file=stream)308            print(repr(desc.callconv), ",", end=" ", file=stream)309            print(repr(desc.cParamsOpt), ",", end=" ", file=stream)310            print(repr(desc.oVft), ",", end=" ", file=stream)311            print(repr(desc.rettype), ",", end=" ", file=stream)312            print(repr(desc.wFuncFlags), ",", end=" ", file=stream)313            print(")),", file=stream)314        print("]", file=stream)315        print(file=stream)316 317 318class DispatchItem(build.DispatchItem, WritableItem):319    order = 3320 321    def __init__(self, typeinfo, attr, doc=None):322        build.DispatchItem.__init__(self, typeinfo, attr, doc)323        self.type_attr = attr324        self.coclass_clsid = None325 326    def WriteClass(self, generator):327        if (328            not self.bIsDispatch329            and not self.type_attr.typekind == pythoncom.TKIND_DISPATCH330        ):331            return332        # This is pretty screwey - now we have vtable support we333        # should probably rethink this (ie, maybe write both sides for sinks, etc)334        if self.bIsSink:335            self.WriteEventSinkClassHeader(generator)336            self.WriteCallbackClassBody(generator)337        else:338            self.WriteClassHeader(generator)339            self.WriteClassBody(generator)340        print(file=generator.file)341        self.bWritten = 1342 343    def WriteClassHeader(self, generator):344        generator.checkWriteDispatchBaseClass()345        doc = self.doc346        stream = generator.file347        print("class " + self.python_name + "(DispatchBaseClass):", file=stream)348        if doc[1]:349            print("\t" + build._makeDocString(doc[1]), file=stream)350        try:351            progId = pythoncom.ProgIDFromCLSID(self.clsid)352            print(353                "\t# This class is creatable by the name '%s'" % (progId), file=stream354            )355        except pythoncom.com_error:356            pass357        print("\tCLSID = " + repr(self.clsid), file=stream)358        if self.coclass_clsid is None:359            print("\tcoclass_clsid = None", file=stream)360        else:361            print("\tcoclass_clsid = " + repr(self.coclass_clsid), file=stream)362        print(file=stream)363        self.bWritten = 1364 365    def WriteEventSinkClassHeader(self, generator):366        generator.checkWriteEventBaseClass()367        doc = self.doc368        stream = generator.file369        print("class " + self.python_name + ":", file=stream)370        if doc[1]:371            print("\t" + build._makeDocString(doc[1]), file=stream)372        try:373            progId = pythoncom.ProgIDFromCLSID(self.clsid)374            print(375                "\t# This class is creatable by the name '%s'" % (progId), file=stream376            )377        except pythoncom.com_error:378            pass379        print("\tCLSID = CLSID_Sink = " + repr(self.clsid), file=stream)380        if self.coclass_clsid is None:381            print("\tcoclass_clsid = None", file=stream)382        else:383            print("\tcoclass_clsid = " + repr(self.coclass_clsid), file=stream)384        print("\t_public_methods_ = [] # For COM Server support", file=stream)385        WriteSinkEventMap(self, stream)386        print(file=stream)387        print("\tdef __init__(self, oobj = None):", file=stream)388        print("\t\tif oobj is None:", file=stream)389        print("\t\t\tself._olecp = None", file=stream)390        print("\t\telse:", file=stream)391        print("\t\t\timport win32com.server.util", file=stream)392        print(393            "\t\t\tfrom win32com.server.policy import EventHandlerPolicy", file=stream394        )395        print(396            "\t\t\tcpc=oobj._oleobj_.QueryInterface(pythoncom.IID_IConnectionPointContainer)",397            file=stream,398        )399        print("\t\t\tcp=cpc.FindConnectionPoint(self.CLSID_Sink)", file=stream)400        print(401            "\t\t\tcookie=cp.Advise(win32com.server.util.wrap(self, usePolicy=EventHandlerPolicy))",402            file=stream,403        )404        print("\t\t\tself._olecp,self._olecp_cookie = cp,cookie", file=stream)405        print("\tdef __del__(self):", file=stream)406        print("\t\ttry:", file=stream)407        print("\t\t\tself.close()", file=stream)408        print("\t\texcept pythoncom.com_error:", file=stream)409        print("\t\t\tpass", file=stream)410        print("\tdef close(self):", file=stream)411        print("\t\tif self._olecp is not None:", file=stream)412        print(413            "\t\t\tcp,cookie,self._olecp,self._olecp_cookie = self._olecp,self._olecp_cookie,None,None",414            file=stream,415        )416        print("\t\t\tcp.Unadvise(cookie)", file=stream)417        print("\tdef _query_interface_(self, iid):", file=stream)418        print("\t\timport win32com.server.util", file=stream)419        print(420            "\t\tif iid==self.CLSID_Sink: return win32com.server.util.wrap(self)",421            file=stream,422        )423        print(file=stream)424        self.bWritten = 1425 426    def WriteCallbackClassBody(self, generator):427        stream = generator.file428        print("\t# Event Handlers", file=stream)429        print(430            "\t# If you create handlers, they should have the following prototypes:",431            file=stream,432        )433        for name, entry in (434            list(self.propMapGet.items())435            + list(self.propMapPut.items())436            + list(self.mapFuncs.items())437        ):438            fdesc = entry.desc439            methName = MakeEventMethodName(entry.names[0])440            print(441                "#\tdef "442                + methName443                + "(self"444                + build.BuildCallList(445                    fdesc,446                    entry.names,447                    "defaultNamedOptArg",448                    "defaultNamedNotOptArg",449                    "defaultUnnamedArg",450                    "pythoncom.Missing",451                    is_comment=True,452                )453                + "):",454                file=stream,455            )456            if entry.doc and entry.doc[1]:457                print("#\t\t" + build._makeDocString(entry.doc[1]), file=stream)458        print(file=stream)459        self.bWritten = 1460 461    def WriteClassBody(self, generator):462        stream = generator.file463        # Write in alpha order.464        names = list(self.mapFuncs.keys())465        names.sort()466        specialItems = {467            "count": None,468            "item": None,469            "value": None,470            "_newenum": None,471        }  # If found, will end up with (entry, invoke_tupe)472        itemCount = None473        for name in names:474            entry = self.mapFuncs[name]475            assert entry.desc.desckind == pythoncom.DESCKIND_FUNCDESC476            # skip [restricted] methods, unless it is the477            # enumerator (which, being part of the "system",478            # we know about and can use)479            dispid = entry.desc.memid480            if (481                entry.desc.wFuncFlags & pythoncom.FUNCFLAG_FRESTRICTED482                and dispid != pythoncom.DISPID_NEWENUM483            ):484                continue485            # If not accessible via IDispatch, then we can't use it here.486            if entry.desc.funckind != pythoncom.FUNC_DISPATCH:487                continue488            if dispid == pythoncom.DISPID_VALUE:489                lkey = "value"490            elif dispid == pythoncom.DISPID_NEWENUM:491                specialItems["_newenum"] = (entry, entry.desc.invkind, None)492                continue  # Dont build this one now!493            else:494                lkey = name.lower()495            if (496                lkey in specialItems and specialItems[lkey] is None497            ):  # remember if a special one.498                specialItems[lkey] = (entry, entry.desc.invkind, None)499            if generator.bBuildHidden or not entry.hidden:500                if entry.GetResultName():501                    print("\t# Result is of type " + entry.GetResultName(), file=stream)502                if entry.wasProperty:503                    print(504                        "\t# The method %s is actually a property, but must be used as a method to correctly pass the arguments"505                        % name,506                        file=stream,507                    )508                ret = self.MakeFuncMethod(entry, build.MakePublicAttributeName(name))509                for line in ret:510                    print(line, file=stream)511        print("\t_prop_map_get_ = {", file=stream)512        names = list(self.propMap.keys())513        names.sort()514        for key in names:515            entry = self.propMap[key]516            if generator.bBuildHidden or not entry.hidden:517                resultName = entry.GetResultName()518                if resultName:519                    print(520                        "\t\t# Property '%s' is an object of type '%s'"521                        % (key, resultName),522                        file=stream,523                    )524                lkey = key.lower()525                details = entry.desc526                resultDesc = details[2]527                argDesc = ()528                mapEntry = MakeMapLineEntry(529                    details.memid,530                    pythoncom.DISPATCH_PROPERTYGET,531                    resultDesc,532                    argDesc,533                    key,534                    entry.GetResultCLSIDStr(),535                )536 537                if details.memid == pythoncom.DISPID_VALUE:538                    lkey = "value"539                elif details.memid == pythoncom.DISPID_NEWENUM:540                    lkey = "_newenum"541                else:542                    lkey = key.lower()543                if (544                    lkey in specialItems and specialItems[lkey] is None545                ):  # remember if a special one.546                    specialItems[lkey] = (547                        entry,548                        pythoncom.DISPATCH_PROPERTYGET,549                        mapEntry,550                    )551                    # All special methods, except _newenum, are written552                    # "normally".  This is a mess!553                    if details.memid == pythoncom.DISPID_NEWENUM:554                        continue555 556                print(557                    '\t\t"%s": %s,' % (build.MakePublicAttributeName(key), mapEntry),558                    file=stream,559                )560        names = list(self.propMapGet.keys())561        names.sort()562        for key in names:563            entry = self.propMapGet[key]564            if generator.bBuildHidden or not entry.hidden:565                if entry.GetResultName():566                    print(567                        "\t\t# Method '%s' returns object of type '%s'"568                        % (key, entry.GetResultName()),569                        file=stream,570                    )571                details = entry.desc572                assert details.desckind == pythoncom.DESCKIND_FUNCDESC573                lkey = key.lower()574                argDesc = details[2]575                resultDesc = details[8]576                mapEntry = MakeMapLineEntry(577                    details[0],578                    pythoncom.DISPATCH_PROPERTYGET,579                    resultDesc,580                    argDesc,581                    key,582                    entry.GetResultCLSIDStr(),583                )584                if details.memid == pythoncom.DISPID_VALUE:585                    lkey = "value"586                elif details.memid == pythoncom.DISPID_NEWENUM:587                    lkey = "_newenum"588                else:589                    lkey = key.lower()590                if (591                    lkey in specialItems and specialItems[lkey] is None592                ):  # remember if a special one.593                    specialItems[lkey] = (594                        entry,595                        pythoncom.DISPATCH_PROPERTYGET,596                        mapEntry,597                    )598                    # All special methods, except _newenum, are written599                    # "normally".  This is a mess!600                    if details.memid == pythoncom.DISPID_NEWENUM:601                        continue602                print(603                    '\t\t"%s": %s,' % (build.MakePublicAttributeName(key), mapEntry),604                    file=stream,605                )606 607        print("\t}", file=stream)608 609        print("\t_prop_map_put_ = {", file=stream)610        # These are "Invoke" args611        names = list(self.propMap.keys())612        names.sort()613        for key in names:614            entry = self.propMap[key]615            if generator.bBuildHidden or not entry.hidden:616                lkey = key.lower()617                details = entry.desc618                # If default arg is None, write an empty tuple619                defArgDesc = build.MakeDefaultArgRepr(details[2])620                if defArgDesc is None:621                    defArgDesc = ""622                else:623                    defArgDesc = defArgDesc + ","624                print(625                    '\t\t"%s" : ((%s, LCID, %d, 0),(%s)),'626                    % (627                        build.MakePublicAttributeName(key),628                        details[0],629                        pythoncom.DISPATCH_PROPERTYPUT,630                        defArgDesc,631                    ),632                    file=stream,633                )634 635        names = list(self.propMapPut.keys())636        names.sort()637        for key in names:638            entry = self.propMapPut[key]639            if generator.bBuildHidden or not entry.hidden:640                details = entry.desc641                defArgDesc = MakeDefaultArgsForPropertyPut(details[2])642                print(643                    '\t\t"%s": ((%s, LCID, %d, 0),%s),'644                    % (645                        build.MakePublicAttributeName(key),646                        details[0],647                        details[4],648                        defArgDesc,649                    ),650                    file=stream,651                )652        print("\t}", file=stream)653 654        if specialItems["value"]:655            entry, invoketype, propArgs = specialItems["value"]656            if propArgs is None:657                typename = "method"658                ret = self.MakeFuncMethod(entry, "__call__")659            else:660                typename = "property"661                ret = [662                    "\tdef __call__(self):\n\t\treturn self._ApplyTypes_(*%s)"663                    % propArgs664                ]665            print(666                "\t# Default %s for this class is '%s'" % (typename, entry.names[0]),667                file=stream,668            )669            for line in ret:670                print(line, file=stream)671            print("\tdef __str__(self, *args):", file=stream)672            print("\t\treturn str(self.__call__(*args))", file=stream)673            print("\tdef __int__(self, *args):", file=stream)674            print("\t\treturn int(self.__call__(*args))", file=stream)675 676        # _NewEnum (DISPID_NEWENUM) does not appear in typelib for many office objects,677        # but it can still be retrieved at runtime, so  always create __iter__.678        # Also, some of those same objects use 1-based indexing, causing the old-style679        # __getitem__ iteration to fail for index 0 where the dynamic iteration succeeds.680        if specialItems["_newenum"]:681            enumEntry, invoketype, propArgs = specialItems["_newenum"]682            assert enumEntry.desc.desckind == pythoncom.DESCKIND_FUNCDESC683            invkind = enumEntry.desc.invkind684            # ??? Wouldn't this be the resultCLSID for the iterator itself, rather than the resultCLSID685            #  for the result of each Next() call, which is what it's used for ???686            resultCLSID = enumEntry.GetResultCLSIDStr()687        else:688            invkind = pythoncom.DISPATCH_METHOD | pythoncom.DISPATCH_PROPERTYGET689            resultCLSID = "None"690        # If we dont have a good CLSID for the enum result, assume it is the same as the Item() method.691        if resultCLSID == "None" and "Item" in self.mapFuncs:692            resultCLSID = self.mapFuncs["Item"].GetResultCLSIDStr()693        print("\tdef __iter__(self):", file=stream)694        print('\t\t"Return a Python iterator for this object"', file=stream)695        print("\t\ttry:", file=stream)696        print(697            "\t\t\tob = self._oleobj_.InvokeTypes(%d,LCID,%d,(13, 10),())"698            % (pythoncom.DISPID_NEWENUM, invkind),699            file=stream,700        )701        print("\t\texcept pythoncom.error:", file=stream)702        print(703            '\t\t\traise TypeError("This object does not support enumeration")',704            file=stream,705        )706        # Iterator is wrapped as PyIEnumVariant, and each result of __next__ is Dispatch'ed if necessary707        print(708            "\t\treturn win32com.client.util.Iterator(ob, %s)" % resultCLSID,709            file=stream,710        )711 712        if specialItems["item"]:713            entry, invoketype, propArgs = specialItems["item"]714            resultCLSID = entry.GetResultCLSIDStr()715            print(716                "\t#This class has Item property/method which allows indexed access with the object[key] syntax.",717                file=stream,718            )719            print(720                "\t#Some objects will accept a string or other type of key in addition to integers.",721                file=stream,722            )723            print(724                "\t#Note that many Office objects do not use zero-based indexing.",725                file=stream,726            )727            print("\tdef __getitem__(self, key):", file=stream)728            print(729                '\t\treturn self._get_good_object_(self._oleobj_.Invoke(*(%d, LCID, %d, 1, key)), "Item", %s)'730                % (entry.desc.memid, invoketype, resultCLSID),731                file=stream,732            )733 734        if specialItems["count"]:735            entry, invoketype, propArgs = specialItems["count"]736            if propArgs is None:737                typename = "method"738                ret = self.MakeFuncMethod(entry, "__len__")739            else:740                typename = "property"741                ret = [742                    "\tdef __len__(self):\n\t\treturn self._ApplyTypes_(*%s)" % propArgs743                ]744            print(745                "\t#This class has Count() %s - allow len(ob) to provide this"746                % (typename),747                file=stream,748            )749            for line in ret:750                print(line, file=stream)751            # Also include a __nonzero__752            print(753                "\t#This class has a __len__ - this is needed so 'if object:' always returns TRUE.",754                file=stream,755            )756            print("\tdef __nonzero__(self):", file=stream)757            print("\t\treturn True", file=stream)758 759 760class CoClassItem(build.OleItem, WritableItem):761    order = 5762    typename = "COCLASS"763 764    def __init__(self, typeinfo, attr, doc=None, sources=[], interfaces=[], bForUser=1):765        build.OleItem.__init__(self, doc)766        self.clsid = attr[0]767        self.sources = sources768        self.interfaces = interfaces769        self.bIsDispatch = 1  # Pretend it is so it is written to the class map.770 771    def WriteClass(self, generator):772        generator.checkWriteCoClassBaseClass()773        doc = self.doc774        stream = generator.file775        if generator.generate_type == GEN_DEMAND_CHILD:776            # Some special imports we must setup.777            referenced_items = []778            for ref, flag in self.sources:779                referenced_items.append(ref)780            for ref, flag in self.interfaces:781                referenced_items.append(ref)782            print("import sys", file=stream)783            for ref in referenced_items:784                print(785                    "__import__('%s.%s')" % (generator.base_mod_name, ref.python_name),786                    file=stream,787                )788                print(789                    "%s = sys.modules['%s.%s'].%s"790                    % (791                        ref.python_name,792                        generator.base_mod_name,793                        ref.python_name,794                        ref.python_name,795                    ),796                    file=stream,797                )798                # And pretend we have written it - the name is now available as if we had!799                ref.bWritten = 1800        try:801            progId = pythoncom.ProgIDFromCLSID(self.clsid)802            print("# This CoClass is known by the name '%s'" % (progId), file=stream)803        except pythoncom.com_error:804            pass805        print(806            "class %s(CoClassBaseClass): # A CoClass" % (self.python_name), file=stream807        )808        if doc and doc[1]:809            print("\t# " + doc[1], file=stream)810        print("\tCLSID = %r" % (self.clsid,), file=stream)811        print("\tcoclass_sources = [", file=stream)812        defItem = None813        for item, flag in self.sources:814            if flag & pythoncom.IMPLTYPEFLAG_FDEFAULT:815                defItem = item816            # If we have written a Python class, reference the name -817            # otherwise just the IID.818            if item.bWritten:819                key = item.python_name820            else:821                key = repr(str(item.clsid))  # really the iid.822            print("\t\t%s," % (key), file=stream)823        print("\t]", file=stream)824        if defItem:825            if defItem.bWritten:826                defName = defItem.python_name827            else:828                defName = repr(str(defItem.clsid))  # really the iid.829            print("\tdefault_source = %s" % (defName,), file=stream)830        print("\tcoclass_interfaces = [", file=stream)831        defItem = None832        for item, flag in self.interfaces:833            if flag & pythoncom.IMPLTYPEFLAG_FDEFAULT:  # and dual:834                defItem = item835            # If we have written a class, reference its name, otherwise the IID836            if item.bWritten:837                key = item.python_name838            else:839                key = repr(str(item.clsid))  # really the iid.840            print("\t\t%s," % (key,), file=stream)841        print("\t]", file=stream)842        if defItem:843            if defItem.bWritten:844                defName = defItem.python_name845            else:846                defName = repr(str(defItem.clsid))  # really the iid.847            print("\tdefault_interface = %s" % (defName,), file=stream)848        self.bWritten = 1849        print(file=stream)850 851 852class GeneratorProgress:853    def __init__(self):854        pass855 856    def Starting(self, tlb_desc):857        """Called when the process starts."""858        self.tlb_desc = tlb_desc859 860    def Finished(self):861        """Called when the process is complete."""862 863    def SetDescription(self, desc, maxticks=None):864        """We are entering a major step.  If maxticks, then this865        is how many ticks we expect to make until finished866        """867 868    def Tick(self, desc=None):869        """Minor progress step.  Can provide new description if necessary"""870 871    def VerboseProgress(self, desc):872        """Verbose/Debugging output."""873 874    def LogWarning(self, desc):875        """If a warning is generated"""876 877    def LogBeginGenerate(self, filename):878        pass879 880    def Close(self):881        pass882 883 884class Generator:885    def __init__(886        self,887        typelib,888        sourceFilename,889        progressObject,890        bBuildHidden=1,891        bUnicodeToString=None,892    ):893        assert bUnicodeToString is None, "this is deprecated and will go away"894        self.bHaveWrittenDispatchBaseClass = 0895        self.bHaveWrittenCoClassBaseClass = 0896        self.bHaveWrittenEventBaseClass = 0897        self.typelib = typelib898        self.sourceFilename = sourceFilename899        self.bBuildHidden = bBuildHidden900        self.progress = progressObject901        # These 2 are later additions and most of the code still 'print's...902        self.file = None903 904    def CollectOleItemInfosFromType(self):905        ret = []906        for i in range(self.typelib.GetTypeInfoCount()):907            info = self.typelib.GetTypeInfo(i)908            infotype = self.typelib.GetTypeInfoType(i)909            doc = self.typelib.GetDocumentation(i)910            attr = info.GetTypeAttr()911            ret.append((info, infotype, doc, attr))912        return ret913 914    def _Build_CoClass(self, type_info_tuple):915        info, infotype, doc, attr = type_info_tuple916        # find the source and dispinterfaces for the coclass917        child_infos = []918        for j in range(attr[8]):919            flags = info.GetImplTypeFlags(j)920            try:921                refType = info.GetRefTypeInfo(info.GetRefTypeOfImplType(j))922            except pythoncom.com_error:923                # Can't load a dependent typelib?924                continue925            refAttr = refType.GetTypeAttr()926            child_infos.append(927                (928                    info,929                    refAttr.typekind,930                    refType,931                    refType.GetDocumentation(-1),932                    refAttr,933                    flags,934                )935            )936 937        # Done generating children - now the CoClass itself.938        newItem = CoClassItem(info, attr, doc)939        return newItem, child_infos940 941    def _Build_CoClassChildren(self, coclass, coclass_info, oleItems, vtableItems):942        sources = {}943        interfaces = {}944        for info, info_type, refType, doc, refAttr, flags in coclass_info:945            #          sys.stderr.write("Attr typeflags for coclass referenced object %s=%d (%d), typekind=%d\n" % (name, refAttr.wTypeFlags, refAttr.wTypeFlags & pythoncom.TYPEFLAG_FDUAL,refAttr.typekind))946            if refAttr.typekind == pythoncom.TKIND_DISPATCH or (947                refAttr.typekind == pythoncom.TKIND_INTERFACE948                and refAttr[11] & pythoncom.TYPEFLAG_FDISPATCHABLE949            ):950                clsid = refAttr[0]951                if clsid in oleItems:952                    dispItem = oleItems[clsid]953                else:954                    dispItem = DispatchItem(refType, refAttr, doc)955                    oleItems[dispItem.clsid] = dispItem956                dispItem.coclass_clsid = coclass.clsid957                if flags & pythoncom.IMPLTYPEFLAG_FSOURCE:958                    dispItem.bIsSink = 1959                    sources[dispItem.clsid] = (dispItem, flags)960                else:961                    interfaces[dispItem.clsid] = (dispItem, flags)962                # If dual interface, make do that too.963                if clsid not in vtableItems and refAttr[11] & pythoncom.TYPEFLAG_FDUAL:964                    refType = refType.GetRefTypeInfo(refType.GetRefTypeOfImplType(-1))965                    refAttr = refType.GetTypeAttr()966                    assert (967                        refAttr.typekind == pythoncom.TKIND_INTERFACE968                    ), "must be interface bynow!"969                    vtableItem = VTableItem(refType, refAttr, doc)970                    vtableItems[clsid] = vtableItem971        coclass.sources = list(sources.values())972        coclass.interfaces = list(interfaces.values())973 974    def _Build_Interface(self, type_info_tuple):975        info, infotype, doc, attr = type_info_tuple976        oleItem = vtableItem = None977        if infotype == pythoncom.TKIND_DISPATCH or (978            infotype == pythoncom.TKIND_INTERFACE979            and attr[11] & pythoncom.TYPEFLAG_FDISPATCHABLE980        ):981            oleItem = DispatchItem(info, attr, doc)982            # If this DISPATCH interface dual, then build that too.983            if attr.wTypeFlags & pythoncom.TYPEFLAG_FDUAL:984                # Get the vtable interface985                refhtype = info.GetRefTypeOfImplType(-1)986                info = info.GetRefTypeInfo(refhtype)987                attr = info.GetTypeAttr()988                infotype = pythoncom.TKIND_INTERFACE989            else:990                infotype = None991        assert infotype in [992            None,993            pythoncom.TKIND_INTERFACE,994        ], "Must be a real interface at this point"995        if infotype == pythoncom.TKIND_INTERFACE:996            vtableItem = VTableItem(info, attr, doc)997        return oleItem, vtableItem998 999    def BuildOleItemsFromType(self):1000        assert (1001            self.bBuildHidden1002        ), "This code doesnt look at the hidden flag - I thought everyone set it true!?!?!"1003        oleItems = {}1004        enumItems = {}1005        recordItems = {}1006        vtableItems = {}1007 1008        for type_info_tuple in self.CollectOleItemInfosFromType():1009            info, infotype, doc, attr = type_info_tuple1010            clsid = attr[0]1011            if infotype == pythoncom.TKIND_ENUM or infotype == pythoncom.TKIND_MODULE:1012                newItem = EnumerationItem(info, attr, doc)1013                enumItems[newItem.doc[0]] = newItem1014            # We never hide interfaces (MSAccess, for example, nominates interfaces as1015            # hidden, assuming that you only ever use them via the CoClass)1016            elif infotype in [pythoncom.TKIND_DISPATCH, pythoncom.TKIND_INTERFACE]:1017                if clsid not in oleItems:1018                    oleItem, vtableItem = self._Build_Interface(type_info_tuple)1019                    oleItems[clsid] = oleItem  # Even "None" goes in here.1020                    if vtableItem is not None:1021                        vtableItems[clsid] = vtableItem1022            elif (1023                infotype == pythoncom.TKIND_RECORD or infotype == pythoncom.TKIND_UNION1024            ):1025                newItem = RecordItem(info, attr, doc)1026                recordItems[newItem.clsid] = newItem1027            elif infotype == pythoncom.TKIND_ALIAS:1028                # We dont care about alias' - handled intrinsicly.1029                continue1030            elif infotype == pythoncom.TKIND_COCLASS:1031                newItem, child_infos = self._Build_CoClass(type_info_tuple)1032                self._Build_CoClassChildren(newItem, child_infos, oleItems, vtableItems)1033                oleItems[newItem.clsid] = newItem1034            else:1035                self.progress.LogWarning("Unknown TKIND found: %d" % infotype)1036 1037        return oleItems, enumItems, recordItems, vtableItems1038 1039    def open_writer(self, filename, encoding="mbcs"):1040        # A place to put code to open a file with the appropriate encoding.1041        # Does *not* set self.file - just opens and returns a file.1042        # Actually returns a handle to a temp file - finish_writer then deletes1043        # the filename asked for and puts everything back in place.  This1044        # is so errors don't leave a 1/2 generated file around causing bizarre1045        # errors later, and so that multiple processes writing the same file1046        # don't step on each others' toes.1047        # Could be a classmethod one day...1048        temp_filename = self.get_temp_filename(filename)1049        return open(temp_filename, "wt", encoding=encoding)1050 1051    def finish_writer(self, filename, f, worked):1052        f.close()1053        try:1054            os.unlink(filename)1055        except os.error:1056            pass1057        temp_filename = self.get_temp_filename(filename)1058        if worked:1059            try:1060                os.rename(temp_filename, filename)1061            except os.error:1062                # If we are really unlucky, another process may have written the1063                # file in between our calls to os.unlink and os.rename. So try1064                # again, but only once.1065                # There are still some race conditions, but they seem difficult to1066                # fix, and they probably occur much less frequently:1067                # * The os.rename failure could occur more than once if more than1068                #   two processes are involved.1069                # * In between os.unlink and os.rename, another process could try1070                #   to import the module, having seen that it already exists.1071                # * If another process starts a COM server while we are still1072                #   generating __init__.py, that process sees that the folder1073                #   already exists and assumes that __init__.py is already there1074                #   as well.1075                try:1076                    os.unlink(filename)1077                except os.error:1078                    pass1079                os.rename(temp_filename, filename)1080        else:1081            os.unlink(temp_filename)1082 1083    def get_temp_filename(self, filename):1084        return "%s.%d.temp" % (filename, os.getpid())1085 1086    def generate(self, file, is_for_demand=0):1087        if is_for_demand:1088            self.generate_type = GEN_DEMAND_BASE1089        else:1090            self.generate_type = GEN_FULL1091        self.file = file1092        self.do_generate()1093        self.file = None1094        self.progress.Finished()1095 1096    def do_gen_file_header(self):1097        la = self.typelib.GetLibAttr()1098        moduleDoc = self.typelib.GetDocumentation(-1)1099        docDesc = ""1100        if moduleDoc[1]:1101            docDesc = moduleDoc[1]1102 1103        # Reset all the 'per file' state1104        self.bHaveWrittenDispatchBaseClass = 01105        self.bHaveWrittenCoClassBaseClass = 01106        self.bHaveWrittenEventBaseClass = 01107        # You must provide a file correctly configured for writing unicode.1108        # We assert this is it may indicate somewhere in pywin32 that needs1109        # upgrading.1110        assert self.file.encoding, self.file1111        encoding = self.file.encoding  # or "mbcs"1112 1113        print("# -*- coding: %s -*-" % (encoding,), file=self.file)1114        print("# Created by makepy.py version %s" % (makepy_version,), file=self.file)1115        print(1116            "# By python version %s" % (sys.version.replace("\n", "-"),), file=self.file1117        )1118        if self.sourceFilename:1119            print(1120                "# From type library '%s'" % (os.path.split(self.sourceFilename)[1],),1121                file=self.file,1122            )1123        print("# On %s" % time.ctime(time.time()), file=self.file)1124 1125        print(build._makeDocString(docDesc), file=self.file)1126 1127        print("makepy_version =", repr(makepy_version), file=self.file)1128        print("python_version = 0x%x" % (sys.hexversion,), file=self.file)1129        print(file=self.file)1130        print(1131            "import win32com.client.CLSIDToClass, pythoncom, pywintypes", file=self.file1132        )1133        print("import win32com.client.util", file=self.file)1134        print("from pywintypes import IID", file=self.file)1135        print("from win32com.client import Dispatch", file=self.file)1136        print(file=self.file)1137        print(1138            "# The following 3 lines may need tweaking for the particular server",1139            file=self.file,1140        )1141        print(1142            "# Candidates are pythoncom.Missing, .Empty and .ArgNotFound",1143            file=self.file,1144        )1145        print("defaultNamedOptArg=pythoncom.Empty", file=self.file)1146        print("defaultNamedNotOptArg=pythoncom.Empty", file=self.file)1147        print("defaultUnnamedArg=pythoncom.Empty", file=self.file)1148        print(file=self.file)1149        print("CLSID = " + repr(la[0]), file=self.file)1150        print("MajorVersion = " + str(la[3]), file=self.file)1151        print("MinorVersion = " + str(la[4]), file=self.file)1152        print("LibraryFlags = " + str(la[5]), file=self.file)1153        print("LCID = " + hex(la[1]), file=self.file)1154        print(file=self.file)1155 1156    def do_generate(self):1157        moduleDoc = self.typelib.GetDocumentation(-1)1158        stream = self.file1159        docDesc = ""1160        if moduleDoc[1]:1161            docDesc = moduleDoc[1]1162        self.progress.Starting(docDesc)1163        self.progress.SetDescription("Building definitions from type library...")1164 1165        self.do_gen_file_header()1166 1167        oleItems, enumItems, recordItems, vtableItems = self.BuildOleItemsFromType()1168 1169        self.progress.SetDescription(1170            "Generating...", len(oleItems) + len(enumItems) + len(vtableItems)1171        )1172 1173        # Generate the constants and their support.1174        if enumItems:1175            print("class constants:", file=stream)1176            items = list(enumItems.values())1177            items.sort()1178            num_written = 01179            for oleitem in items:1180                num_written += oleitem.WriteEnumerationItems(stream)1181                self.progress.Tick()1182            if not num_written:1183                print("\tpass", file=stream)1184            print(file=stream)1185 1186        if self.generate_type == GEN_FULL:1187            items = [l for l in oleItems.values() if l is not None]1188            items.sort()1189            for oleitem in items:1190                self.progress.Tick()1191                oleitem.WriteClass(self)1192 1193            items = list(vtableItems.values())1194            items.sort()1195            for oleitem in items:1196                self.progress.Tick()1197                oleitem.WriteClass(self)1198        else:1199            self.progress.Tick(len(oleItems) + len(vtableItems))1200 

Showing the first 1,200 of 1412 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai