I've been working on getting a python executable working for OSX El Capitan, and i successfully get the executable built using both Pyinstaller and cx_Freeze, the issue comes when i actually run the executable on another mac. The error i get is about not being able to find the .db file referenced in my main script, so i looked at documentation for both programs and came across sys.MEIPASS (Pyinstaller) and sys.executable (cx_Freeze) to include data files in the --onefile app. This is the code i used in my main script:
def find_data_file(filename):
if getattr(sys, 'frozen', False):
# The application is frozen
datadir = os.path.dirname(sys._MEIPASS) #in cx_Freeze this is sys.executable
else:
# The application is not frozen
# Change this bit to match where you store your data files:
datadir = ospath.abspath(os.pardir)
return os.path.join(datadir, filename)
#This is how im using the "find_data_file" function in my code.
dbpath = find_data_file('PubData.db')
conn = lite.connect(dbpath)
ive changed it a bit in the else statement to match the layout of my project directories, and it works perfectly fine when running an unfrozen application.
However when i try to run using the built executable it gives me an error about not being able to find the .db file, which i thought referencing sys.MEIPASS or sys.executable would fix.
Error:
Traceback (most recent call last):
File "interface/GUI.py", line 673, in <module>
File "interface/GUI.py", line 82, in __init__
File "interface/GUI.py", line 212, in getServerNames
sqlite3.OperationalError: no such table: servernames
This is how my file tree looks:
PubData-master ##(Project Root Directory)
Interface ##(Directory)
GUI.py ##(Main Script, this is where i reference 'PubData.db')
GUI.spec ##(Pyinstaller spec file)
PubData.db ## This is my database file, in the PubData-master Directory
If anyone could tell me what i am doing wrong, or give me a solution, i would be extremely grateful!
if you are trying to access any data file you specified in the .spec file, in your code, you must use Pyinstaller's _MEIPASS folder to reference your file. Here is how i did so with the file named Data.db:
import sys
import os.path
if hasattr(sys, "_MEIPASS"):
datadir = os.path.join(sys._MEIPASS, 'Data.db')
else:
datadir = 'Data.db'
conn = lite.connect(datadir)
this replaced the following single line:
conn = lite.connect("Data.db")
This link explained it very well:
https://irwinkwan.com/2013/04/29/python-executables-pyinstaller-and-a-48-hour-game-design-compo/
Related
I am attempting to make a simple pygame game, and I need to load in some images. When I run my code, or:
bg_image = pygame.image.load('assets/Fondotiff.tif(1).png').convert_alpha()
It gives me an error which says:
Traceback (most recent call last):
File "C:\Users\victo\Desktop\Assets - Pulga\mainpulga.py", line 12, in <module>
bg_image = pygame.image.load('assets/Fondotiff.tif(1).png').convert_alpha()
FileNotFoundError: No file 'assets/Fondotiff.tif(1).png' found in working directory 'C:\Users\victo\Desktop\Assets - Pulga'.
***Repl Closed***
I have double checked if the image is inside the folder on my desktop and it is there, but for some reason it doesn't find it.
How can I fix this?
The asset file path has to be relative to the current working directory. The working directory is possibly different from the directory of the python file.
It is not enough to put the files in the same directory or sub directory. You also need to set the working directory.
e.g.:
import os
os.chdir(os.path.dirname(os.path.abspath(__file__)))
I get an error when i'm compiling with pyinstaller it works on my pc not on a different pc.
error i get
Traceback (most recent call last):
File "app.py", line 30, in <module>
password = parser.get('settings', 'password')
File "configparser.py", line 781, in get
File "configparser.py", line 1152, in _unify_values
configparser.NoSectionError: No section: 'settings'
[9464] Failed to execute script 'app' due to unhandled exception!
Here is my code
parser = ConfigParser()
parser.read('C:\\Users\\abc\Desktop\\Maker\\settings.ini')
I followed some solutions but still no luck is solving this can anyone please help?
I tried this solution as well with no luck
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
parser = ConfigParser()
settings_file = resource_path('settings.ini')
You have to make sure you are bundling your ini file with your application. This is a little more difficult if you are using UPX to compress all files into one executable file. I never saw the point in this because it seems like a false savings. Every time you run the EXE it will decompress all files into a temporary folder. Then your application now consumes all of the uncompressed space plus all of the compressed space. Bleah.
I would recommend you use a Spec file to specify all of the additional
files you want to include with your application.
For debugging purposes, you can put this in your program to make sure the ini file is where you think it is (you can delete it or comment it out once you verify the file is there)
print(os.listdir(<path>))
or
print(os.listdir(os.getcwd()))
where getcwd stands for 'get current working directory' which should be the directory where your EXE resides.
If you don't want to mess with a spec file, you can pass the --add-data parameter to pyinstaller and pass your ini file.
I'm trying to export my .py script to .exe using PyInstaller, which has dependencies on .ui files which were created using Qt Designer.
I can confirm that my .py script works just fine when running it through PyCharm - I'm able to see the GUI I've created with the .ui files.
However, when I export my .py script to .exe and launch it, I recieve the following errors in the command line:
C:\Users\giranm>"C:\Users\giranm\PycharmProjects\PyQt Tutorial\dist\secSearch_demo.exe"
Traceback (most recent call last):
File "secSearch_demo.py", line 13, in <module>
File "site-packages\PyQt4\uic\__init__.py", line 208, in loadUiType
File "site-packages\PyQt4\uic\Compiler\compiler.py", line 140, in compileUi
File "site-packages\PyQt4\uic\uiparser.py", line 974, in parse
File "xml\etree\ElementTree.py", line 1186, in parse
File "xml\etree\ElementTree.py", line 587, in parse
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\giranm\\securitySearchForm.ui'
Failed to execute script secSearch_demo
For some reason, the .exe file is looking for the .ui file within the path - C:\Users\giranm\
However, having done some research already, I was told that I needed to use os.getcwd() and ensure that I have the full path in my script. Even with the code below, I still get errors trying to locate the .ui files.
PyInstaller: IOError: [Errno 2] No such file or directory:
# import relevant modules etc...
cwd = os.getcwd()
securitySearchForm = os.path.join(cwd, "securitySearchForm.ui")
popboxForm = os.path.join(cwd, "popbox.ui")
Ui_MainWindow, QtBaseClass = uic.loadUiType(securitySearchForm)
Ui_PopBox, QtSubClass = uic.loadUiType(popboxForm)
# remainder of code below.
I'm aware that one can convert .ui files to .py and import them into the main routine using pyuic4. However, I will be making multiple edits to the .ui files
and thus it is not feasible for me to keep converting them.
Is there anyway to fix this so that I can create a standalone .exe?
I'm fairly new to using PyQT4 and PyInstaller - any help would be much appreciated!
After scratching my head all weekend and looking further on SO, I managed to compile the standalone .exe as expected using the UI files.
Firstly, I defined the following function using this answer
Bundling data files with PyInstaller (--onefile)
# Define function to import external files when using PyInstaller.
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
Next I imported the .UI files using this function and variables for the required classes.
# Import .ui forms for the GUI using function resource_path()
securitySearchForm = resource_path("securitySearchForm.ui")
popboxForm = resource_path("popbox.ui")
Ui_MainWindow, QtBaseClass = uic.loadUiType(securitySearchForm)
Ui_PopBox, QtSubClass = uic.loadUiType(popboxForm)
I then had to create a resource file (.qrc) using Qt Designer and embed images/icons using this resource file. Once done, I used pyrcc4 to convert the .qrc file to .py file, which would be imported in the main script.
Terminal
C:\Users\giranm\PycharmProjects\PyQt Tutorial>pyrcc4 -py3 resources.qrc -o resources_rc.py
Python
import resources_rc
Once I have confirmed the main .py script works, I then created a .spec file using PyInstaller.
Terminal
C:\Users\giranm\PycharmProjects\PyQt Tutorial>pyi-makespec --noconsole --onefile secSearch_demo.py
As per PyInstaller's guide, I've added data files by modifying the above .spec file.
https://pythonhosted.org/PyInstaller/spec-files.html#adding-data-files
Finally, I then compiled the .exe using the .spec file from above.
You can simply use:
uic.loadUi(r'E:\Development\Python\your_ui.ui', self)
Use the full path, and use pyinstaller with standard arguments, and it works fine. The r prefix makes sure the backslashes are interpreted literally.
Another method, tested on Ubuntu 20.04 is to add the .ui file to the data section in the spec file. First generate a spec file with pyinstaller --onefile hello.py. Then update the spec file and run pyinstaller hello.spec.
a = Analysis(['hello.py'],
...
datas=[('mainwindow.ui', '.')],
...
The next step is to update the current directory in your Python file. To do this, the os.chdir(sys._MEIPASS) command has to be used. Wrap it in a try-catch for development use when _MEIPASS is not set.
import os
import sys
# Needed for Wayland applications
os.environ["QT_QPA_PLATFORM"] = "xcb"
# Change the current dir to the temporary one created by PyInstaller
try:
os.chdir(sys._MEIPASS)
print(sys._MEIPASS)
except:
pass
from PySide2.QtUiTools import QUiLoader
from PySide2.QtWidgets import QApplication
from PySide2.QtCore import QFile, QIODevice
if __name__ == "__main__":
app = QApplication(sys.argv)
ui_file_name = "mainwindow.ui"
ui_file = QFile(ui_file_name)
if not ui_file.open(QIODevice.ReadOnly):
print(f"Cannot open {ui_file_name}: {ui_file.errorString()}")
sys.exit(-1)
loader = QUiLoader()
window = loader.load(ui_file)
ui_file.close()
if not window:
print(loader.errorString())
sys.exit(-1)
window.show()
sys.exit(app.exec_())
I'm fairly new with programming (and with Python) and the Stack Overflow question/response system allowed me to resolve all my problems until now. I didn't find any post directly addressing my current issue, but have to admit that I don't really know what's wrong. Let me explain.
I'm trying to make an executable file of a *.py script using PyInstaller. There's no problem doing it with a simple Python script (using --onefile), but it does not work when it comes to a more complex program that uses other *.py and *.txt files. I know that I need to modify the specification file and tried many alternatives - adding hidden files for instance.
Here are the files:
UpdatingStrategy.py (the target file to transform in executable)
LPRfunctions.py (UpdatingStrategy.py imports functions from this file)
The following *.txt files are read by UpdatingStrategy.py:
Strategy_Observ.txt
Strategy_Problems.txt
Updating_Observ1.txt
Updating_Observ2.txt
Updating_Problems.txt
I'm using Python 3.5 and Windows 10. Tell me if you need extra information.
How do I use the specification file properly and modify it in order to make an executable file of UpdatingStrategy.py?
I have read the PyInstaller documentation, but I lack many key principles and I couldn't make it work.
After the line
a = Analysis( ... )
add
a.datas += [
("/absolute/path/to/some.txt","txt_files/some.txt","DATA"),
("/absolute/path/to/some2.txt","txt_files/some2.txt","DATA"),
("/absolute/path/to/some3.txt","txt_files/some3.txt","DATA"),
]
Then in your program use the following to get the resource path of your .txt files.
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
base_path = sys._MEIPASS
except Exception:
base_path = os.environ.get("_MEIPASS2",os.path.abspath("."))
return os.path.join(base_path, relative_path)
...
txt_data = open(resource_path("txt_files/some.txt")).read()
Make sure you build it like python -m PyInstaller my_target.spec ... do not call PyInstaller directly against your .py file after you have edited your specification file or it will overwrite your edited file...
Anyone reading this in 2021... I've just run into similar issue with Pyinstaller. Needed to add a text file to my python code:
pyinstaller --add-data "/my/path/to/mytextfile.txt:/path/mytextfile.txt" mypython.py --onedir or --onefile
No matter if onedir or onefile, my code just never found the text file. Infact it threw the error:
IsADirectoryError: [Errno 21] Is a directory: /path/mytextfile.txt
Which didn't make sense to me because that's a file not a folder. Only when I checked this with the --onedir flag and I followed the path, I realized that pyinstaller would not only create a folder path, but also folder mytextfile.txt and put mytextfile.txt in there... so really the --add-data flag only wants a destination folder not the path to the file.
pyinstaller --add-data "/my/path/to/mytextfile.txt:path" mypython.py
or in the spec file i.e mypython.spec
datas=[('/my/path/to/mytextfile.txt', 'path')]
Should fix this. Note also the "DATA" configuration in the spec file is gone.
I have converted a python game I designed into an exe. Running the exe itself causes it to flash and then close, meaning an error has occured. Running it from the Command Prompt causes the error as well, but documents it:
Cannot load image: Playfield.png
Couldn't open images\Playfield.png
This is telling me that the load_image block is failing. I have encountered this before when I did not have an images directory.
I attempted to move the images folder to the dist directory. This is the error that shows up:
Traceback (most recent call last):
File "Table_Wars.py", line 728, in <module>
File "Table_Wars.py", line 51, in main
File "Table_Wars.py", line 236, in __init__
File "pygame\__init__.pyc", line 70, in __getattr__
NotImplementedError: font module not available
(ImportError: DLL load failed: The specified module could not be found.)
This is my first time with py2exe, so I'm not really sure what is happening. The raw python file itself, Table_Wars.py, runs as expected.
If it helps, the location for the entire Table_Wars folder is inside a folder called Games, located on my Desktop (C:\Users\Oventoaster\Desktop\Games\Table_Wars). I am running Windows 7 32 bit OS.
On request, here is the output.txt I have generated:
Folder PATH listing for volume OS
Volume serial number is 7659-4C9C
C:\USERS\OVENTOASTER\DESKTOP\GAMES\TABLE_WARS
build
bdist.win32
winexe
bundle-2.7
collect-2.7
ctypes
distutils
email
mime
encodings
logging
multiprocessing
dummy
pygame
threads
unittest
xml
parsers
temp
dist
images
Here is the setup.py I used to convert the file:
from distutils.core import setup
import py2exe
setup(console=['Table_Wars.py'])
EDIT: I have attempted to use the full py2exe example. This will create the exe, but gives the same Cannot load image error. Attempting to put the images folder in the same folder as the exe creates a Runtime Error: The application requested the runtime to terminate it in an unusual way.
The shortened form of the code Slace Diamond suggested prevents py2exe from finding Table_Wars.py:
from cmd:
running py2exe
*** searching for required modules ***
error: Table_Wars.py: No such file or directory.
setup and Table_Wars are in the same directory. If it help, I input the full path to python.exe and setup.py.
EDIT: I seem to be getting closer. I put the images directory within self.extra_datas, and now I am getting this:
Fatal Python error: (segmentation fault)
This application has requested the runtime to terminate it in an unusual way. Please contact the application's suppourt team for more information
When you build a distributable package with py2exe (and py2app for that matter), part of the package environment is to point to a local resource location for files. In your plain unpackaged version, you are referring to a relative "images/" location. For the packaged version, you need to configure your setup.py to include the resources in its own location.
Refer to this doc for very specific info about how to set the data_files option of your package: http://www.py2exe.org/index.cgi/data_files
That page has multiple examples to show both very simple paths, and also a helper function for finding the data and building the data_files list for you.
Here is an example of the simple snippet:
from distutils.core import setup
import py2exe
Mydata_files = [('images', ['c:/path/to/image/image.png'])]
setup(
console=['trypyglet.py.py']
data_files = Mydata_files
options={
"py2exe":{
"unbuffered": True,
"optimize": 2,
"excludes": ["email"]
}
}
)
This closely matches what you are trying to achieve. It is saying that the "image.png" source file should be placed into the "images" directory at the root of the resources location inside the package. This resource root will be your current directory from your python scripts, so you can continue to refer to it as a relative sub directory.
It looks like you've already fixed the image problem by moving the folder into dist. The missing font module, on the other hand, is a known problem between pygame and py2exe. Py2exe doesn't copy some necessary DLLs, so you have to override py2exe's isSystemDLL method, forcing it to include audio and font related DLLs.
If Table_Wars.py is the only module in your project, try running this script with python setup.py py2exe:
from os.path import basename
from distutils.core import setup
import py2exe
origIsSystemDLL = py2exe.build_exe.isSystemDLL
def isSystemDLL(pathname):
if basename(pathname).lower() in ("libogg-0.dll", "sdl_ttf.dll"):
return 0
return origIsSystemDLL(pathname)
py2exe.build_exe.isSystemDLL = isSystemDLL
setup(windows=[{"script": "Table_Wars.py"}],
options={"py2exe": {"dist_dir": "dist"}})
You could also try the example py2exe setup file on the pygame wiki. If neither of them are working, please add the error messages to your question.
I tried running py2exe on a sample project, and it also breaks for me when I use the default pygame font. If you're using the default font, try putting a ttf file in the root of your project and also in the dist folder. You'll have to change the call to pygame.Font in your script as well:
font = pygame.font.Font("SomeFont.ttf", 28)