I am trying to create an installer for a program that uses the pywin32 bindings to edit some excel spreadsheets. I have created an executable using py2exe and everything works when running the executable out of a folder on the desktop. However, I wish to be able to distribute a single installer file that will install the program into C:\Program Files\ or equivalent folder on whatever system. I have also succeeded in this, however, when the pywin32 bindings are used they create temporary files wherever the working directory is.
This is highly problematic as newer versions of windows have made it so only administrators have permission to write to these directories. Because of this when the app is run from these directories it fails with the error:
WindowsError: [Error 5] Access is denied: 'C:\\Program Files (x86)\\DataPlotter\\.\\win32com\\gen_py\
\00020813-0000-0000-C000-000000000046x0x1x6'
Changing the app to run with administrator permissions is a bad solution as it can introduce vulnerabilities.
Does anybody know of a fix to this problem or how to change the location that the pywin32 bindings use as a temporary file location.
It is a stupid hack-y solution but this problem can be avoided by doing a runaround on pywin32.
By switching the current working directory to one that is guaranteed to be safe to write to such as the temp directory it is possible to avoid the problem.
#Save the current working directory and then switch back once
#excel has been started. This is so pywin32 does not ruin everything
#by trying to write in the current directory without the proper
#permission. This mainly happens (for me) when the program is installed in
#program files which requires administrator permissions to write to.
import os
import tempfile
import win32com.client
cwd = os.getcwd()
tdir = tempfile.gettempdir()
os.chdir(tdir)
self.xl = win32com.client.gencache.EnsureDispatch("Excel.Application")
os.chdir(cwd)
N.B. the switch at the end back to the original working directory is not necessary but it will work if you need it (as I did).
martineau suggested a more robust way of doing this below using contextmanagers:
from contextlib import contextmanager
@contextmanager
def tempManager(self):
cwd = os.getcwd()
tdir = tempfile.gettempdir()
os.chdir(tdir)
yield
os.chdir(cwd)
with self.tempManager():
self.xl = win32com.client.gencache.EnsureDispatch("Excel.Application")