Pack pytest with pytest_html module using pyinstaller - python

I am having an issue to pack pytest with pytest_html module to an executable using pyinstaller
On Windows.
When running it with Python it does work, but I need to pack it as exe.
My example code:
import pytest
import pytest_html
def test_hello():
assert True
pytest.main(["-p", "pytest_html","-vvv", "--capture=tee-sys","--html=report.html", __file__])
Also Tied with
pytest.main(["-vvv","--html=report.html", __file__], plugins=[pytest_timeout])
The Pyinstaller command I am running is:
pyinstaller --noconfirm --onefile --nowindow --exclude-module PyQt5 --log-level DEBUG -n py_exe file.py
Also tried adding it as a hidden module with no luck.
The result I am getting is:
error: unrecognized arguments: --html=report.html
Looking at Analysis-00.toc, I can see the module :
('pytest_html', 'c:\\users\\nathan\\appdata\\local\\programs\\python\\python38-32\\lib\\site-packages\\pytest_html\\__init__.py', 'PYMODULE')
Versions: Windows 10,
Python 3.8.3,
pytest 5.4.3,
pytest-html 2.1.1,
pyinstaller 3.6
EDIT:
Issue was fixed, see https://github.com/pyinstaller/pyinstaller/issues/5016

Related

pyinstaller with customtkinter: exception when running exe --> AttributeError: module 'customtkinter' has no attribute 'CTk'

I have created a Python script, which uses customtkinter for a GUI where the user can select some options.
Here is an overview about the imported packages:
used libraries
Everything works properly when I run the script in Pycharm (Community Edition 2021.1.2) and the GUI shows up as expected.
But after building (creating an exe from the script) using pyinstaller and running the exe I get following error message:
Error when running exe file
Line 403 makes a problem acc. to this message - the corresponding line in the script looks like:
Line 403 causes error
For building the exe I use following command:
pyinstaller --noconfirm --onedir --windowed --add-data c:\users\myName\appdata\local\programs\python\python39\lib\site-packages\customtkinter;customtkinter\ DataAnalysisTool.py
Hope somebody can help!
I would expect that the exe file also runs as the script in Pycharm runs without any problem.
Update: minimum reproducible example (throws same error message when running exe)
import customtkinter
# create the root window
root_file = customtkinter.CTk()
root_file.title('Data Analysis Tool - File Selection')
root_file.resizable(False, False)
root_file.geometry('350x150')
root_file.mainloop()
I was able to compile your example code with the following steps:
Create a new virtual environment and install customtkinter and pyinstaller
create a main.py file with your example code.
import customtkinter
# create the root window
root_file = customtkinter.CTk()
root_file.title('Data Analysis Tool - File Selection')
root_file.resizable(False, False)
root_file.geometry('350x150')
root_file.mainloop()
run pyinstaller -F main.py --collect-all customtkinter
The compiled executable runs without error.
It works using the --onedir option as well.

Problems with Pynput and Pyinstaller on Ubuntu 20.04LTS GUI

