5 Replies Latest reply on Dec 9, 2010 5:34 PM by mahunter243

    ArcMap 10, ArcObjects, and Python:  very cool, but help with a couple of problems?

    celticflute
      VITALS:  ArcGIS 10.0 - ArcView, Python 2.6.5, comtypes 0.6.2

      I am writing an external Python script that needs to access the running ArcMap 10 application; therefore, I am getting my app reference through the AppROT object, which is working fine, as far as that goes.  So, here are my problems/questions:

      1)  What object type is returned when I execute the line  pApp=pAppROT.Item(i)?  I definitely get an IApplication for ArcMap but on what object exactly?  I thought it was IApplication in the esriArcMapUI.olb, but that may not be the case ... esriFramework.olb maybe?  [BTW, pAppROT is the IAppROT interface on the AppROT object.]  It makes a difference, because I later QI to IMxDocument and get an error that the module (esriArcMapUI) has no attribute IMxDocument.  This may all relate to my 2nd question:

      2)  I am building Python wrappers for ESRI olb's on the fly using the GetModule function in comtypes.  The problem is that wrappers are not being built for all of the olb's I specify, or rather the wrapper .py modules (the ones with the long GUID names) are empty.  esriFramework, esriGeometry, esriSystem, and esriSystemUI build just fine.  esriArcMapUI, esriCarto, and esriGeoDatabase do not build.  Has anyone else had this problem?  If so, how did you fix it ... if you did , that is?

      Thank you all for the help.

      -- Ti
        • Re: ArcMap 10, ArcObjects, and Python:  very cool, but help with a couple of problems
          fperks
          1. Your first problem is related to you second:

          2. If you run the following (this will generate wrappers for every ESRI com lib):

          import os
          import comtypes.client
          # change com_dir to whatever it is for you
          com_dir = r'C:\Program Files (x86)\ArcGIS\Desktop10.0\com'
          coms = [os.path.join(com_dir, x) for x in os.listdir(com_dir) if os.path.splitext(x)[1].upper() == '.OLB']
          map(comtypes.client.GetModule, coms)
          
          # check add whatever you want here.
          import comtypes.gen.esriArcMapUI
          import comtypes.gen.esriGeodatabase
          
          print dir(comtypes.gen.esriArcMapUI)


          Do you get anything from the dir?

          If not then run this:

          import logging
          # grab rootlogger
          _loggy = logging.getLogger()
          _loggy.setLevel(logging.DEBUG)
          _loggy.addHandler(logging.FileHandler("derpdebug.log"))
          import os
          import comtypes.client
          # change com_dir to whatever it is for you
          com_dir = r'C:\Program Files (x86)\ArcGIS\Desktop10.0\com'
          coms = [os.path.join(com_dir, x) for x in os.listdir(com_dir) if os.path.splitext(x)[1].upper() == '.OLB']
          map(comtypes.client.GetModule, coms)
          
          # check add whatever you want here.
          import comtypes.gen.esriArcMapUI
          import comtypes.gen.esriGeodatabase
          
          print dir(comtypes.gen.esriArcMapUI)
          


          There should now be a derpdebug.log file now (where ever you ran it from), open it up and look for, anything that indicates an error, also make sure you see the GetModule call for esriArcMapUI.

          Worst case, delete everything in <PYTHON_DIR>\comtypes\gen directory (python_dir is your python installation path).

          If still this does not work, let me know.
          • Re: ArcMap 10, ArcObjects, and Python:  very cool, but help with a couple of problems
            celticflute
            Frank,

            Thank you so much for your help.  Your solutions worked like a charm.  When I ran your script, the dir listed everything in the __dict__ of esriArcMapUI, as it should.  esriArcMapUI.py was intact.  With help from the person who wrote the example code that I used as a base, I have discovered that the comtypes generation of wrappers for ArcObjects occasionally fails, creating blank wrapper files.  This seems to happen when a wrapper file already exists and GetModule() is called to build it again.  I tested the wrapping process many more times, with both existing wrappers and a cleared out gen cache directory.  I got a failure once, and that was for an existing wrapper.  No failures for an empty cache.  Also, the failures all produced readable but empty files.  I have not encountered any instances of missing wrappers (where there should be one) or of corrupted, unreadable wrappers.  I did also run your second, debug script quite a few times, and dir() reported as expected.  The debug logs also showed no errors.  So, I have modified my code to check for existing (the more secure open(filepath) way) wrappers and whether those existing modules are blank or not before I make any calls to GetModule().  Works great.  I'll just be sure to rerun the wrapping process after ArcObjects updates.  Thanks, again, Frank.  I only wish I could give you some MVP points.  Grrrr.

            Cheers,

            Ti
            GIS Specialist
            Durham, NH
            • Re: ArcMap 10, ArcObjects, and Python:  very cool, but help with a couple of problems
              fperks
              Frank,

              Thank you so much for your help.  Your solutions worked like a charm.  When I ran your script, the dir listed everything in the __dict__ of esriArcMapUI, as it should.  esriArcMapUI.py was intact.  With help from the person who wrote the example code that I used as a base, I have discovered that the comtypes generation of wrappers for ArcObjects occasionally fails, creating blank wrapper files.  This seems to happen when a wrapper file already exists and GetModule() is called to build it again.  I tested the wrapping process many more times, with both existing wrappers and a cleared out gen cache directory.  I got a failure once, and that was for an existing wrapper.  No failures for an empty cache.  Also, the failures all produced readable but empty files.  I have not encountered any instances of missing wrappers (where there should be one) or of corrupted, unreadable wrappers.  I did also run your second, debug script quite a few times, and dir() reported as expected.  The debug logs also showed no errors.  So, I have modified my code to check for existing (the more secure open(filepath) way) wrappers and whether those existing modules are blank or not before I make any calls to GetModule().  Works great.  I'll just be sure to rerun the wrapping process after ArcObjects updates.  Thanks, again, Frank.  I only wish I could give you some MVP points.  Grrrr.

              Cheers,

              Ti
              GIS Specialist
              Durham, NH


              The way comtypes generates modules is a goldmine of horrors. GetModule only checks if the module is importable (via importerror), and does not check if the module actually finished generation. Technically it should hold off of writing the modules until all other linked modules are finished processing, sadily it does not (this bug has been in their bug tracker for quite awhile last time i checked.)

              If you are deploying a script that uses comtypes, the safest way is to modify the distutils setup.py file(if your not using one then make a script that is run once, when the script is installed). So:

              1. Nuke the comtypes.gen folder
              2. call GetModule() on all of the comlibs in the ArcGIS/com folder.

              This prevents the need for GetModule() to be used within your actual program. Which hopefully makes things a little easier.
              • Re: ArcMap 10, ArcObjects, and Python:  very cool, but help with a couple of problems
                philmorefield
                Frank,

                I'm only just learning ArcObjects, and I'm hoping you can throw a little advice my way. Based on what I've read so far, I thought the following would work:

                import arcpy
                import comtypes
                import comtypes.client
                import comtypes.gen.esriDataSourcesNetCDF
                
                ws_factory = comtypes.client.CreateObject("esriDataSourcesNetCDF.NetCDFWorkspaceFactory", interface = esriDataSourcesNetCDF.INetCDFWorkspaceFactory)


                However, this throws an error since there is "no attribute 'INetCDFWorkspaceFactory'. As I understand it, Step 1 is to create a workspace factory. Step 2 is to create the workspace. And Step 3 is to instantiate the file of interest (in this case a NetCDF file) so I can play with the data.

                Can you steer me back on course?
                • Re: ArcMap 10, ArcObjects, and Python:  very cool, but help with a couple of problems
                  mahunter243
                  Try this.  It should work:


                  import comtypes.gen.esriDataSourcesNetCDF as esriDataSourcesNetCDF
                  import comtypes.gen.esriGeoDatabase as esriGeoDatabase

                  ws_factory = comtypes.client.CreateObject("esriDataSourcesNetCDF.NetCDFWorkspaceFactory", interface = esriGeoDatabase.IWorkspaceFactory)

                  In AO, a class may be in 1 library, and an interface to that class may be in another.  Also, do the imports like I did above--it will help your IDE to follow what's going on and help you with autocompletes.

                  good luck,
                  Mike