[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)
Related
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.
So I have this piece of code here:
import os
import sys
onlyfiles = [f for f in os.listdir(sys.path[0]) if os.path.isfile(os.path.join(sys.path[0], f))]
while True:
print(onlyfiles)
x = input()
if x == "y":
continue
else:
break
I converted the script into a .exe file with pyinstaller. But when I try to run it, I assume it crashed?
Can anyone help me with this?
your exe is crashing due to 'NotADirectory' error being thrown by the program.
As you are on windows, you can see this error.
Navigate to the path where you have created you exe and launch cmd.exe, and then execute your exe by issuing 'filename.exe' .
The 'NotADirectory' error is coming as now exe is frozen and system paths are changed as well, which include 'base_library.zip' . Certainly this is not a directory and hence exception is expected.
Running my GUI application created in PyQt5 using any IDLE or the file.py is running perfectly, however, when I converted the .py to .exe using Pyinstaller
I get an error every time I try to run the .exe file for some reason a small command window pops with an error and immediately disappear I screenshot the error before it closes. Any Idea Thanks in advance
Error image.
I tried to execute different commands for pyinstaller but no luck.
<pyinstaller filename -F >
<pyinstaller filename -onefile >
<pyinstaller filename >
It's an app over 900 lines and I cannot upload all of that but I think according to the error first lines.
The error occurs so here are the lines of code.
The problem is within importing modules I believe.
from PyQt5.QtWidgets import QWidget
from PyQt5 import QtCore, QtGui, QtWidgets
from datetime import datetime
import time
import os, sys #importing system modules
class Ui_MyTrophiesWindow(object):
class save_txt_file(QWidget):
def GetSaveFile(self):
path = QFileDialog.getSaveFileName(self,"Save MyTrophies.txt here", "MyTrophies", "*.txt")
working_path = os.path.abspath(__file__)[0:-13]
file = open(str(working_path) + "Txtpath.dat", "w+")
for i in path:
file.write(str(i))
file.close()
It is very common that sometimes PyInstaller won't recognize all Qt5 dependencies especially QT core DLLs. A simple way is to just locate that file on your current Python path and feed it with add-data flag in PyInstaller. Also, I suggest you not to use upx with PyQt as it may corrupt some DLLs:
pyinstaller --noupx -F --add-data "<Python_path>/Lib/site-packages/PyQt5/Qt/bin/Qt5Core.dll;./PyQt5/Qt/bin" script.py
To verify the answer suppose below example:
import traceback
import os
import sys
def func():
from PyQt5.QtWidgets import QWidget
from PyQt5 import QtCore, QtGui, QtWidgets
try:
if getattr(sys, 'frozen', False):
print(sys._MEIPASS)
func()
print("Import OK!")
except Exception:
traceback.print_exc()
input()
After you run the executable you would see the path for Pyinstaller (something like C:\Users\User\AppData\Local\Temp\_MEI90202), go to this path and search for the Qt5Core.dll and check if it is there.
I had look your error and according to me, I think you need to (re)install Qt5core.dll module and to add it in the site-package/PyQt5/init.py path. You can download the dll file here:
http://www.telecharger-dll.fr/dll-Qt5Core.dll.html
Good evening
Make sure that you have all the items of that app in the correct folder. Let me put an example that happened to me days ago:
I had an app with a folder named "options" that had 3 files (2 icons for my buttons ui and a .ini file). When I created the pyinstaller version of my program I assumed that it would somehow copy those files and pack them inside the --onefile file or into the dist folder (if not --onefile command was used). Nope, it didn't.
After scratching my head for hours, I just copied the options folder from my source files and pasted it next to my --onefile file (or inside the dist folder).
After that, my app works without issues. So... make sure it has all the files it needs in the correct folders.
I make program in python to open some executable file given by path. I use:
os.startfile(path)
to start program. When i run script.py in IDLE it works fine, but when i make .exe file with pyinstaller when i run it that program i want to open starts to open and closes almost immediately. I tried with different functions like subprocess.Popen(path) and it does the same thing, open and close program after 1 second. Can someone help me? Is there a problem in python functions or in pyinstaller or even windows 10?
The problem is that your code most likely just runs and then the window closes.
You can add import time to your imports and time.sleep(x) or something to keep the window open for x seconds after you run
Read all the way through before doing anything!
Ok so try this:
Put this in a python file called start.py:
import os
import subprocess
#py_command - whatever opens python in cmd
#path - must be full path of file you want to call
def StartPythonScript(path, py_command):
command = 'start cmd /k ' + py_command + " " + path
subprocess.run(command, shell=True)
Now, take the code from file you are calling from the exe, let's say its name is run.py, and put it in a different file, say code.py.
Make sure start.py is in the same folder as run.py
In run.py, put this:
import start
cmd = "py" #change this to whatever opens python in cmd
path = "code.py" #change to the full path of code.py
start.StartPythonScript(path, cmd)
So when you click on the exe, it opens run.py which tells start.py to open code.py, which contains your program.
You can actually merge start.py and run.py, but you can reuse start.py if they are seperate.
OR...
Add import os to your program that is called by the exe.
Add os.system("pause") to the end of your program.
I'm not sure if this will work on an infinitely running program...but try this first to save time.
More info:
How to stop Python closing immediately when executed in Microsoft Windows
Good luck!
I want a python line of code that sets the working directory to folder the code is part of. I am using spyder IDE for writing and running python codes.
Side note: This question is very similar to R command for setting working directory to source file location in Rstudio
This is a common problem I run into when developing in Jupyter for the command line.
You can try this to find where your script is executing from:
import os
from pathlib import Path
def myPath():
'''
return the current working directory in both interpeters and when exectued on the commandline
'''
try:
# path of this file when executed
wd = os.path.dirname(os.path.abspath(__file__))
except NameError as e:
print('this script is running in an interpreter')
# if not found
wd = Path().resolve()
return(wd)