I have a python script that uses the Pynput module. When I run the python script from terminal on Ubuntu [20.04LTS GUI] it runs perfectly.
$ pyinstaller --onefile vTwo.py
cd ./dist
./vTwo
Error occurs when running ./script:
ImportError: this platform is not supported: No module named 'pynput.keyboard._xorg'
Try one of the following resolutions:
* Please make sure that you have an X server running, and that the DISPLAY environment variable is set correctly
[5628] Failed to execute script vTwo
If someone could advise me on what may be going wrong. I have had a look at the Pynput requirements page where they mention that it requires X server to be running in the background which should not be an issue as I have a GUI installed.
Also is there anyway to use Pynput on a system without a gui?
The Solution
The solution is easy. Just include this module as a hidden import in the PyInstaller program:
python -m PyInstaller your_program.py --onefile --hidden-import=pynput.keyboard._xorg
If you also use the mouse with pynput, then you'll get the same error with the module pynput.mouse._xorg. So do this:
python -m PyInstaller your_program.py --onefile --hidden-import=pynput.keyboard._xorg --hidden-import=pynput.mouse._xorg
Warning! You'll likely get a different module that it doesn't find, if you're packaging for Windows or Mac. This is what you get for Linux. If you want your program to be cross-platform, then you'll have to package the program, for example, for Windows and test it to see which module it doesn't find and include it as a hidden import.
For example, if you want your program to work on Linux and Windows, use this command:
python -m PyInstaller your_program.py --onefile --hidden-import=pynput.keyboard._xorg --hidden-import=pynput.mouse._xorg --hidden-import=pynput.keyboard._win32 --hidden-import=pynput.mouse._win32
If you have a lot of hidden modules, then you may edit the .spec file and add the modules to the hiddenimports list like so (on PyInstaller 4.1):
hiddenimports=['pynput.keyboard._xorg', 'pynput.mouse._xorg'],
Why The Error
When you see an ImportError in a Python program packaged by PyInstaller, there is a high chance that the problem is that PyInstaller couldn't detect that specific import and didn't include it in the binary, hence the import error.
In the error message it tells you which module it didn't find:
ImportError: this platform is not supported: No module named 'pynput.keyboard._xorg'
which is pynput.keyboard._xorg, because you're on Linux.
It couldn't find the module, because it was imported in a "non-traditional" way. Look at the source code for pynput/_util/__init__.py in the backend function:
def backend(package):
backend_name = os.environ.get(
'PYNPUT_BACKEND_{}'.format(package.rsplit('.')[-1].upper()),
os.environ.get('PYNPUT_BACKEND', None))
if backend_name:
modules = [backend_name]
elif sys.platform == 'darwin':
modules = ['darwin']
elif sys.platform == 'win32':
modules = ['win32']
else:
modules = ['xorg']
errors = []
resolutions = []
for module in modules:
try:
return importlib.import_module('._' + module, package)
except ImportError as e:
errors.append(e)
if module in RESOLUTIONS:
resolutions.append(RESOLUTIONS[module])
raise ImportError('this platform is not supported: {}'.format(
'; '.join(str(e) for e in errors)) + ('\n\n'
'Try one of the following resolutions:\n\n'
+ '\n\n'.join(
' * {}'.format(s)
for s in resolutions))
if resolutions else '')
You can see that it uses the import_module function from the importlib module to import the correct module for the platform. This is why it couldn't find the
pynput.keyboard._xorg module.
Your Second Question
Also is there anyway to use Pynput on a system without a gui?
I don't know.

failed to create executable with pyinstaller and cefpython on Linux (Invalid file descriptor to ICU data)

