home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 July / CMCD0704.ISO / Software / Shareware / Comunicatii / jyte / jyte.exe / makepy.py < prev    next >
Text File  |  2002-10-16  |  12KB  |  373 lines

  1. # Originally written by Curt Hagenlocher, and various bits
  2. # and pieces by Mark Hammond (and now Greg Stein has had
  3. # a go too :-)
  4.  
  5. # Note that the main worker code has been moved to genpy.py
  6. # As this is normally run from the command line, it reparses the code each time.  
  7. # Now this is nothing more than the command line handler and public interface.
  8.  
  9. # XXX - TO DO
  10. # XXX - Greg and Mark have some ideas for a revamp - just no
  11. #       time - if you want to help, contact us for details.
  12. #       Main idea is to drop the classes exported and move to a more
  13. #       traditional data driven model.
  14.  
  15. """Generate a .py file from an OLE TypeLibrary file.
  16.  
  17.  
  18.  This module is concerned only with the actual writing of
  19.  a .py file.  It draws on the @build@ module, which builds 
  20.  the knowledge of a COM interface.
  21.  
  22. """
  23. usageHelp = """ \
  24. Usage:
  25.  
  26.   makepy.py [-h] [-x0|1] [-u] [-o filename] [-d] [typelib, ...]
  27.   
  28.   typelib -- A TLB, DLL, OCX, Description, or possibly something else.
  29.   -h    -- Do not generate hidden methods.
  30.   -u    -- Python 1.5 and earlier: Do not convert all Unicode objects to strings.
  31.            Python 1.6 and later: Do convert all Unicode objects to strings.
  32.   -o outputFile -- Generate to named file - dont generate to standard directory.
  33.   -i [typelib] -- Show info for specified typelib, or select the typelib if not specified.
  34.   -v    -- Verbose output
  35.   -q    -- Quiet output
  36.   -d    -- Generate the base code now and classes code on demand
  37.   
  38. Examples:
  39.   makepy.py
  40.     Present a list of type libraries.
  41.     
  42.   makepy.py "Microsoft Excel 8.0 Object Library"
  43.     Generate support for the typelibrary with the specified description
  44.     (in this case, MS Excel object model)
  45.  
  46. """
  47.  
  48. import genpy, string, sys, os, types, pythoncom
  49. import selecttlb
  50. import gencache
  51. from win32com.client import NeedUnicodeConversions
  52.  
  53. bForDemandDefault = 0 # Default value of bForDemand - toggle this to change the world - see also gencache.py
  54.  
  55. error = "makepy.error"
  56.  
  57. def usage():
  58.     sys.stderr.write (usageHelp)
  59.     sys.exit(2)
  60.  
  61. def ShowInfo(spec):
  62.     if not spec:
  63.         tlbSpec = selecttlb.SelectTlb(excludeFlags=selecttlb.FLAG_HIDDEN)
  64.         if tlbSpec is None:
  65.             return
  66.         try:
  67.             tlb = pythoncom.LoadRegTypeLib(tlbSpec.clsid, tlbSpec.major, tlbSpec.minor, tlbSpec.lcid)
  68.         except pythoncom.com_error: # May be badly registered.
  69.             sys.stderr.write("Warning - could not load registered typelib '%s'\n" % (tlbSpec.clsid))
  70.             tlb = None
  71.         
  72.         infos = [(tlb, tlbSpec)]
  73.     else:
  74.         infos = GetTypeLibsForSpec(spec)
  75.     for (tlb, tlbSpec) in infos:
  76.         desc = tlbSpec.desc
  77.         if desc is None:
  78.             if tlb is None:
  79.                 desc = "<Could not load typelib %s>" % (tlbSpec.dll)
  80.             else:
  81.                 desc = tlb.GetDocumentation(-1)[0]
  82.         print desc
  83.         print " %s, lcid=%s, major=%s, minor=%s" % (tlbSpec.clsid, tlbSpec.lcid, tlbSpec.major, tlbSpec.minor)
  84.         print " >>> # Use these commands in Python code to auto generate .py support"
  85.         print " >>> from win32com.client import gencache"
  86.         print " >>> gencache.EnsureModule('%s', %s, %s, %s)" % (tlbSpec.clsid, tlbSpec.lcid, tlbSpec.major, tlbSpec.minor)
  87.  
  88. class SimpleProgress(genpy.GeneratorProgress):
  89.     """A simple progress class prints its output to stderr
  90.     """
  91.     def __init__(self, verboseLevel):
  92.         self.verboseLevel = verboseLevel
  93.     def Close(self):
  94.         pass
  95.     def Finished(self):
  96.         if self.verboseLevel>1:
  97.             sys.stderr.write("Generation complete..\n")
  98.     def SetDescription(self, desc, maxticks = None):
  99.         if self.verboseLevel:
  100.             sys.stderr.write(desc + "\n")
  101.     def Tick(self, desc = None):
  102.         pass
  103.  
  104.     def VerboseProgress(self, desc, verboseLevel = 2):
  105.         if self.verboseLevel >= verboseLevel:
  106.             sys.stderr.write(desc + "\n")
  107.  
  108.     def LogBeginGenerate(self, filename):
  109.         self.VerboseProgress("Generating to %s" % filename, 1)
  110.     
  111.     def LogWarning(self, desc):
  112.         self.VerboseProgress("WARNING: " + desc, 1)
  113.  
  114. class GUIProgress(SimpleProgress):
  115.     def __init__(self, verboseLevel):
  116.         # Import some modules we need to we can trap failure now.
  117.         import win32ui, pywin
  118.         SimpleProgress.__init__(self, verboseLevel)
  119.         self.dialog = None
  120.         
  121.     def Close(self):
  122.         if self.dialog is not None:
  123.             self.dialog.Close()
  124.             self.dialog = None
  125.  
  126.     def Starting(self, tlb_desc):
  127.         SimpleProgress.Starting(self, tlb_desc)
  128.         if self.dialog is None:
  129.             from pywin.dialogs import status
  130.             self.dialog=status.ThreadedStatusProgressDialog(tlb_desc)
  131.         else:
  132.             self.dialog.SetTitle(tlb_desc)
  133.         
  134.     def SetDescription(self, desc, maxticks = None):
  135.         self.dialog.SetText(desc)
  136.         if maxticks:
  137.             self.dialog.SetMaxTicks(maxticks)
  138.  
  139.     def Tick(self, desc = None):
  140.         self.dialog.Tick()
  141.         if desc is not None:
  142.             self.dialog.SetText(desc)
  143.  
  144. def GetTypeLibsForSpec(arg):
  145.     """Given an argument on the command line (either a file name or a library description)
  146.     return a list of actual typelibs to use.
  147.     """
  148.     typelibs = []
  149.     try:
  150.         try:
  151.             tlb = pythoncom.LoadTypeLib(arg)
  152.             spec = selecttlb.TypelibSpec(None, 0,0,0)
  153.             spec.FromTypelib(tlb, arg)
  154.             typelibs.append((tlb, spec))
  155.         except pythoncom.com_error:
  156.             # See if it is a description
  157.             tlbs = selecttlb.FindTlbsWithDescription(arg)
  158.             if len(tlbs)==0:
  159.                 print "Could not locate a type library matching '%s'" % (arg)
  160.             for spec in tlbs:
  161.                 # Version numbers not always reliable if enumerated from registry.
  162.                 # (as some libs use hex, other's dont.  Both examples from MS, of course.)
  163.                 if spec.dll is None:
  164.                     tlb = pythoncom.LoadRegTypeLib(spec.clsid, spec.major, spec.minor, spec.lcid)
  165.                 else:
  166.                     tlb = pythoncom.LoadTypeLib(spec.dll)
  167.                 
  168.                 # We have a typelib, but it may not be exactly what we specified
  169.                 # (due to automatic version matching of COM).  So we query what we really have!
  170.                 attr = tlb.GetLibAttr()
  171.                 spec.major = attr[3]
  172.                 spec.minor = attr[4]
  173.                 spec.lcid = attr[1]
  174.                 typelibs.append((tlb, spec))
  175.         return typelibs
  176.     except pythoncom.com_error:
  177.         t,v,tb=sys.exc_info()
  178.         sys.stderr.write ("Unable to load type library from '%s' - %s\n" % (arg, v))
  179.         tb = None # Storing tb in a local is a cycle!
  180.         sys.exit(1)
  181.  
  182. def GenerateFromTypeLibSpec(typelibInfo, file = None, verboseLevel = None, progressInstance = None, bUnicodeToString=NeedUnicodeConversions, bQuiet = None, bGUIProgress = None, bForDemand = bForDemandDefault, bBuildHidden = 1):
  183.     if bQuiet is not None or bGUIProgress is not None:
  184.         print "Please dont use the bQuiet or bGUIProgress params"
  185.         print "use the 'verboseLevel', and 'progressClass' params"
  186.     if verboseLevel is None:
  187.         verboseLevel = 0 # By default, we use a gui, and no verbose level!
  188.  
  189.     if bForDemand and file is not None:
  190.         raise RuntimeError, "You can only perform a demand-build when the output goes to the gen_py directory"
  191.     if type(typelibInfo)==type(()):
  192.         # Tuple
  193.         typelibCLSID, lcid, major, minor  = typelibInfo
  194.         tlb = pythoncom.LoadRegTypeLib(typelibCLSID, major, minor, lcid)
  195.         spec = selecttlb.TypelibSpec(typelibCLSID, lcid, major, minor)
  196.         spec.FromTypelib(tlb, str(typelibCLSID))
  197.         typelibs = [(tlb, spec)]
  198.     elif type(typelibInfo)==types.InstanceType:
  199.         if typelibInfo.dll is None:
  200.             # Version numbers not always reliable if enumerated from registry.
  201.             tlb = pythoncom.LoadRegTypeLib(typelibInfo.clsid, typelibInfo.major, typelibInfo.minor, typelibInfo.lcid)
  202.         else:
  203.             tlb = pythoncom.LoadTypeLib(typelibInfo.dll)
  204.         typelibs = [(tlb, typelibInfo)]
  205.     elif hasattr(typelibInfo, "GetLibAttr"):
  206.         # A real typelib object!
  207.         tla = typelibInfo.GetLibAttr()
  208.         guid = tla[0]
  209.         lcid = tla[1]
  210.         major = tla[3]
  211.         minor = tla[4]
  212.         spec = selecttlb.TypelibSpec(guid, lcid, major, minor)
  213.         typelibs = [(typelibInfo, spec)]
  214.     else:
  215.         typelibs = GetTypeLibsForSpec(typelibInfo)
  216.  
  217.     if progressInstance is None:
  218.         try:
  219.             if not bForDemand: # Only go for GUI progress if not doing a demand-import
  220.                 # Win9x console programs don't seem to like our GUI!
  221.                 # (Actually, NT/2k wouldnt object to having them threaded - later!)
  222.                 import win32api, win32con
  223.                 if win32api.GetVersionEx()[3]==win32con.VER_PLATFORM_WIN32_NT:
  224.                     bMakeGuiProgress = 1
  225.                 else:
  226.                     try:
  227.                         win32api.GetConsoleTitle()
  228.                         # Have a console - can't handle GUI
  229.                         bMakeGuiProgress = 0
  230.                     except win32api.error:
  231.                         # no console - we can have a GUI
  232.                         bMakeGuiProgress = 1
  233.                 if bMakeGuiProgress:
  234.                     progressInstance = GUIProgress(verboseLevel)
  235.         except ImportError: # No Pythonwin GUI around.
  236.             pass
  237.     if progressInstance is None:
  238.         progressInstance = SimpleProgress(verboseLevel)
  239.     progress = progressInstance
  240.  
  241.     bToGenDir = (file is None)
  242.  
  243.     for typelib, info in typelibs:
  244.         if file is None:
  245.             this_name = gencache.GetGeneratedFileName(info.clsid, info.lcid, info.major, info.minor)
  246.             full_name = os.path.join(gencache.GetGeneratePath(), this_name)
  247.             if bForDemand:
  248.                 try: os.unlink(full_name + ".py")
  249.                 except os.error: pass
  250.                 try: os.unlink(full_name + ".pyc")
  251.                 except os.error: pass
  252.                 try: os.unlink(full_name + ".pyo")
  253.                 except os.error: pass
  254.                 if not os.path.isdir(full_name):
  255.                     os.mkdir(full_name)
  256.                 outputName = os.path.join(full_name, "__init__.py")
  257.             else:
  258.                 outputName = full_name + ".py"
  259.             fileUse = open(outputName, "wt")
  260.             progress.LogBeginGenerate(outputName)
  261.         else:
  262.             fileUse = file
  263.  
  264.         gen = genpy.Generator(typelib, info.dll, progress, bUnicodeToString=bUnicodeToString, bBuildHidden=bBuildHidden)
  265.  
  266.         gen.generate(fileUse, bForDemand)
  267.         
  268.         if file is None:
  269.             fileUse.close()
  270.         
  271.         if bToGenDir:
  272.             progress.SetDescription("Importing module")
  273.             gencache.AddModuleToCache(info.clsid, info.lcid, info.major, info.minor)
  274.  
  275.     progress.Close()
  276.  
  277. def GenerateChildFromTypeLibSpec(child, typelibInfo, verboseLevel = None, progressInstance = None, bUnicodeToString=NeedUnicodeConversions):
  278.     if verboseLevel is None:
  279.         verboseLevel = 0 # By default, we use no gui, and no verbose level for the children.
  280.     if type(typelibInfo)==type(()):
  281.         typelibCLSID, lcid, major, minor  = typelibInfo
  282.         tlb = pythoncom.LoadRegTypeLib(typelibCLSID, major, minor, lcid)
  283.     else:
  284.         tlb = typelibInfo
  285.         tla = typelibInfo.GetLibAttr()
  286.         typelibCLSID = tla[0]
  287.         lcid = tla[1]
  288.         major = tla[3]
  289.         minor = tla[4]
  290.     spec = selecttlb.TypelibSpec(typelibCLSID, lcid, major, minor)
  291.     spec.FromTypelib(tlb, str(typelibCLSID))
  292.     typelibs = [(tlb, spec)]
  293.  
  294.     if progressInstance is None:
  295.         progressInstance = SimpleProgress(verboseLevel)
  296.     progress = progressInstance
  297.  
  298.     for typelib, info in typelibs:
  299.         dir_name = gencache.GetGeneratedFileName(info.clsid, info.lcid, info.major, info.minor)
  300.         dir_path_name = os.path.join(gencache.GetGeneratePath(), dir_name)
  301.         progress.LogBeginGenerate(dir_path_name)
  302.  
  303.         gen = genpy.Generator(typelib, info.dll, progress, bUnicodeToString=bUnicodeToString)
  304.         gen.generate_child(child, dir_path_name)
  305.         progress.SetDescription("Importing module")
  306.         __import__("win32com.gen_py." + dir_name + "." + child)
  307.     progress.Close()
  308.  
  309. def main():
  310.     import getopt
  311.     hiddenSpec = 1
  312.     bUnicodeToString = NeedUnicodeConversions
  313.     outputName = None
  314.     verboseLevel = 1
  315.     doit = 1
  316.     bForDemand = bForDemandDefault
  317.     try:
  318.         opts, args = getopt.getopt(sys.argv[1:], 'vo:huiqd')
  319.         for o,v in opts:
  320.             if o=='-h':
  321.                 hiddenSpec = 0
  322.             elif o=='-u':
  323.                 bUnicodeToString = not NeedUnicodeConversions
  324.             elif o=='-o':
  325.                 outputName = v
  326.             elif o=='-v':
  327.                 verboseLevel = verboseLevel + 1
  328.             elif o=='-q':
  329.                 verboseLevel = verboseLevel - 1
  330.             elif o=='-i':
  331.                 if len(args)==0:
  332.                     ShowInfo(None)
  333.                 else:
  334.                     for arg in args:
  335.                         ShowInfo(arg)
  336.                 doit = 0
  337.             elif o=='-d':
  338.                 bForDemand = not bForDemand
  339.  
  340.     except (getopt.error, error), msg:
  341.         sys.stderr.write (str(msg) + "\n")
  342.         usage()
  343.  
  344.     if bForDemand and outputName is not None:
  345.         sys.stderr.write("Can not use -d and -o together\n")
  346.         usage()
  347.  
  348.     if not doit:
  349.         return 0        
  350.     if len(args)==0:
  351.         rc = selecttlb.SelectTlb()
  352.         if rc is None:
  353.             sys.exit(1)
  354.         args = [ rc ]
  355.  
  356.     if outputName is not None:
  357.         f = open(outputName, "w")
  358.     else:
  359.         f = None
  360.  
  361.     for arg in args:
  362.         GenerateFromTypeLibSpec(arg, f, verboseLevel = verboseLevel, bForDemand = bForDemand, bBuildHidden = hiddenSpec)
  363.  
  364.     if f:    
  365.         f.close()
  366.  
  367.  
  368. if __name__=='__main__':
  369.     rc = main()
  370.     if rc:
  371.         sys.exit(rc)
  372.     sys.exit(0)
  373.