Pyinstaller : --noconsole gives error and doesn't work - python

I have been trying different solutions from all over the internet and still haven't found a solution that works for me yet.
this is the pyinstaller command i use
pyinstaller --hidden-import "numpy.core._dtype_ctypes" --hidden-import "canmatrix.formats" --hidden-import "canmatrix.formats.dbc" --hidden-import "canmatrix.formats.arxml" --hidden-import "asammdf.blocks.cutils" --additional-hooks-dir=hooks --onefile --noconsole myscript.py
my python script uses few cmd commands as well but redirecting the output doesn't work
my code --
import eel
from pathlib import Path
from asammdf import MDF
from pathlib import Path
import glob
import sys
import os
from datetime import timedelta
import subprocess
eel.init("D:\SharedFolder\suprava\VS code\Python")
#eel.expose
def pythoncode():
#python code ----
#few cmd commands but redirecting the std
output doesnt work
eel.start("main.html")
The .exe seems to work well without the --noconsole option but i dont wish to show the code's std output in the terminal.
i tried editing the service.py file as well, as suggested by other solutions on the internet, but that doesn't seem to work as well.
Is there a way to hide the terminal after the .exe file has been created?

When you use --noconsole mode it sets your sys.stdout and sys.stderr to None automatically, so if your code or the libraries it uses logs or writes messages to either of those streams it will cause an error. Usually something like NoneType object has no attribute write. If this is the error you are receiving then all you need to do is redirect sys.stdout and sys.stderr to a new stream like an open file or an io buffer. For Example:
import io
import sys
stream = io.StringIO()
sys.stdout = stream
sys.stderr = stream
Just have your script run that code as early in your script as possible.

Related

Pyinstaller -w exe still opening terminals in Windows

I ran this command to convert my script from .py to .exe:
pyinstaller.exe -w -i .\icon.png --add-data='icon.png;.' .\gui_script.py
and after adding in some poorly added packages the GUI opens via my tkinter script. But when I run code using the tkinter window in Windows, every time there's a subprocess.run or os.system function it opens up a new terminal window. Is there any way to suppress these? Or at least make them minimized or not noticeable?
Here's a piece of the gui_script.py that combines two files which opens an external terminal window.
import os
os.system('copy cDNA.fa+ncRNA.fa transcriptome.fa /b')
I started using python tools for the merging of files:
with open('transcriptome.fa','wb') as transcriptome_file:
for fasta_file in ['cDNA.fa','ncRNA.fa']:
with open(fasta_file,'rb') as current_fasta:
shutil.copyfileobj(current_fasta, transcriptome_file)
as well as downloading of larger files:
with requests.get('http://ftp.ensembl.org/pub/current_fasta/'+species+'/cdna/'+cDNA_file_name, stream=True) as cDNA_request:
with open('cDNA.fa.gz', 'wb') as cDNA_gz_file:
shutil.copyfileobj(cDNA_request.raw, cDNA_gz_file)
Despite this I still need to run an external program, blast, so there I used subprocess.run with the creationflag = subprocess.CREATE_NO_WINDOW argument like this:
if os.name == 'nt':
blast_db_run = subprocess.run(['makeblastdb',
'-in', fasta_file,
'-dbtype', 'nucl',
'-out','blast_db'],
capture_output=True,
creationflags = subprocess.CREATE_NO_WINDOW)
Used the if statement since creationflags doesn't work in a non-windows environment apparently.

Blessed / Curses controls don't work with Pyinstaller. Missing vtwin10

