I am having this problem that we compiled our python project into an exe with py2exe and the resulting exe does not work unless it is executed as an administrator.
I wanted to ask that is this supposed to happen ?? As in there are so many applications that we can run as not an administrator so is there any way I can convert my python code to such an application ...
Thanks a lot..
It sounds like your application is attempting to write to a directory for which the basic user doesn't have access; most likely the "Program Files" directory. I believe in Vista/Win7 this is not allowed, and the standard convention is to write to the user's appdata folder, for any user data you might wish to store.
You can reliably obtain the location of this directory using the ctypes module, here's an example:
import ctypes
from ctypes import wintypes
def get_appdata_directory():
CSIDL_APPDATA = 0x001a
dll = ctypes.windll.shell32
app_data_directory = ctypes.create_unicode_buffer(wintypes.MAX_PATH)
found = dll.SHGetFolderPathW(0, CSIDL_APPDATA, 0, 0, app_data_directory)
# FYI: if `found` is False, then it failed to locate the appdata directory
# and app_data_directory.value is empty. So you might want to add some
# code here to verify that a valid path is going to be returned.
# This would probably only happen on older versions of windows,
# but, this is just a guess as I don't have any older OSs available
# for testing. (see my note below)
return app_data_directory.value
appdata = get_appdata_directory()
print(appdata)
# outputs something such as: 'C:\Users\bob\AppData'
Note: I believe the appdata folder was introduced with WinXP/Win2k. Not sure about WinME and prior, however, I don't believe you have to worry about the administrator restrictions on these earlier OSs. If you really care to support them, you could use python's builtin platform module along with some conditionals, then simply write user data to the "Program Files" directory for the archaic versions of Windows.
I've had serious problems with getting py2exe to work. Luckily I found the excellent PyInstaller which not only works, but also creates smaller executables. I haven't ran into the problem you mention with PyInstaller so I recommend trying it.
http://www.pyinstaller.org/
Related
As mentioned in this related question, os.path.expanduser or pathlib.Path.home() can be used to get a path to the user home directory.
If a Python module needs to store some data, it will normally be stored somewhere in this directory, but the relative path to an appropriate location may vary by operating system. Programs running on Linux systems will typically store their settings and other data in a directory under ~/.local/share or in a dot-file directly under the home directory. In Windows, this data normally gets stored under $HOME\AppData if I recall correctly. Under macOS, the directory would be located under ~/Library/Application Support.
Is there a standard library module or third-party package available that will make it possible to do something like:
import homedir_storage
app_directory = homedir_storage.get_package_storage_dir('my_package_name')
sqlite3.connect(os.path.join(app_directory, "db.sqlite"))
Where homedir_storage represents the name of the hypothetical module/package?
To my surprise, I was unable to find a package on PyPI to fill this role, so I've created one.
It's called pypaxtor and it's really simple, just including a single function get_storage_location.
Example code from the README:
>>> import pypaxtor
>>> savedir = pypaxtor.get_storage_location('my_package')
>>> savedir # if on Mac as user `rlyacht`
PosixPath('/Users/rlyacht/Library/Application Support/pypaxtor/my_package')
>>> with open(savedir / 'SaveFile.txt') as savefile:
... # do stuff
If the above code is executed on a linux system, the saved file will be located at /home/rlyacht/.local/share/pypaxtor/my_package/SaveFile.txt.
If it's run under Windows, that location will be $HOME\AppData\Local\pypaxtor\my_package\SaveFile.txt.
That's pretty much it. Code is maintained at github. Licensed under the BSD license.
I have a C++ application (X-Plane) for which there is a plugin which permits the use of python scripts (XPPython3 plugin). The plugin is written in C, using python CAPI, and works great, allowing me to write python scripts which get executed within the C++ application.
On Windows 10, I want to extend my python features by importing imgui. I have a python cython-built pyd file (_imgui.cp39-win_amd64.pyd).
If I place the pyd file in C\Program Files\Python39\DLLs, it works as expected: C++ application calls CAPI to python, which loads script which imports and executes imgui code.
If I place the pyd file anywhere else, embedded python either reports "module not found" -- if the pyd isn't on sys.path(), or if it is on sys.path():
ImportError: DLL load failed while importing _imgui: The parameter is incorrect.'
Changes using: os.add_dll_directory(r'D:\somewhere\else')
Does not effect whether the module is found or not, nor does it change the 'parameter incorrect' error. (see https://bugs.python.org/issue36085 for details on this change. -- my guess is add_dll_directory changes lookup for DLLs, but not for pyd?) sys.path appears to be used for locating pyd.
Yes, the pyd is compiled with python3.9: I've compiled it both with mingw and with visual studio toolchains, in case that might be a difference.
For fun, I moved python-standard _zoneinfo.pyd from Python39\DLLs and it fails in the same way in embedded python: "The parameter is incorrect". So, that would appear to rule out my specific pyd file.
The key question is/are:
Other than placing a pyd file under PythonXX\DLLs, is there a way to load a PYD in an embedded python implementation? (I want to avoid having to tell users to move my pyd file into the Python39\DLLs directory... because they'll forget.)
Note that using IDLE or python.exe, I can load pyds without error -- anywhere on sys.path -- so they don't have to be under Python39\DLLs. It's only when trying to load from embedded python that the "Parameter is incorrect" appears. And of course, this works flawlessly on Mac.
(Bonus question: what parameter? It appears to be python passing through a windows error.)
There seems to be a simple answer, though I suspect it's better characterized as a python bug.
There is nothing magical about Python39\DLLs directory.
The problem is using absolute vs relative paths in sys.path.
Python can find modules using absolute or relative paths. So if zippy.py is in folder foobar,
sys.path.append('foobar')
import zippy
# Success
Python and find, BUT NOT LOAD pyd files using relative paths. For example, move _zoneinfo.pyd from PythonXX\LDDs to foobar
sys.path.append('foobar')
import _zoneinfo
# ImportError: DLL load failed while importing _zoneinfo: The parameter is incorrect.'
Instead, use absolute path, and it will find and load PYD:
sys.path.append(r'c:\MyTest\foobar')
import _zoneinfo
# Success
So, there is actually a way to do this—that is, ship your application with the desired libraries. The solution is to use an embedded distribution and ship this with your application. You can find the correct distribution on the official Python download page corresponding to your desired version (here's the link to the lastest 3.9 release which seems to be what you're using: https://www.python.org/downloads/release/python-392/). Look for the Windows Embeddable Package.
You can then simply drop in your .pyd file alongside the standard library files (note that if your third-party library is dependent on any other libraries, you will have to include them, as well). Shipping your application with an embeddable distribution should not only solve your current issue, but will also mean that your application will work regardless of which version of Python a user has installed (or without having Python installed at all).
I am currently working on a project to embed a Python interpreter in my website--I would like users to be able to execute their own Python code on the server-side in a secure Python sandbox. I have been using PyPy's sandboxing features and have set my virtual tmp/ directory (which corresponds to the real directory that the sandbox can read from) to my server-side files. So ideally, users will be able to run their own code on the server and use whatever libraries I make available to them (with no ability to write to any of these files/make system calls/do anything in general that would mess up my files).
The issue is that within my server-side code I use standard Python libraries as well as others I have installed separately (e.g. "import datetime", "import pandas", etc.). While the sandbox can read my server-side code it ends up failing whenever I try to import additional libraries within this code. I have thought of setting my virtual tmp/ directory to include my server-side files + the standard Python libraries + separately installed libraries such as PANDAS. However, when I tried setting it to just the Python libraries it ended up not working, not to mention that this solution seems pretty inelegant.
Any thoughts on how to go about fixing this? I appreciate whatever advice anyone may have. Thanks!
EDIT: I think part of the answer lies in the following portion of pypy_interact.py (the full source code can be found here: https://github.com/ojii/sandlib/blob/master/sandlib/pypy_interact.py):
def build_virtual_root(self):
# build a virtual file system:
# * can access its own executable
# * can access the pure Python libraries
# * can access the temporary usession directory as /tmp
exclude = ['.pyc', '.pyo']
if self.tmpdir is None:
tmpdirnode = Dir({})
else:
tmpdirnode = RealDir(self.tmpdir, exclude=exclude)
libroot = str(LIB_ROOT)
return Dir({
'bin': Dir({
'pypy-c': RealFile(self.executable),
'lib-python': RealDir(os.path.join(libroot, 'lib-python'),
exclude=exclude),
'lib_pypy': RealDir(os.path.join(libroot, 'lib_pypy'),
exclude=exclude),
}),
'tmp': tmpdirnode,
})
I am relatively new to Python and can't seem to figure out how to use this method properly. Any suggestions would be greatly appreciated.
I'm a python programmer and I'm trying to build an executable binary to distribute my software to my clients, even if it's not fully executable I want to be able to distribute my software in a way so that it is convenient for the end user.
I have already tried PyInstaller as well as Py2Exe and I'm facing the same problem with a particular software.
I used the splinter module for my program (which of course is a new high level framework to interact with other frameworks like Selenium) and every time I try to compile it there seems to be a file called "webdriver.xpi" that is always left out from the final package and therefore when the program attempts to execute the web-driver it fails with an IO Error saying that the file "webdriver.xpi" was not found....but other than that the GUI and everything works perfectly fine.
So is there a way to include it even manually? I tried including it manually by browsing to the specific folder # library.zip file but it didn't work.
I'm not really expert in this matter and I rely on GUI2Exe for building everything...and I would really appreciate some advice if possible on how to fix this.
Thanks.
I was at this all day and found a workaround, it's sneaky but it works. In the error message I was receiving I noticed that there was a space between in library .zip. I could not trace it down in the source code for py2exe or selenium. I too had tried putting the xpi file in the library zip and it did not work. The workaround is:
In your setup file use these options:
setup(
console=['yourFile.py'],
options={
"py2exe":{
"skip_archive": True,
"unbuffered": True,
"optimize": 2
}
}
)
Run the py2exe install
Copy the xpi file into the dist directory
That should do it.
You need an instruction in your setup.py to include any resource files in your distribution. There is a couple of ways of doing this (see distutils, setuptools, distribute - depending on what you are using to build your distribution), but the py2exe wiki has an example.
You may need to use this py2exe tip to find your resources if you're installing them into the same directory as your exe.
See this answer for some additional info on including resource files in your distribution.
Here is a solution of your question:
I have modify a code little and it should be work since I had a same issue and I solved it:
from distutils.core import setup
import py2exe
wd_base = 'C:\\Python27\\Lib\site-packages\\selenium-2.44.0-py2.7.egg \\selenium\\webdriver'
RequiredDataFailes = [
('selenium/webdriver/firefox', ['%s\\firefox\\webdriver.xpi'%(wd_base), '%s\\firefox\\webdriver_prefs.json'%(wd_base)])
]
setup(
windows=[{"script":"gui_final.py"}],options={"py2exe":{"skip_archive": True,"includes":["sip"]}},
data_files=RequiredDataFailes,
)
I know this is old, but I wanted to give an updated answer to avoid suggesting that programmers do something manually.
There is a py2exe option to specify a list of data files as tuples. (pathtocopyto, [list of files and where to get them])
Example:
from disutils.core import setup
import py2exe
wd_base = 'C:\\Python27\\Lib\\site-packages\\selenium\\webdriver'
RequiredDataFailes = [
('selenium/webdriver/firefox', ['%s\\firefox\\webdriver.xpi'%(wd_base), '%s\\firefox\\webdriver_prefs.json'%(wd_base)])
]
setup(
console=['MyScript.py'],
data_files=RequiredDataFiles,
options={
**mypy2exeopts
}
)
The only downside I am aware of currently is that you still need skip_archive = True. There are workarounds to get the data files in the library.zip, but I haven't had much luck with the webdriver's info.
I have lots of directories with text files written using (g)vim, and I have written a handful of utilities that I find useful in Python. I start off the utilities with a pound-bang-/usr/bin/env python line in order to use the Python that is installed under cygwin. I would like to type commands like this:
%cd ~/SomeBook
%which pythonUtil
/usr/local/bin/pythonUtil
%pythonUtil ./infile.txt ./outfile.txt
(or % pythonUtil someRelPath/infile.txt somePossiblyDifferentRelPath/outfile.txt)
pythonUtil: Found infile.txt; Writing outfile.txt; Done (or some such, if anything)
However, my pythonUtil programs keep telling me that they can't find infile.txt. If I copy the utility into the current working directory, all is well, but then I have copies of my utilities littering the landscape. What should I be doing?
Yet Another Edit: To summarize --- what I wanted was os.path.abspath('filename'). That returns the absolute pathname as a string, and then all ambiguity has been removed.
BUT: IF the Python being used is the one installed under cygwin, THEN the absolute pathname will be a CYGWIN-relative pathname, like /home/someUser/someDir/someFile.txt. HOWEVER, IF the Python has been installed under Windows (and is here being called from a cygwin terminal commandline), THEN the absolute pathname will be the complete Windows path, from 'drive' on down, like D:\cygwin\home\someUser\someDir\someFile.txt.
Moral: Don't expect the cygwin Python to generate a Windows-complete absolute pathname for a file not rooted at /; it's beyond its event horizon. However, you can reach out to any file on a WinXP system with the cygwin-python if you specify the file's path using the "/cygdrive/driveLetter" leadin convention.
Remark: Don't use '\'s for separators in the WinXP path on the cygwin commandline; use '/'s and trust the snake. No idea why, but some separators may be dropped and the path may be modified to include extra levels, such as "Documents and Settings\someUser" and other Windows nonsense.
Thanks to the responders for shoving me in the right direction.
Look at os.getcwd:
http://docs.python.org/library/os.html#os-file-dir
Edit: For relative paths, please take a look at the os.path module:
http://docs.python.org/library/os.path.html
in particular, os.path.join and os.path.normpath. For instance:
import os
print os.path.normpath(os.path.join(os.getcwd(), '../AnotherBook/Chap2.txt'))
What happens when you type "ls"? Do you see "infile.txt" listed there?
os.chdir(my_dir)
or
os.chdir(os.getcwd())