pyinstaller: packaging multiple python scripts under Mac - python

This is my first time using pyinstaller. My goal is to build an .app in Mac Mountain Lion. The app is basically a GUI written in PySide, and I have about 7 different Python scripts + 1 .png file. The main file calls 4 of the files, and the 4 files will call the rest of the 2 files repeatedly. The .png file is nothing but the window logo. Could someone help me with some diagnosis? I do not know what went wrong. I searched a lot of documentations online, i.e., change spec, add import, ... etc. but my app still doesn't run.
FYI, Pyinstaller could generate an app for me, but there are two issues:
Icon is not changed for the app.
App crashes when opened.
My Python version is 2.7.5 and I am using PyInstaller-2.0. Here is my code for packaging:
python pyinstaller.py --onefile --windowed --name=MyApplication -i ~/Documents/AASource/icon.ico ~/Documents/AASource/Scripts/main_file.py
Here is the spec file:
# -*- mode: python -*-
a = Analysis(['/Users/boxuancui/Documents/AASource/Scripts/main_file.py'],
pathex=['/Users/boxuancui/Documents/pyinstaller-2.0'],
hiddenimports=[],
hookspath=None)
pyz = PYZ(a.pure)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
name=os.path.join('dist', 'MyApplication'),
debug=False,
strip=None,
upx=True,
console=False , icon='/Users/boxuancui/Documents/AASource/icon.ico')
app = BUNDLE(exe,
name=os.path.join('dist', 'MyApplication.app'))
Here is part of the crash message:
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x00000000000054d8
Thanks in advance! Any help will be appreciated!
UPDATE1: I have narrowed down the problem to this: whenever I tried to do the following imports, the created app will crash. Does anyone know why?
import pandas.rpy.common as com
import pandas.io.sql as psql
import rpy2.robjects as robjects
UPDATE2: I take a closer look into pandas.io.sql. There is no such module existing. That's why PyInstaller cannot find it. Where can I find this file? Similarly, rpy2.objects and pandas.rpy.common are missing too.

Can you import pandas.io.sql from your python console?
Are those imports in the main file? If not try doing so

Related

How to package python and kivy application for Raspbian Buster

I am currently writing an application for a raspberry pi 3 using python3.7 and kivy1.11.1. I am trying to package a test application to ensure that it will work. I have created a simple grid with 6 buttons. When you click on a button it prints "button pressed" to the screen. I am using a separate kv file to lay this out as this will be more practical as the application develops. So I have two files, "test.py" and "Test.kv".
I have been using pyinstaller to package my app but it is not working. It runs and creates the executable file just fine with no errors. I then drag my executable file out to my main folder from the "dist" folder as recommended in this video.
My command is:
pyinstaller --onefile --add-data "Test.kv:." test.py
I have also tried:
pyinstaller --onedir --add-data "Test.kv:." test.py
which does the same: blank window no widgets, no errors.
When I try to execute it nothing happens. I don't know what is wrong because I'm not getting any errors when I try to execute it from the terminal. When I do the exact same process on windows it works so its not the code. On occasion, I think it does eventually run but I just get a blank screen and again no error. This would leave me to believe it's an issue with reading the .kv file.
Perhaps this process doesn't work with kivy and I need to use some other method to package my application. However I have also tried this kind of approach but it has left me with errors. I much prefer the pyinstaller method however I don't know if it is going to work as it doesn't seem to pick up the .kv file.
Any help/advice on this issue would be greatly appreciated?
My test.spec file:
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(['test.py'],
pathex=['/home/pi/Desktop/WinTest'],
binaries=[],
datas=[('Test.kv', '.')],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='test',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False )
The following picture is my program folder (sorry for the poor quality). My library files are in venv/Lib/site-packages. This is where my kivy/kivy_deps folders are. Could the issue be that the program can't find my library files? But surely if that was the issue it would throw a "file not found" error? And as previously stated, I am not receiving any errors.
Found this in my warn-text.txt file
missing module named kivy.lib.vidcore_lite.egl - imported by kivy.lib.vidcore_lite (top-level), kivy.core.window.window_egl_rpi (top-level)
missing module named kivy.lib.vidcore_lite.bcm - imported by kivy.lib.vidcore_lite (top-level), kivy.core.window.window_egl_rpi (top-level)

How do I resolve a missing utility module preventing my executable from running when I already installed the parent module?