I have a very simple Python program that uses 'Blessed'. It works fine with the Win10 Python interpreter, but reports an error when packaged with Pyinstaller, and terminal control codes are ignored. Here's the code:
from blessed import Terminal
t = Terminal()
print(t.bright_green('Hello world'))
The string 'Hello world' is supposed to display on the console in bright green. Pyinstaller completes with no errors, and when I run the .exe, I get the message:
terminal.py:222: UserWarning: Failed to setupterm(kind='vtwin10'): Could not find terminal vtwin10
and then 'Hello world' is displayed in default terminal color.
It looks like Pyinstaller isn't including something in the build that the interpreter finds without issue. I found a vtwin10.py file in my Anaconda3 installation folder at:
C:\Anaconda3\Lib\site-packages\jinxed\terminfo
I looked at the referenced error in the blessed library's terminal.py file. Here's the code:
try:
curses.setupterm(self._kind, self._init_descriptor)
except curses.error as err:
warnings.warn('Failed to setupterm(kind={0!r}): {1}'
.format(self._kind, err))
So it looks like self._kind is being set to 'vtwin10'. There is a conditional import in terminal.py that looks like this:
if platform.system() == 'Windows':
import jinxed as curses # pylint: disable=import-error
HAS_TTY = True
(I get the humor.) It looks like the jinxed package is being imported explicitly in the code, and replaces the curses package. But somehow the vtwin10 definition is missing.
I found setupterm() in jinxed and dug deeper to find where that error message is coming from. It's in this code:
try:
self.terminfo = importlib.import_module('jinxed.terminfo.%s' % term.replace('-', '_'))
except ImportError:
raise error('Could not find terminal %s' % term)
This is where I get stuck. It looks like this code is unable to find the vtwin10.py file in the jinxed library. Does anyone know how to force Pyinstaller to include the vtwin10 terminal definition for curses? I'm guessing this is the problem.
Many thanks.
For now you will only need to specify jinxed.terminfo.vtwin10 and jinxed.terminfo.ansicon on Windows, but if you want it to be more dynamic, pyinstaller spec files are executable Python, so you can just dynamically look up any terminfo modules.
import pkgutil
import jinxed.terminfo
hiddenimports = [mod.name for mod in pkgutil.iter_modules(jinxed.terminfo.__path__, 'jinxed.terminfo.')
Finally figured this out. In the jinxed library, the code line:
importlib.import_module('jinxed.terminfo.%s' % term.replace('-', '_'))
dynamically loads a library module. Pyinstaller can't package dynamically imported modules. So to fix this, I need to specify the module using the --hidden-import option. The syntax is as follows:
pyinstaller --hidden-import=jinxed.terminfo.vtwin10 --onefile test.py
Program works just like in the interpreter. It works, but I'm concerned this breaks any platform independence jinxed was supposed to have. I can force import the vtwin10.py module, and it will work on win10 platforms. But the way jinxed is written, it figures out the windows platform and then dynamically loads the required terminfo module. There are a number of them in the jinxed.terminfo directory. Wildcards for --hidden-import don't work, so the only option is to use --hidden-import for every file in the jinxed.terminfo folder.

Python3 executes terminal differently than manual input

I have a small piece of python3 code. Which runs a command from the terminal.
import os
os.system('"C:/directory/program.exe" -k "C:/directory/options.txt" & pause')
When I run this code in IDLE, I get the following error:
The filename, directory name, or volume label syntax is incorrect.
Both of the paths are valid. So thats not the problem. In addition, running:
"C:/directory/program.exe" -k "C:/directory/options.txt" & pause
from the terminal works correctly.
You don't need quotes around the system paths, this should work:
import os
os.system("C:/directory/program.exe -k C:/directory/options.txt & pause")
Hopefully that helps.
[Edit] Working with spaces like you're doing it with os.system is to my knowledge impossible, referring to this python bug tracker thread
A solution might be using the subprocess module insead.
import subprocess
subprocess.call(["C:/direc tory/program.exe", "-k", "C:/direc tory/program.exe"])

Can I open an application from a script during runtime?

I was wondering if i could open any kind of application in Python during runtime?
Assuming that you are using Windows you would use one of the following commands like this.
subprocess.call
import subprocess
subprocess.call('C:\\myprogram.exe')
os.startfile
import os
os.startfile('C:\\myprogram.exe')
Using system you can also take advantage of open function (especially if you are using mac os/unix environment. Can be useful when you are facing permission issue.
import os
path = "/Applications/Safari.app"
os.system(f"open {path}")
Try having a look at subprocess.call http://docs.python.org/2/library/subprocess.html#using-the-subprocess-module
Use the this code : -
import subprocess
subprocess.call('drive:\\programe.exe')
Try this :
import os
import subprocess
command = r"C:\Users\Name\Desktop\file_name.exe"
os.system(command)
#subprocess.Popen(command)
Of course you can. Just import import subprocess and invoke subprocess.call('applicaitonName').
For example you want to open VS Code in Ubuntu:
import subprocess
cmd='code';
subprocess.call(cmd)
This line can be also used to open application, if you need to have more information, e.g. as I want to capture error so I used stderr
subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
Some extra examples for Windows, Linux and MacOS:
import subprocess
# Generic: open explicitly via executable path
subprocess.call(('/usr/bin/vim', '/etc/hosts'))
subprocess.call(('/System/Applications/TextEdit.app/Contents/MacOS/TextEdit', '/etc/hosts'))
# Linux: open with default app registered for file
subprocess.call(('xdg-open', '/tmp/myfile.html'))
# Windows: open with whatever app is registered for the given extension
subprocess.call(('start', '/tmp/myfile.html'))
# Mac: open with whatever app is registered for the given extension
subprocess.call(('open', '/tmp/myfile.html'))
# Mac: open via MacOS app name
subprocess.call(('open', '-a', 'TextEdit', '/etc/hosts'))
# Mac: open via MacOS app bundle name
subprocess.call(('open', '-b', 'com.apple.TextEdit', '/etc/hosts'))
If you need to open specifically HTML pages or URLs, then there is the webbrowser module:
import webbrowser
webbrowser.open('file:///tmp/myfile.html')
webbrowser.open('https://yahoo.com')
# force a specific browser
webbrowser.get('firefox').open_new_tab('file:///tmp/myfile.html')

Twisted application without twistd

I've wrote a nice app for myself using the Twisted framework. I launch it using a command like:
twistd -y myapp.py --pidfile=/var/run/myapp.pid --logfile=/var/run/myapp.log
It works great =)
To launch my app I wrote a script with this command because I'm lazy^^
But since I launch my app with the same twistd option, and I tink the script shell solution is ugly, how I can do the same but inside my app? I'd like to launch my app by just doing ./myapp and without a shell work around.
I've tried to search about it in twisted documentation and by reading twisted source but I don't understand it since it's my first app in Python (wonderful language btw!)
Thanks in advance for anyhelp.
You need to import the twistd script as a module from Twisted and invoke it. The simplest solution for this, using your existing command-line, would be to import the sys module to replace the argv command line to look like how you want twistd to run, and then run it.
Here's a simple example script that will take your existing command-line and run it with a Python script instead of a shell script:
#!/usr/bin/python
from twisted.scripts.twistd import run
from sys import argv
argv[1:] = [
'-y', 'myapp.py',
'--pidfile', '/var/run/myapp.pid',
'--logfile', '/var/run/myapp.log'
]
run()
If you want to bundle this up nicely into a package rather than hard-coding paths, you can determine the path to myapp.py by looking at the special __file__ variable set by Python in each module. Adding this to the example looks like so:
#!/usr/bin/python
from twisted.scripts.twistd import run
from my.application import some_module
from os.path import join, dirname
from sys import argv
argv[1:] = [
'-y', join(dirname(some_module.__file__), "myapp.py"),
'--pidfile', '/var/run/myapp.pid',
'--logfile', '/var/run/myapp.log'
]
run()
and you could obviously do similar things to compute appropriate pidfile and logfile paths.
A more comprehensive solution is to write a plugin for twistd. The axiomatic command-line program from the Axiom object-database project serves as a tested, production-worthy example of how to do similar command-line manipulation of twistd to what is described above, but with more comprehensive handling of command-line options, different non-twistd-running utility functionality, and so on.
You can also create the options / config for a twisted command and pass it to the twisted runner.
#!/usr/bin/env python3
import twisted.scripts.twistd
import twisted.scripts._twistd_unix
config = twisted.scripts._twistd_unix.ServerOptions()
config.parseOptions([
"--nodaemon",
"web",
"--listen=tcp:80",
"--path=/some/path"
])
twisted.scripts._twistd_unix.UnixApplicationRunner(config).run()

Categories

Resources