Problems with Pynput and Pyinstaller on Ubuntu 20.04LTS GUI - python

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.

Related

Make an executable file from python project

I want to make a .exe file from my python project, I have made a GUI in tkinter. This project has multiple files and uses a variety of libraries.
I tried to use auto-py-to-exe but it gave a variety of errors concerning the use of tkinter, saying it can not find tkinter. I do not understand this error since tkinter is automatically installed with python? Are there better ways to use auto-py-to-exe or better programs to convert a hole project to .exe? I also tried pyinstaller, but when opening the program it immediately closes again. The program does run properly in pycharm.
The error is I\output\main_init_.py", line 1, in <module> import tkinter ModuleNotFoundError: No module named 'tkinter'
I personally use CX-Freeze to compile my executables. I have probably used it over 100 or so updates of my tools and typically the problem I run into is either related to missing file that need to be identified in the setup.py file or the fact that when it compiles the Tkinter folder it uses a capital T instead of a lower case t so after I compiling an app I have to manually update the folder to be lowercase T.
Here is an example of the setup file.
As you can see below when compiling tkinter you need to ID the TK and TCL library folders in order for it to compile the listed DLL files properly.
from cx_Freeze import setup, Executable
import os
base = "Win32GUI"
os.environ['TCL_LIBRARY'] = r'C:\Users\user\Desktop\Python381\tcl\tcl8.6'
os.environ['TK_LIBRARY'] = r'C:\Users\user\Desktop\Python381\tcl\tk8.6'
build_exe_options = {'packages': ['os',
'json',
'http',
'email',
'pyodbc',
'openpyxl',
'calendar',
'threading',
'datetime',
'tkinter',
'tkinter.ttk',
'tkinter.messagebox'],
'excludes': ['PyQt5',
'PIL',
'numpy',
'pandas'], # 'urllib', # 'encodings', # 'numpy'
'include_files': [r'excel_temp.xlsx',
r'opt_3_excel_temp.xlsx',
r'tcoms_excel_temp.xlsx',
r'main_config.json',
r"C:\Users\user\Desktop\Python381\DLLs\tcl86t.dll",
r"C:\Users\user\Desktop\Python381\DLLs\tk86t.dll"]}
setup(
name='<GIT>',
options={'build_exe': build_exe_options},
version='0.57',
description='<GIT - Global Inventory Tool!>',
executables=[Executable(r'C:\Users\user\PycharmProjects\Py381_GIT\MAIN.py', base=base)]
)
After you run the compiler you will often get an error that looks like this.
The error NoduleNotFoundError: No module named 'tkinter' is due to the odd behavior of the compiler giving the tkinter folder a Capital T like the below image in the lib folder.
In this case you would update the library to be a lowercase t.
Use this package :
python -m pip install auto-py-to-exe
Run this command :
auto-py-to-exe

No application is registered as handling this file in bundled Python program

I am using Ubuntu 21.04 with Python 3.8, Matplotlitb 3.4.3, pyinstaller 4.5.1 and I would like python program to open google.com page in default web browser. There is also matplotlib package (the reason why it's not working, without matplotlib everything is fine).
#!/usr/bin/python3
import webbrowser
import matplotlib.pyplot as plt
plt.plot([1, 2, 4, 8, 16])
plt.show()
webbrowser.open("https://www.google.com/")
When I run this program as ./main.py or python3 main.py, everything is ok and Google Chrome is opened. However when I bundle program into executable using pyinstaller:
pyinstaller --onefile main.py
And run this bundled program as ./dist/main, following error appears in terminal:
gio https://www.google.com/: No application is registered as handling this file
When I define BROWSER variable before running file, then it work again:
export BROWSER=$(which google-chrome) && ./dist/main
However, I would like to run program without declaring that variable. Default browser doesn't have to be Chrome and even OS doesn't have to be Linux, but eg. Windows. I found question with similar problem. But when I downgrade matplotlib from 3.4.3 to 3.0.3 is in the link, there is a lot of compatibility errors. So I would like to keep newest matplotlib.
Is there any way fix the gio error?
Seems like the problem is caused by various environment variables being messed up. More info here: https://github.com/pyinstaller/pyinstaller/issues/3668
As a workaround you might be able to use subprocess to open the https URL with its default handler, which should be the default browser:
import os
import platform
import subprocess
env = dict(os.environ)
lp_key = 'LD_LIBRARY_PATH'
lp_orig = env.get(lp_key + '_ORIG')
if lp_orig is not None:
env[lp_key] = lp_orig
else:
lp = env.get(lp_key)
if lp is not None:
env.pop(lp_key)
opener = {'Darwin': 'open', 'Windows': 'start'}.get(platform.system(), 'xdg-open')
subprocess.run((opener, 'https://www.google.com/'), env=env)

pyinstaller exe fails - fusionscript.dll problem

[Thanks to Charles Duffy for the gentle nudging toward a clearer question! I am new to Stack Overflow and appreciate the help. After more research, it appears that the dependent code is actually within Blackmagic's fusionscript.dll code (If the .dll is missing, my exe is able to continue past the line of my code which tries to import) , so I don't see any way to get around it until they update.]
Original question:
I'm stuck trying to get a pyinstaller executable to work on a Windows 10 test system. My exe works fine on a system that has Python 3.6.8 installed.
Complete code is below. The print command that starts with "trying:" succeeds and shows the correct path for the import. The print command immediately after the import command print("Made it past import") is not executed, and the exe quits without showing any errors.
I've determined that there's just one file that is necessary for the exe to run on the test system, and that's the os.py file in the Lib folder of the Python install. Without that file, the exe just quits (without any error message) when it hits the line of code: script_module = imp.load_dynamic("fusionscript", path + "fusionscript" + ext)
For anyone trying to reproduce: the exe runs when a Python 3.6.8 install is present, or more specifically, when os.py is. I made the installer with a simple pyinstaller importTest.py command. I place the fusionscipt.dll in the folder with the resulting executable. If os.py is present, the exe runs normally and prints all of it's print commands. If you remove os.py from the Python Lib directory, this is no longer the case, and the exe quits when it hits the imp command.
NOTE: I know that imp is deprecated, but the API that my code engages with (fusionscript.dll for Resolve) only works with Python 3.6, so I can't use anything newer.
Here's the code:
from PyQt5.QtCore import QObject
import sys
import imp
import os
CURR_DIR = os.getcwd()
sys.path.append(CURR_DIR)
script_module = None
ext = ".dll"
path = CURR_DIR+"\\"
try:
print("trying: " + path + "fusionscript" + ext)
script_module = imp.load_dynamic("fusionscript", path + "fusionscript" + ext)
print("Made it past import")
except ImportError:
pass
print("script module = ",script_module)

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.

Importing PyVISA via Py2exe

My script file test.py is:
try:
from visa import *
except Exception as ex:
print ex
raw_input()
My setup.py file is:
from distutils.core import setup
import py2exe
setup(console=['test.py'])
I then run:
python setup.py py2exe
If I then launch test.exe on my pc I see no issues but if I copy it to a new pc with no prior python installs I get:
[Error 126] The specified module could not be found
I don't know how to get the full traceback to print. Has anyone else seen this issue?
Running Python 2.7, PyVisa 1.4. Both machines are Win7.
Turns out the problem was that the visa libraries that pyvisa relies on weren't installed on the test pc. These libraries don't come included with pyvisa.

Categories