I've written a few Python scripts to create a tkinter GUI for a machine learning algorithm process. I originally coded everything in PyCharm, but I'd really like to put everything together into a stand-alone executable. I've moved my main script and its .py dependencies into their own directory and tested it out using the Command Prompt, and it works great. However, when I run pyinstaller, the executable is created but fails on startup.
The program is made up of three files, with GUI.py being the main script. As mentioned above, I moved the dependent files into a new directory and tested GUI.py in the Command Prompt, and it worked great. Executable is created (albeit with a lot of warnings about missing 'api-ms-win-crt' files) but can't be run.
I created the executable using the command:
pyinstaller --onefile GUI.py
When the executable is run from the command line after creation, I get a big long traceback ending in the following:
File "site-packages\sklearn\metrics\pairwise.py", line 32, in <module>
File "sklearn\metrics\pairwise_fast.pyx", line 1, in init
sklearn.metrics.pairwise_fast
ModuleNotFoundError: No module named 'sklearn.utils._cython_blas'
[3372] Failed to execute script GUI
I know I've already explicitly imported sklearn through the command prompt, but from the traceback, it seems I'm missing a utility module somewhere. I tried to import the missing module specifically, but I got an error that no distributed module was available.
I don't have much experience with pyinstaller, and I have no idea where to go from here. I'm using Windows 10 and Python 3.7.3.
It seems that Pyinstaller can't resolve sklearn import. So one easy way is to just bring the whole module directory which located in <path_to_python>/Lib/site-packages/sklearn/ with executable output. So use below spec file to generate your executable:
# -*- mode: python -*-
block_cipher = None
a = Analysis(['test.py'],
pathex=['<path to root of your project>'],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
a.datas += Tree('<path_to_sklearn_in_python_dir>', prefix='sklearn')
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='test',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=False,
runtime_tmpdir=None,
console=True )
Finally generate your executable with
pyinstaller test.spec
This should resolve import errors for sklearn but if you face other NotFound imports add them like above to spec file.
Building up on M.R.'s answer, you can directly include the path to sklearn in your original pyinstaller command:
pyinstaller --onefile GUI.py --add-data "<path-to-python>\Lib\site-packages\sklearn;sklearn"
which results in the following line of code being added inside a = Analysis() in the automatically-generated GUI.spec file:
datas=[('<path-to-python>\\Lib\\site-packages\\sklearn', 'sklearn')]
Note that the --onefile option will result in an executable that is slower to start up than the default one-folder bundle (based on both the pyinstaller documentation and my own experience bundling up sklearn):
pyinstaller GUI.py --add-data "<path-to-python>\Lib\site-packages\sklearn;sklearn"

How to tidy up a packaged Python app with pyinstaller?

So, let's say I got a simple pyqt app main.py:
import sys
from PyQt5 import QtWidgets
def main():
app = QtWidgets.QApplication(sys.argv)
w = QtWidgets.QWidget()
w.resize(250, 150)
w.move(300, 300)
w.setWindowTitle('Simple')
w.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
And then i got a main.spec which packages the app in one folder:
# -*- mode: python -*-
block_cipher = None
import inspect, os
current_path = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
a = Analysis(['main.py'],
pathex=[current_path],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
exclude_binaries=True,
name='main',
debug=False,
strip=False,
upx=False,
console=True )
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=False,
name='main')
The outcome of doing pyinstaller main.spec will be a working pyqt app which has a mess of files:
So, here's the thing, I don't like the current outcome and I also don't like the option of using --onefile (the idea of extracting files into a temp directory is not my cup of tea).
Now, I've found this interesting article which presents a solution to this problem and I was trying to reproduce it here with this simple mcve but for some reason I've got stuck at certain point. Here's the steps i've followed:
1) I've created a file pyinstaller\use_lib.py:
import sys
import os
sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), "lib"))
2) I've replaced runtime_hooks=[] by runtime_hooks=['.\\pyinstaller\\use_lib.py'] in the above main.spec file
3) I've rerun pyinstaller main.spec, which has generated the bunch of messy files like the above screenshot
4) I've moved manually all dependency files to a lib directory and the results is this:
PROBLEM: When i try to run the app will crash:
Why do you think it's crashing? At which step I've messed up? Could you please explain me how to fix it?
You can't move those dlls away from exe (into another directory). Those dlls are linked statically and should be placed in the same directory as exe.
Anyway. Look into some application folders inside of your C:\Program Files. There are big bunch of files inside each of those directories. It is just the way it goes. And no one cares because users does not look into these folders.
If you want to distribute your application you should act as all other developers. Folder state after using PyInstaller is not the final form of your application but only an initial form: any C/C++ application will start its way to the users from this exact form.
So if you want to distribute your application to the users you should use one of the installer tools. The best form of installation packet for the Windows platform is msi packet (made for "Windows Installer"). To build your msi packet you may use WiX Installer (the simplest way to create msi packets) or MS Visual Studio. Also there is a plenty amount of installation tools which will generate exe form of installation packets (and usually they are much more simple to use than msi-tools): NSIS, Inno Setup, InstallShield (paid!), etc. Also you may search names of this installers through https://pypi.python.org/pypi database: there are some special Python packets which you can use to manage some of this installation tools.

