I recently finished a stand alone Python program that uses Arcpy extensively. I wanted to package and distribute it as an executable so my users would have minimal problems trying to get the program working. My program uses third-party libraries and I needed to update numpy on all the computers I tried to use it on. The Tcl/Tk package was out of date on one of the computers and trying to update it was a nightmare. Even though people using my program already have Python because they have ArcGIS, I really needed to get my program into an executable so my users would not have to endure the headache of setting up their Python environment to run my program.
Cue Py2exe. I set it up, ran my .exe, and got an error immediately: "arcpy module could not be found" or something to that effect. Well, crap.
A bit of Internet searching did not turn up the results I wanted. There were some complicated workarounds, such as calling the arcpy module in a subprocess, creating and using a wrapper script, or rewrite the script entirely. Someone even said that it just can't be done. Well, it can, and the solution is actually very simple, elegant (in my opinion), and requires very little extra effort by the user and the developer.
Arcpy isn't packaged with the rest of the files when the executable is made, and forcing it to package the module is sure to be a gross violation of the ArcGIS user agreement. Every user of the program will already have the arcpy module somewhere on their computer, so to get the executable to work, we just need to tell the program where to look for the arcpy module. Unfortunately, the location of the arcpy module is likely to be different on everyone's computer. Fortunately, the arcpy module isn't located with the rest of the Python modules anyway! Instead, a .PTH file tells the program where to find the module. We can make this work for us with Py2exe.
1. Exclude "arcpy" from the Py2exe setup.py script.
I'm not 100% sure this is necessary, to be honest. There's no harm in doing it though.
options = {"py2exe": {"excludes": ["arcpy"]}}
setup(console=['MyProgram.py'], options=options)
2. Add the executable directory + "\\site-packages" to the Python site directory in the main code of MyProgram.py.
sys.executable gives the file path of the Python interpreter. In this case, the Python interpreter is the executable. The .PTH file needs to go into a folder called "site-packages" in order for the arcpy module to import correctly. (You will add the site-packages folder manually to the dist folder after Py2exe has completed its job.) If you're not using Windows, change the backslashes to a single forward slash, ie + "/site-packages". I also added the code to any script that would be running as a separate process, just in case.
from site import addsitedir
from sys import executable
from os import path
interpreter = executable
sitepkg = path.dirname(interpreter) + "\\site-packages"
addsitedir(sitepkg)
3. Run Py2exe as usual.
4. Add a "site-packages" folder to the "dist" folder.
5. Navigate to the GIS-installed Python folder, usually C:/Python27/ArcGIS10.x/Lib/site-packages
6. Copy the "Desktop10.x" PTH file and paste it into the "site-packages" folder in the "dist" directory for your application.
That's it. The executable should load the arcpy module now.
Instruct your users to copy the "Desktop10.x" PTH file into the executable's "site-packages" folder prior to running the application for the first time and it should work for them, too.