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
Related
I have a working python package that's a CLI tool and I wanted to convert it into a single .exe file to upload it to other package managers so I used Pyinstaller. After building the .exe file with this command:
pyinstaller -c --log-level=DEBUG main.py 2> build.txt --onefile --exclude-module=pytest --add-data "src;src"
I double-clicked the .exe file but it closed immediately but in that split second, I saw the expected output which is supposed to be the command-line interface so the .exe does work but not entirely.
main.py
from src.Categorize_CLI.__main__ import main
if __name__ == "__main__":
main()
.spec file
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(
['main.py'],
pathex=[],
binaries=[],
datas=[('src', 'src')],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=['pytest'],
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='main',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
Update
I got it working by dragging the main.exe file to a open command prompt and then pressed enter and it worked, and I got an error:
RuntimeError: 'package' is not installed. Try passing 'package_name' instead.
[15592] Failed to execute script 'main' due to unhandled exception!
It sounds like the script ran to end of file to fast for you to see. You can confirm this by opening your terminal (cmd/poweshell in windows) and running your program like any other CLI tool.
cd path\to\exe
./exe -arguments
Since you launched it from an allready opened terminal it won't close when the script ends.
If this is the problem you can solve it by adding
input("Continue...") # wait for user
Update
As #BokiX says pyinstaller can cause false positives with anti virus software. Try a diffrent one e.g. nuikta:
pip install Nuikta
python -m nuikta main.py
installing python programs vs tradtitional programs
A tradtitional program installer is usualy a fancy zip file with some additianal feautures to setup a program for the relevant system it's on (e.g. make registry changes, download additianal files).
A python program is just a python script that was "frozen" in state so it can run independently on a system without python or it's dependencies. once you have an exe it should just run without needing to be "installed".
using console programs
A console program is a program that is made to be exicuted from a terminal. In modern use these are usualy so they can be run by a script or someone who finds typing is faster than using a GUI.
Run the code in the cmd and not by clicking the exe
A pyinstaller exe "usually" closes when 1 - Theres an error in the code , 2 - The code execution finished , closes after displaying the output
Also as BokiX stated , pyinstaller exe's often get false flagged as malicious , so maybe add an exception to your anti virus.
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"
I'm trying to bundle a cefpython1 application into a single exe with pyinstaller.
I have a working spec file which creates a distrubiton for the cefpython1 example, cefsimple:
# -*- mode: python -*-
def get_cefpython_path():
import cefpython1 as cefpython
path = os.path.dirname(cefpython.__file__)
return "%s%s" % (path, os.sep)
cefp = get_cefpython_path()
a = Analysis(['cefsimple.py'],
hiddenimports=["json.decoder", "json.scanner", "json.encoder"])
pyz = PYZ(a.pure)
exe = EXE(pyz,
a.scripts,
exclude_binaries=True,
name='cefsimple.exe',
debug=False,
strip=None,
upx=False,
console=False )
coll = COLLECT(exe,
a.binaries + [('icudt.dll', '%s/icudt.dll' % cefp, 'BINARY')],
a.zipfiles,
a.datas + [('locales/en-US.pak', '%s/locales/en-US.pak' % cefp, 'DATA'), ('cefsimple.html', 'cefsimple.html', 'DATA'), ('icon.ico', 'icon.ico', 'DATA')],
strip=None,
upx=False,
name='cefsimple')
The project files can be found on my Google Drive. Don't care about setup.py, it contains a py2exe build which i was playing with next to pyinstaller. You need Python 2.7, Win32gui, cefpython1 and of course pyinstaller packages to run this, I've tested this with the Win32 version only! I've even tried installing the development pyinstaller if it makes any change.
If i try to execute pyinstaller with the --onefile attribute seems like nothing changes, pyinstaller just creates the distribution directory under dist. The command I'm using is: pyinstaller --onefile cefsimple.spec
Tested --onefile with a simple Hello World python file and it does work by that. What's causing pyinstaller to not creating a single exe? The build log doesn't show anything interesting, but there are some things i don't understand in the warning file. For eg. it says there's no module named cefpython1.cefpython but the correct pyd is copied to the dist directory and the application is working anyway.
Here is the list of files created under dist/: cefsimple.lst Maybe this helps finding the problem.
The command I'm using is: pyinstaller --onefile cefsimple.spec
Tested --onefile with a simple Hello World python file and it does
work by that. What's causing pyinstaller to not creating a single exe?
The option --onefile is ignored when you type pyinstaller --onefile cefsimple.spec because the .spec already defines if you will get a directory or a standalone file. A .spec file with a COLLECT function will make a whole dist directory.
I would suggest remaking a new .spec file by typing pyi-makespec --onefile cefsimple.py and adding back your various modifications (data, binaries, hiddenimports...), then trying pyinstaller cefsimple.spec without option. That works for me with pyinstaller 3.3.1.
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
I need to convert a Python script to a Windows executable.
I have Python 2.6 installed to python26.
I have created one script and kept it in C:\pythonscript. Inside this folder there are two files
Setup.py and oldlogs.py (this file need coversion)
setup.py code is
from distutils.core import setup
import py2exe
setup(console=['oldlogs.py'])
How can I convert oldlogs.py to an exe file?
Or use PyInstaller as an alternative to py2exe. Here is a good starting point. PyInstaller also lets you create executables for linux and mac...
Here is how one could fairly easily use PyInstaller to solve the issue at hand:
pyinstaller oldlogs.py
From the tool's documentation:
PyInstaller analyzes myscript.py and:
Writes myscript.spec in the same folder as the script.
Creates a folder build in the same folder as the script if it does not exist.
Writes some log files and working files in the build folder.
Creates a folder dist in the same folder as the script if it does not exist.
Writes the myscript executable folder in the dist folder.
In the dist folder you find the bundled app you distribute to your users.
I recommend PyInstaller, a simple python script can be converted to an exe with the following commands:
utils/Makespec.py [--onefile] oldlogs.py
which creates a yourprogram.spec file which is a configuration for building the final exe. Next command builds the exe from the configuration file:
utils/Build.py oldlogs.spec
More can be found here
Since other SO answers link to this question it's worth noting that there is another option now in PyOxidizer.
It's a rust utility which works in some of the same ways as pyinstaller, however has some additional features detailed here, to summarize the key ones:
Single binary of all packages by default with the ability to do a zero-copy load of modules into memory, vs pyinstaller extracting them to a temporary directory when using onefile mode
Ability to produce a static linked binary
(One other advantage of pyoxidizer is that it does not seem to suffer from the GLIBC_X.XX not found problem that can crop up with pyinstaller if you've created your binary on a system that has a glibc version newer than the target system).
Overall pyinstaller is much simpler to use than PyOxidizer, which often requires some complexity in the configuration file, and it's less Pythony since it's written in Rust and uses a configuration file format not very familiar in the Python world, but PyOxidizer does some more advanced stuff, especially if you are looking to produce single binaries (which is not pyinstaller's default).
# -*- mode: python -*-
block_cipher = None
a = Analysis(['SCRIPT.py'],
pathex=[
'folder path',
'C:\\Windows\\WinSxS\\x86_microsoft-windows-m..namespace-downlevel_31bf3856ad364e35_10.0.17134.1_none_50c6cb8431e7428f',
'C:\\Windows\\WinSxS\\x86_microsoft-windows-m..namespace-downlevel_31bf3856ad364e35_10.0.17134.1_none_c4f50889467f081d'
],
binaries=[(''C:\\Users\\chromedriver.exe'')],
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,
a.binaries,
a.zipfiles,
a.datas,
name='NAME OF YOUR EXE',
debug=False,
strip=False,
upx=True,
runtime_tmpdir=None,
console=True )