I would like to be able to script some things that are not exposed via
arcgisscripting or ArcPy.
How do I access ArcObjects from Python?
I'm working with ArcGIS Desktop 9.3.1 right now, but will be upgrading to version 10 in the next few months.
Download and install comtypes, put the
Note for 10.1 you need to make a small change to
Yes, Mark Cederholm's presentation that Matt Wilkie mentions above is a great place to start. The recipe/code that Matt presents is certainly a slick and probably the best way to go about things. I wanted to mention, though, the rather brute force method I am using in ArcGIS 10.0. I have several automation scripts (standalone, outside the application boundary) that I run this way, and they work just fine. If maximum speed is a concern, though, you might just go with Matt's solution and be done with it.
I use the comtypes package to force wrapping of all ArcObjects libraries (.olb). Then Python has access to all of ArcObjects. I got the wrapping code from Frank Perks through an ESRI forum posting. I had my own code that essentially did the same thing, but it was bloated and merely functional, while his is much prettier. So:
Then, pretty much straight out of Mark Cederholm's presentation:
That's it. You should have full access to ArcObjects starting with the pApp object that is IApplication on the AppRef object. In my experience, the wrapping of the ArcObjects libraries on the first run isn't objectionably slow, and for subsequent runs the wrapping doesn't happen. The libraries are already wrapped and compiled, so things are much speedier.
Added: There is a large caution that comes with this. The NewObj function given here assumes the Python script is being run in-process. If not, this function will create objects in the Python process (ie. out-of process), and object references will be wrong. To create in process objects from an external Python script you should use IObjectFactory. See Kirk Kuykendall's comments and tips in this stackexchange post for more info.
If what you are looking for is specific functionality that exists and is in the C++ Arcobjects code, then your best bet would be to create C++ methods to call them.... and then create a python wrapper to access those C++ methods.
There are quite a few ways to access C++ methods from python, and lots of people that do so use a tool like SWIG to auto-generate the python classes from the C++ method signatures. It's been my experience that these autogenerated APIs get pretty nasty when passing non-native C++ types (int, floats) and are never very 'pythonic'.
My recommended solution would be to use the ctypes API. A great tutorial is here: http://python.net/crew/theller/ctypes/tutorial.html
The basic steps are:
This is probably more general way to reference C/C++ code from within python, it is probably going to be much simpler in the long run if you don't have to deal with COM objects. It also will allow all of the system specific functionality reside in the compilation of the linked library object (so the python will not be system/python implementation specific).
Another option is to use Python for .NET - this is very easy to set up, and can work with any .NET DLLs including ArcObjects.
I've not experienced any issues with in-process obects, and opening up an instance of ArcMap and adding and manipulating layers worked fine for me.
The only requirements are a folder containing the Python for .NET library, and a standard Python install.
Unfortunately, whilst this works without problems on a local development machine, deploying it elsewhere requires the ArcObjects SDK, and Visual Studio (including the free Express edition) to be installed. See Deploying ArcObject .NET DLLs
One approach I don't see mentioned in the other answers is to use the same methods that the arcpy libraries themselves use. E.g. in C:\Program Files\ArcGIS\Desktop10.0\arcpy\arcpy\cartography.py, we see Python calling ArcObjects tools using some fixargs and object conversion functions.
I don't how much it's OK to post about it here, since the code says "TRADE SECRETS: ESRI PROPRIETARY AND CONFIDENTIAL"; but you'll find it elsewhere on the web too. Anyway, this looks like a relatively easy way to call functions like
See Jason's comments below. Sounds like doing the above won't buy you much.