I've got a python script that is currently run on a command line (both macOS and windows) with some command lines.
I'm considering moving to use pyinstaller to bundle everything up to make life easier for the users. One interesting feature of pyinstaller is that it has the --windowed option that gives it an icon, and is runnable from the gui.
My question is: if I use this, how do I get data into the argv? Where command line arguments would normally go?
If I create a "config file" and have the users drag and drop that into the app, would the filename become argv[1]?
Related
I'm asking help today because I'm new to Tkinter and Pyinstaller (and python in general) and I'm having troubles with it.
I have a simple app working with sqlite, tkinter and pyinstaller to compile all of this in an executable program, the entrance point of my program is a file named main.py
This file calls all the dependancies (like the sqlite module for python, tkinter and my other files like classes etc...)
I made a very simple interface, with a Hello World in a tkinter label and a button to go to page 2 which displays page2 (also in a label), just to see if I'm capable of making it all run and compile all of these pieces together.
I can run it throught my shell executing it like : python main.py and everything is working fine.
But when I run pyinstaller on my linux machine, and start executing the program, nothing appears, my database.db (sqlite database file) is created but I don't have any interface like when I run it with my shell. The thing is getting even worse on windows where, once I've my .exe it just opens a shell and crash after few seconds, not even creating the database.
What I did is I created a 'log file', in which I write the steps of the program.
As you can see on the following picture, the 2 first prints are wrote in my log file (on linux), so I think it crashes when I try to create the window.
If any of you have an idea on what I do wrong, I would really appreciate help :)
General
From the PyInstaller manual:
Before you attempt to bundle to one file, make sure your app works correctly when bundled to one folder. It is is much easier to diagnose problems in one-folder mode.
As the comments suggested, use a catch-all try/except block to log all exceptions to a file. That is probably the best way to see what is really happening. Make sure that the logfile is created in an existing location where you have the necessary permissions.
I would suggest to take advantage of the built-in logging module instead of creating your own. It can e.g. automatically add from which file a log line was created.
IMHO, it is probable that the failures on Linux and ms-windows have completely different causes. You should probably treat them as different issues.
Linux
When you use single file mode, that file is unpacked into a temporary folder, probably somewhere in /tmp. Some Linux distributions mount the /tmp filesystem with the noexec flag. This is incompatible with PyInstaller.
ms-windows
On windows, there are basically two different Pythons; python.exe and pythonw.exe. Basically it is one of the quirks of windows that this is necessary. The latter is for GUI programs like tkinter programs. A tkinter script should not show a cmd window. So I'm guessing that PyInstaller calls your command with python.exe instead of pythonw.exe. From the manual:
By default the bootloader creates a command-line console (a terminal window in GNU/Linux and Mac OS, a command window in Windows). It gives this window to the Python interpreter for its standard input and output. Your script’s use of print and input() are directed here. Error messages from Python and default logging output also appear in the console window.
An option for Windows and Mac OS is to tell PyInstaller to not provide a console window. The bootloader starts Python with no target for standard output or input. Do this when your script has a graphical interface for user input and can properly report its own diagnostics.
As noted in the CPython tutorial Appendix, for Windows a file extention of .pyw suppresses the console window that normally appears. Likewise, a console window will not be provided when using a myscript.pyw script with PyInstaller.
Also, on windows it can matter which Python distribution you're using. I used to be a fan of Anaconda, but lately I've come to prefer the python.org version because it gives me less headaches. On anaconda Python I had the problem that tkinter programs would not launch without showing a cmd window, whatever I tried. Only switching to python.org Python solved that problem.
I have an .exe I'm packaging using pyinstaller and it works like a charm. However when the .exe is clicked, I have to wait nearly 10 seconds while staring at a blank console window for the actual application to start.
From my research I've surmised that this is because of --onefile, and all the various files packaged in need to be unpacked before any code is run. I'm not concerned about the 10 second wait, but new users often need support because they think the program isn't working (reasonably so).
My ask is incredibly simple, but I can't figure out a way to do it: Is there anyway to get pyinstaller to run a tiny script BEFORE UNPACKING to just post a status blurb to the console, so users know that it's working?
As far as I know it is currently not possible to display custom messages before unpacking to let the user know the application is working. Source
There are a few workarounds to let the user know the program is working.
Display the console window
Displaying the console window after launching the application will output the status of the PyInstaller Bootloader while it is being opened.
To display the console, use the --console flag (or edit the .spec file to contain console = True) when bundling your application
Enable debug mode
To enable debug mode, use the --debug flag (or edit the .spec file to contain debug = True)
Example
exe = EXE(pyz,
//...
debug=True,
console=True )
You could always wrap your program into 7zip installer. You can add a quick shell script to say "Loading..." before running your main program or you could just edit config.txt to do the same.
How do I make a self extract and running installer
I want to make my program executable.
I used TkInter to write the GUI, and I read somewhere that you have to save your file as .pyw to hide the console when the program is executed.
The problem is that after making it an executable with PyInstaller, the console shows up again, even though the file converted was .pyw.
How can I hide the console also in the .exe file?
Did you try --windowed command line flag ?
You can just save the file with .pyw extension and you can just use pyinstaller --onefile Filename.pyw
I think you renamed it. You save it as .pyw don't rename it.
The screenshot are below:
Output:
But it takes a while to open.
Thank you
-Levers
What are you using to make the executable?
If you use py2exe and you use:
setup(windows=[pythonscriptnamehere])
in the setup script instead of:
setup(console=[pythonscriptnamehere])
it will run the executable without launching a terminal in the background.
From The PyInstaller Documentation:
Using a Console Window
By default the bootloader creates a command-line console (a terminal
window in GNU/Linux and Mac OS, a command window in Windows). It gives
this window to the Python interpreter for its standard input and
output. Your script’s use of print and input() are directed here.
Error messages from Python and default logging output also appear in
the console window.
An option for Windows and Mac OS is to tell PyInstaller to not provide
a console window. The bootloader starts Python with no target for
standard output or input. Do this when your script has a graphical
interface for user input and can properly report its own diagnostics.
As noted in the CPython tutorial Appendix, for Windows a file
extention of .pyw suppresses the console window that normally appears.
Likewise, a console window will not be provided when using a
myscript.pyw script with PyInstaller.
Rather than saving/renaming/changing the extension to .pyw, you can just add --noconsole to the command line and use the standard .py file with it and this would hide that console window.
Example:
We have a file named GUI_name.py in our folder that uses Tkinter. Now we could easily create .exe file that doesn't show the console window by typing pyinstaller --onefile --noconsole GUI_name.py in cmd.
I am writing a Python program that can be used both on the command-line, and as an interactive window. (Is that a bad idea?) If command-line arguments are supplied, it executes a task, then prints "success" or "failure". Otherwise, it launches an interactive window.
PyInstaller doesn't seem to be built to support this. I have two non-optimal options:
Use --console mode: The command-line works great, but if I double-click the exe to show the interactive window, it also shows a console window that I don't want
Use --noconsole mode: There's no console popup, but no output shows when using the command-line.
It seems I either need a way to not pop-up the console in --console mode, or to show print output in --noconsole mode. If neither of those options work, I may need to make a separate command-line version of the program.
Any advice?
This is not a perfect solution, but this workaround did the job for me:
Build gui app in --noconsole --one file mode like this:
pyinstaller --noconsole --onefile hello.py
When you double click on the app from windows it will launch normally (without the console).
Now to see the output, navigate to the executable from the command line and type:
hello.exe | more
The "| more" should send the print statements to the console.
This is a problem with Windows (not PyInstaller), which requires the subsystem to be specified as either CONSOLE or WINDOWS at compilation-time.
https://github.com/pyinstaller/pyinstaller/issues/6244#issuecomment-927131015
The recommended solution is to split your app (eg hello) into two distinct versions:
hellow.exe for the GUI version (windowed) and
hello.exe for the CLI version (console)
In theory, you could also add a wrapper .exe that switches between the two actual binaries above, depending on how it's called..
I'd like to write cross platform Python scripts that are GUI frontends for command line programs. The problem is I know a few Mac users who think that using the terminal will have the same effect as throwing their computer off the top of a skyscraper. In Linux and Windows it's easy enough to setup a Python script so the user can double click an icon and the script will start without opening any extra windows. Is there an easy way to do this with OS-X? Would the user have to install a different Python than the one that comes with OS-X? I haven't been able to find a definitive answer.
You might want to look at Platypus. It's a freeware app for generating apps which wrap scripts.
Another way to do something like that is using Automator or even AppleScript Editor. Either can produce an application which just runs a script.
Update:
For Automator: Launch Automator, select the Application template, type "script" in the search field, double-click Run Shell Script, switch the shell pop-up menu to /usr/bin/python, type/paste your Python script into the text field. Or, leave the pop-menu on /bin/bash and just write an invocation of an external script in the text field. Save as an application.
You can also view help from its Help menu.
For AppleScript, launch AppleScript Editor, type the following as the script:
do shell script "/usr/bin/true"
Replace /usr/bin/true with the path to whatever script you like. Save as an application.
Again, there's help in the Help menu.
py2app does this with aplomb. You make your Python script, use whatever dependencies you need (wx, Tkinter, etc.) and py2app makes you a standalone app bundle that will run in any modern OS X environment. It bundles Python too, so you can use any Python you want (not just the system default).
The downside is that the generated apps might be large, up to 50MB if you have a lot of dependencies (though that is somewhat of an extreme).
There are two ways to do this:
Click on a script.
Press command-i to open the "get info" window.
Expand the "Open With" section (if it isn't already).
Choose "Python Launcher" from the drop-down menu.
Click "Change All" if you would like ALL Python scripts to launch when double clicked.
Possibly open Python Launcher and uncheck "Run in a Terminal window"
This will work for this machine only, so it is less portable than the following. Why? Because the default for opening a document type varies depending on what is installed (XCode and/or IDLE will both take over opening a .py file).
Method Two:
Validate the Interpreter Directive, that's the first line of the file. I suggest using /usr/bin/env python3. This will run the first python3 interpreter that is on the users path.
Make the script executable chmod a+x <script_name> from the Terminal.
Change the extension from .py to .command (this will be opened by the Terminal).
Use zip or tar for distribution so that the permissions do not get mangled.
This method will open a Terminal window, but when the Python window is closed the terminal window will also close.
If your script has dependencies outside of the standard library, then you should provide a second .command file to install those. This may make things more complicated, but using pip3 install --user <list of dependencies> should minimize complications.