How do you get pyinstaller to bundle .jar files as archives for a python project that utilizes them?
For instance, to make an exe with (I am using pyjnius for handling the sikuli-standalone jar):
# test.py
import os
import sys
# set the classpath so java can find the code I want to work with
sikuli_jar = '/sikuli-api.standalone-1.0.3-Pre-1.jar'
jarpath = os.path.dirname(os.path.realpath(__file__)) + sikuli_jar
os.environ['CLASSPATH'] = jarpath
# now load a java class
from jnius import autoclass
API = autoclass('org.sikuli.api.API')
Pyisntaller creates the (one folder) exe with:
pyinstaller -d test.py
But the jar to the best of my knowledge is not bundled and is inaccessible to the exe unless you manually place it in the folder generated by Pyinstaller
According to the Pyinstaller manual:
"CArchive contains whatever you want to stuff into it. It's very much
like a .zip file."
I then try editing the previously auto-generated test.spec file with:
jar = 'sikuli-api.standalone-1.0.3-Pre-1.jar'
jar_path = 'C:\\Python27\\Lib\\site-packages\\sikuli-0.1-py2.7.egg\\sikuli\\' + jar
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
[('sikulijar', jar_path, 'PKG')],
strip=None,
upx=True,
name='test')
And I try building the exe based on this spec file with:
python C:\workspace\code\PyInstaller-2.1\PyInstaller\build.py --onefile test.spec
But nothing happens and no error returns. Can someone provide a simple step by step tutorial how this could be done? Many thanks!
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
[('sikulijar', jar_path, 'PKG')],
strip=None,
upx=True,
name='test')
change 'sikulijar' in the tuple to just jar (the variable that you have already defined). you need to reference the same name that you have used in code.
However, I'm still trying to get the JVM to initialize properly. I'll post that if I figure that out.
With a valid virtual environment installed, here's how I've packaged a jar interoperating with python via jnius:
addFiles=" \
--add-data project/resources/jnius.so:jnius \
--add-data relative-path-to-jar.jar:resources \ # <-- example jar
--add-data any-other-resources:resources \
"
source ./venv/bin/activate
./venv/bin/pip install -r ./requirements.txt
./venv/bin/pyinstaller --onefile ${addFiles} project/mainModule.py --log-level WARN --hidden-import=jnius_config
Related
What I want: Turn a python file to executable file with all modules and start script.
Problem: Executable file gives no module named signalrcore when execute.
I already have module named 'signalrcore' but when I convert my python script to executable file with pyinstaller it wont work. The error is no module named signalrcore . It only appears with executable file. The python script is work fine. Script work with python2 python myscript.py -> work without any error. But python3 myscript.py -> have same error with executable file.
My python code:
from signalrcore.hub_connection_builder import HubConnectionBuilder
print('TEST')
My .spec file :
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(['service.py'],
pathex=['/home/pi/Desktop/agent'],
binaries=[],
datas=[],
hiddenimports=['signalrcore','signalrcore.hub_connection_builder'] ,
hookspath=['/usr/lib/python2.7/dist-packages'],
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='service',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=False)
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
name='service')
This errors pops while compile python code to executable ( sudo pyinstaller service.spec)
56429 INFO: Analyzing hidden import 'signalrcore'
56433 ERROR: Hidden import 'signalrcore' not found
56434 INFO: Analyzing hidden import 'signalrcore.hub_connection_builder'
56438 ERROR: Hidden import 'signalrcore.hub_connection_builder' not found
The problem seems to be, that you installed signalrcore only for the current user, but not for root.
Is there any reason, that you run pyinstaller as root?
This should not be necessary.
Call following command without sudo and look at the output.
python -c "import signalrcore ; print(signalrcore.__file__)"
It will show you where the signalrcore module is installed I assume, that this is a local path.
What is normally best is to use python virtualenv to have specific python setups for specific tasks. these virtualenvs can be shared amongst users as long as it is always one user (the one who created the virtualenv) who performs the pip installs and as long as the other is only using the virtualenv.
I suggest you try to read about virtualenvs. ( https://virtualenv.pypa.io/en/latest/ )
Very quick introduction
# install virtualenv
python -m pip install --user virtualenv
# create a virtualenv
python -m virtualenv /path/to/virtualenv # e.g /home/pi/virtualenv4service
# activate virtualenv
source /path/to/virtualenv/bin/activate
pip install signalrcore
pip install pyinstaller
pip install any_other_module_you_need
Then call pyinstaller with
pyinstaller service.spec
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.
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.
I am using pyinstaller to convert python script into a binary in Ubuntu (14.04). I use Canopy (Enthought) to manage all python libraries.
The code uses networkx, numpy, and scipy. Here is my spec file:
# -*- mode: python -*-
a = Analysis(['main_test.py'],
pathex=['/home/sean/Desktop/prog',],
hiddenimports=[],
hookspath=None,
runtime_hooks=None)
pyz = PYZ(a.pure)
exe = EXE(pyz,
a.scripts,
exclude_binaries=True,
name='main_test',
debug=False,
strip=None,
upx=True,
console=True )
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=None,
upx=True,
name='main_test')
At first I got the error:
ImportError: libmkl_gf.so: cannot open shared object file:
No such file or directory
Then I found the .so library in
/home/sean/Canopy/appdata/canopy-1.3.0.1715.rh5-x86/lib
I manually copied several .so files into the dist direcotry.
However, I got another error:
File "/home/sean/Enthought/Canopy_32bit/User/lib/python2.7/site-
packages/PyInstaller/loader/pyi_importers.py", line 409, in load_module
module = imp.load_module(fullname, fp, filename, self._c_ext_tuple)
File "_ufuncs.pyx", line 1, in init scipy.special._ufuncs
(scipy/special/_ufuncs.c:21824)
ImportError: No module named _ufuncs_cxx
How do I fix this error? And how should I modify the spec file to add those libraries and modules?
Edit:
I found the solutuion. My question is now: How can I modify the spec file to add the .so libraies? Now I have to mannually copy a number of .so files to the dist directory...
Edit2
It turns out that I have to add it to COLLECT:
a.binaries + ["libmkl_gf.so" ,
"/home/sean/Canopy/appdata/canopy-1.3.0.1715.rh5-x86/lib/libmkl_gf.so",
"binaries"]
Is there any easy way to find the hidden imports or libraries?
Thanks
I just came out from solving the problem. I had to specify the missing modules with the --hidden-import flag. There were a lot of them missing, but I noticed most of them were from scipy.integrate. So I specified:
pyinstaller --hidden-import=scipy.integrate --hidden-import=scipy.integrate.quadpack --hidden-import=scipy.integrate._vode bla bla bla bla -F --windowed myscript.py
Painful, but worked
Do you want to try adding the library paths into LD_LIBRARY_PATH?
something like,
export LD_LIBRARY_PATH=/home/sean/Canopy/appdata/canopy-1.3.0.1715.rh5-x86/lib
or
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/sean/Canopy/appdata/canopy-1.3.0.1715.rh5-x86/lib (if already set up by admin)
so that at run time all the .so in that folder won't give you linking error...
Oh I got what you mean,
import sys
sys.path.append('your_lib_path')
This should work.
I've wrote GTK application with python.
All graphical user interface is in glade file, and there are some images used. I wish to compile my application into EXEcutable file. For that I'm using PyInstaller compiler and UPX packer.
I've done as manual says:
python Configure.py
python Makespec.py --onefile --windowed --upx /path/to/yourscript.py
python Build.py /path/to/yourscript.spec
PyInstaller works perfectly and create one exe file. But to make my application work correctly i have to copy my glade and image files into exe's folder.
Is there any way to compile those files into executable?
I've edited my spec file in various ways but i can not achieve what i want. Spec file below only copies file to directory, but does not compile into executable file
# -*- mode: python -*-
a = Analysis([os.path.join(HOMEPATH,'support\\_mountzlib.py'), os.path.join(HOMEPATH,'support\\useUnicode.py'), 'r:\\connection\\main.py'],
pathex=['C:\\Documents and Settings\\Lixas\\Desktop\\pyinstaller-1.5-rc1'])
pyz = PYZ(a.pure)
exe = EXE( pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
name=os.path.join('dist', 'NetworkChecker.exe'),
debug=False,
strip=False,
upx=True,
console=False,
icon='r:\\connection\\ikona.ico' )
coll = COLLECT(
exe,
[('gui.glade', 'r:\\connection\\gui.glade', 'DATA')],
[('question16.png', 'r:\\connection\\question16.png', 'DATA')],
# a.binaries,
# strip=False,
upx=True,
name='distFinal')
I wish to have only one executable file with everything included into
PyInstaller does allow you to bundle all your resources into the exe, without the trickyness of turning your data files into .py files -- your COLLECT object seems to be correct, the tricky step is accessing these files at runtime. PyInstaller will unpack them into a temporary directory and tell you where they are with the _MEIPASS2 variable. To get the file paths in both development and packed mode, I use this:
def resource_path(relative):
return os.path.join(
os.environ.get(
"_MEIPASS2",
os.path.abspath(".")
),
relative
)
# in development
>>> resource_path("gui.glade")
"/home/shish/src/my_app/gui.glade"
# in deployment
>>> resource_path("gui.glade")
"/tmp/_MEI34121/gui.glade"
With a few changes, you can incorporate everything into your source code and thus into your executable file.
If you run gdk-pixbuf-csource on your image files, you can convert them into strings, which you can then load using gtk.gdk.pixbuf_new_from_inline().
You can also include your Glade file as a string in the program and then load it using gtk.Builder.add_from_string().
Is there any way to compile those files into executable?
Strictly speaking: no, because you compile source code, while the glade file is XML and the images are binary data. What you would normally do is to create an installer (i.e. a self-unpacking archive that will place different files in the correct directories when the installer is ran).
EDIT: If your concern is simply to have a one-file executable (so it's not about "compiling" but really about the number of files that are permanently written on the filesystem) you could try to use this script based on py2exe. What it does, is to create temporary files each time the program is ran, removing them when execution is completed.
EDIT2: Apparently what you are asking for is also possible under PyInstaller. From the documentation:
By default, pyinstaller.py creates a distribution directory containing the main executable and the dynamic libraries. The option --onefile specifies that you want PyInstaller to build a single file with everything inside.