Kivy app crashes after packaging with pyinstaller

Here are some of the pointers for the issue I've been facing:
Trying to package a example app that comes with Kivy.
I am able to run the app normally via command line [kivy main.py]
When I try to package the app with Pyinstaller, the spec file is generated, and the app can be packaged, but this is what I see in the warning text file: http://pastebin.com/3D2A9ZLG
The app is not able to start after that, and this is the error I see in the console logs: (com.apple.xpc.launchd.oneshot.0x10000028.day2[6584]) Service exited with abnormal code: 1
Kivy Installation
Installed Kivy 1.9.0 on Mac OS X Yosemite using the DMG that came with the download. And ran the MakeSymbols script with sudo user.
Kivy is currently installed in the Applications folder
Pyinstaller 2.0 is being used by downloading the code from their Github repo, and running kivy pyinstaller --windowed --name guide main.py
I'm using Python 2.7
Code:
Here's the spec file for the app I tried creating with the example:
# -*- mode: python -*-
from kivy.tools.packaging.pyinstaller_hooks import install_hooks
install_hooks(globals())
a = Analysis(['/Users/karthik/Desktop/SHRINK/kivy/examples/guide/quickstart/main.py'],
pathex=['/Users/karthik/Desktop/SHRINK/pyinstaller-2.0'],
hiddenimports=[])
pyz = PYZ(a.pure)
exe = EXE(pyz,
a.scripts,
exclude_binaries=1,
name=os.path.join('build/pyi.darwin/day2', 'day2'),
debug=False,
strip=None,
upx=True,
console=False )
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=None,
upx=False,
name=os.path.join('dist', 'day2'))
app = BUNDLE(coll,
name=os.path.join('dist', 'day2.app'))
Any help would be highly appreciated.
I can see a couple of issues, you're using the os library without importing it which should cause some issues and according to here: (http://kivy.org/docs/guide/packaging-windows.html) you need to include the path in the COLLECT statement so kivy can find everything.
coll = COLLECT( exe, Tree('../kivy27/examples/demo/touchtracer/'),
a.binaries, Tree([f for f in os.environ.get('KIVY_SDL2_PATH', '').split(';') if 'bin' in f][0])
#...
)
Kivy 1.9.0 also uses SDL2 instead of Pygame so you need to link pyinstaller to that as well. In my experience Kivy is quite tempermental working through Pyinstaller so I recommend attempting to follow the link I posted above.

Packaging pygame python scripts for cross-platform

What is the best way to package python scripts using the pygame module as cross platform executables? I need to be able to compile from my Linux machine. I've tried using PyInstaller, however, when I run the compiled executable, it says it can't find the pygame module. When I running it as a python script through the Wing IDE debug it works fine, so I clearly have pygame installed. However, when I try running without the IDE debug it fails to create a windows. Is there something wrong with my script that it can only be run through Wing IDE? How can I package my game so that it work on any computer, Linux or Windows, without even needed python or pygame? Is this even possible?
My source: https://github.com/william1008/TrappedTux
PyInstaller works fine to build a Windows executable that embed both python and pygame.
Here is the spec file I'm using:
# -*- mode: python -*-
a = Analysis(['MyApplication.py'],
pathex=['.'],
hiddenimports=[],
hookspath=None,
runtime_hooks=None)
# Remove some weird error message
for d in a.datas:
if 'pyconfig' in d[0]:
a.datas.remove(d)
break
pyz = PYZ(a.pure)
exe = EXE(pyz,
Tree('resource', prefix='resource', excludes=[]),
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
name='MyApplication.exe',
debug=False,
strip=None,
upx=True,
console=False,
icon="resource/image/MyApplication.ico")
This will bundle everything (resources as well) into a single executable. However, you'll need to use sys._MEIPATH to access those resources. I use this code to detect automatically which path to use:
def resource_path(relative):
if hasattr(sys, "_MEIPASS"):
return os.path.join(sys._MEIPASS, relative)
return relative
I suggest using cx_Freeze, it’s relatively easy to use and supports both windows and OS X

Categories

Resources