I have some simple cefpython code opening a url and am trying to create a stand alone executable with pyinstaller:
I copied files from https://github.com/cztomczak/cefpython/tree/master/examples/pyinstaller to a a directry named pyinstaller
I made following minor changes to pyinstaller.spec
+SECRET_CIPHER = ""
...
- ["../wxpython.py"],
+ ["../hello.py"],
...
- icon="../resources/wxpython.ico")
+ )
I can successfully compile my application on windows with python
On the same machine with python 3.5.4 64 bit and following virtualenv:
cefpython3==66.0
future==0.18.2
PyInstaller==3.2.1
pypiwin32==223
pywin32==228
I can also compile windows with python 3.6.4 64 and following virtualenv:
altgraph==0.17
cefpython3==66.0
future==0.18.2
macholib==1.14
pefile==2019.4.18
PyInstaller==3.3.1
pyinstaller-hooks-contrib==2020.9
pypiwin32==223
pywin32==228
pywin32-ctypes==0.2.0
On Linux compilation works as well, but the executable is not operational.
I get following output and error:
CEF Python 66.0
Chromium 66.0.3359.181
CEF 3.3359.1774.gd49d25f
Python 3.5.2 64bit
[1013/180954.001980:ERROR:icu_util.cc(133)] Invalid file descriptor to ICU data received.
Trace/breakpoint trap (core dumped)
version is python 3.5.2 64bit and the virtualenv is:
cefpython3==66.0
pkg-resources==0.0.0
PyInstaller==3.2.1
What could be the cause?
The code, that I try to compile is below:
import platform
import sys
from cefpython3 import cefpython as cef
def check_versions():
ver = cef.GetVersion()
print("CEF Python {ver}".format(ver=ver["version"]))
print("Chromium {ver}".format(ver=ver["chrome_version"]))
print("CEF {ver}".format(ver=ver["cef_version"]))
print("Python {ver} {arch}".format(
ver=platform.python_version(),
arch=platform.architecture()[0]))
assert cef.__version__ >= "57.0", "CEF Python v57.0+ required to run this"
def main(url="https://www.stackoverflow.com"):
sys.excepthook = cef.ExceptHook
check_versions()
settings = {}
switches = {}
browser_settings = {}
cef.Initialize(settings=settings, switches=switches)
cef.CreateBrowserSync(
url=url,
window_title="CEF_HELLO: ",
settings=browser_settings,
)
cef.MessageLoop()
cef.Shutdown()
if __name__ == "__main__":
main()
Addendum: 2020-10-14:
same error on linux with other versions:
so far I tried python 3.5 and 3.7
Is there anybody who successfully created an executable?
I could be, that this just an issue with the example project and its configuration?
As alternative, a solution could be found in PyInstaller bug 5400
Here the steps:
1- download the PyInstaller helper in CEFpython named hook-cefpython3.py from:
https://github.com/cztomczak/cefpython/tree/master/examples/pyinstaller and put in the root directory of your project
2- In that file, replace the line:
from PyInstaller.compat import is_win, is_darwin, is_linux, is_py2
with:
from PyInstaller.compat import is_win, is_darwin, is_linux
is_py2 = False
3- in your PyInstaller .spec file, add the '.' to the hookspath, e.g. hookspath=['.']. I think it is also possible to add it as PyInstaller command line option.
These steps should solve the problem, until CEFPython deliver a correct version of the hook file.
This is not really the answer I would like to accept, but it is at least one solution and contains information, that might lead to a better fix, a better answer.
After debugging with strace I found out, that the executable searches many files like for example icudtl.dat, v8_context_snapshot.bin, locales/* were searched in
'dist/cefapp/cefpython3but were copied todist/cefapp/`
An ugly work around is to do following after compilation
cd dist/cefapp/cefpython3
ln -s ../* .
and the executable works.
I'm sure there is also a nicer non-brute-force solution, but for the time being I wanted to answer in case others are stuck as well
Probably this can be fixed in the spec file but would we need one spec file for linux and one for windows then?
Perhaps there's also an option to tell the excutable to search for these files one level higer?
To solve this, you need to set this in your spec file:
hookspath=[r'YOUR_ENV_SITE_PACKAGES\cefpython3\examples\pyinstaller\']
And then rebuild, you will have things in the right place.
The following steps solved the issue for me on Windows 10, Python 3.9.5 32-bit, PyInstaller 4.3, and CEFPython 66.1:
Download the hook-cefpython3.py file from here and put it into your project root directory.
Run the pyinstaller command as usual but add the --additional-hooks-dir . command line option, so the command will look like this:
pyinstaller --additional-hooks-dir . <main-file.py>
As opposed to other answers here, this anser neither requires changes of hookspath directive in pyinstaller's spec file and, as of now, nor any changes to the downloaded hook-cefpython3.py file.

Make executable a PyQt5 project

I've tried to make a PyQt5 project an executable file.
I used a PyInstaller module, and I got a half success.
pyinstaller --clean -w -F --specpath=spec -n=project_name -i="..\resource\logo.ico" src\main.py
The executable file generated by this command did not run successfully.
The error message was like this.
pyinstaller --clean -c -F --specpath=spec -n=project_name -i="..\resource\logo.ico" src\main.py
The executable file generated by this command ran successfully.
But it has a terminal even though it is a GUI project.
The difference is just -c and -w. But one can be executed and can not one.
How should I do it?
The problem was subprocess.Popen with Python v3.7.5.
I didn't set the stdin. I set only stdout, stderr.
After I set the stdin=subprocess.PIPE, it works well.
And I want to add 1 more thing.
I've imported the win32api module with Python v3.8.0. This raises issues.
So, I've added the module pywintypes, and now the issue is resolved.
Before
import win32api
After
import pywintypes
import win32api

ModuleNotFoundError: py3k for PyInstaller + savReaderWriter

I want to use PyInstaller with module savReaderWriter. My code is very simple:
import savReaderWriter
print("hello world")
input("Press enter, to finish...")
I was trying to use hidden import with appropriate module:
pyinstaller --clean --win-private-assemblies --upx-exclude=vcruntime140.dll --onedir --hidden-import="savReaderWriter" temp.py
pyinstaller --clean --win-private-assemblies --upx-exclude=vcruntime140.dll --onedir --hidden-import="py3k" temp.py
pyinstaller --clean --win-private-assemblies --upx-exclude=vcruntime140.dll --onedir --hidden-import="py3k" --hidden-import="savReaderWriter" temp.py
But in all cases I have received the same error:
ModuleNotFoundError: No module named 'py3k'
I solved the issue by including the path of the savReaderWriter to the parameter.
pyinstaller -p "C:\PyProjects\test\venv\Lib\site-packages\savReaderWriter"; test.py
Also, the real pain is when you trying to delete the module, an Error will occur because it is finding a non "UTF-8" character.

Categories