chriskiehl / Gooey

Turn (almost) any Python command line program into a full GUI application with one line

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

PyInstaller executable issue

ardoramor opened this issue · comments

After testing the application to work from source, I've built an executable:
pyinstaller.exe --onefile app.py

When I run the app.exe from the cmd, it prints the following error to the log:

Traceback (most recent call last):
File "", line 146, in
File "C:...\build\app\out00-PYZ.pyz\gooey.python_bindings.gooey_decorator", line 86, in inner
IOError: [Errno 2] No such file or directory: 'C:\Users...\AppData\Local\Temp_MEI108682\gooey_tmp\app.exe'

Does Gooey play well with PyInstaller or it hasn't been tested?

commented

You're a bit of a pioneer :) I haven't dug into PyInstaller and what all Gooey needs in order to be packaged up nicely.

Try running it without --onefile. I know in the past there was an issue with PyInstaller that, for whatever reason, would cause it to throw an error whenever you packaged a python app that used multiprocessing with --onefile. I dunno if that's still the case, but it could be a good starting point for debugging.

(note: typing this at work.. so it's just a quick off the top of my head guess at one possible issue)

I'll hopefully dig into the issue soon.

I got the following output while compiling without --onefile:

Traceback (most recent call last):
File "", line 151, in
File "C:\Users...\Documents\Projects\app\build\App\out00-PYZ.pyz\gooey.python_bindings.gooey_decorator", line 86, in inner
IOError: [Errno 2] No such file or directory: 'C:\Users...\DOCUME1\PROJ1\Ap1\dist\Ap1\gooey_tmp\App.exe'

The following directory exists:
'C:\Users...\DOCUME1\PROJ1\Ap1\dist\Ap1
But gooey_tmp\App.exe does not exist.

Looking at PyInstaller's warning output, I noticed the following:
W: delayed import hack detected at line 0 - gooey.python_bindings.modules (C:\Python27\lib\site-packages\gooey-0.1.0-py2.7.egg\gooey\python_bindings\modules.pyc)
W: delayed import hack detected at line 0 - gooey.python_bindings.gooey_decorator (C:\Python27\lib\site-packages\gooey-0.1.0-py2.7.egg\gooey\python_bindings\gooey_decorator.pyc)

I can confirm this error as well, with perhaps a bit more traceback:

Traceback (most recent call last):
  File "<string>", line 24, in <module>
  File "Z:\...\build\build\test\out00-PYZ.pyz\gooey.python_bindings.gooey_decorator", line 96, in inner
  File "Z:\...\build\build\test\out00-PYZ.pyz\gooey.gui.lang.i18n", line 41, in load
IOError: [Errno Language file not found. Make sure that your ] translation file is in the languages directory, 
err:seh:setup_exception_record stack overflow 1568 bytes in thread 0009 eip 7bc4629f esp 00240d10 stack 0x240000-0x241000-0x340000

using the compile options

wine python pyinstaller/pyinstaller.py --hidden-import=gooey test.py

and the test file

import gooey
from gooey import GooeyParser

@gooey.Gooey()
def main():
    parser = GooeyParser()
    parser.add_argument('-i', widget='FileChooser')
    args = parser.parse_args()
    print "DONE"



if __name__ == '__main__':
  main()

So, I tried messing around and compiling gooey. It did not work out but since there is an open issue i'll try to add in what i have.

I got passed the part where it complains about the language files (Thank you .spec file), with these files :

My test.py File

from gooey import Gooey
from gooey import GooeyParser
import argparse

@Gooey
def toto():
    parser = GooeyParser()
    parser.add_argument("toto")
    print("After add_argument")
    parser.parse_args()
toto()
print("Hello World!")

My test.spec File : (As a --onefile)

# -*- mode: python -*-
#Gooey_languages and gooey_images are used to fetch the files and solve the problem that was occuring preivously. (i.e : Language file not found)
gooey_languages = Tree('C:/Python27/Lib/site-packages/gooey/languages', prefix = 'gooey/languages')
gooey_images = Tree('C:/Python27/Lib/site-packages/gooey/images', prefix = 'gooey/images')
a = Analysis(['test.py'],
             pathex=['c:\\Python27\\Scripts'],
             hiddenimports=[],
             hookspath=None,
             runtime_hooks=None)
pyz = PYZ(a.pure)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          gooey_languages, # Add them in to collected files
          gooey_images, # Same here.
          name='test.exe',
          debug=False,
          strip=None,
          upx=True,
          console=True )

Commandline :
pyinstaller test.spec

Some warnings pop up, however since no reference to import issues are made when launched, i'm assuming they're uneventful.

C:\Python27\lib\site-packages\PyInstaller\hooks\hook-wx.lib.pubsub.core.py:11: RuntimeWarning: Parent module 'PyInstaller.hooks.hook-wx.lib.pubsub' not found while handling absolute import
  import os
C:\Python27\lib\site-packages\PyInstaller\hooks\hook-wx.lib.pubsub.core.py:12: RuntimeWarning: Parent module 'PyInstaller.hooks.hook-wx.lib.pubsub' not found while handling absolute import
  import PyInstaller.hooks.hookutils
C:\Python27\lib\site-packages\PyInstaller\hooks\hook-wx.lib.pubsub.core.py:14: RuntimeWarning: Parent module 'PyInstaller.hooks.hook-wx.lib.pubsub' not found while handling absolute import
  from PyInstaller.hooks.hookutils import logger

And it outputs an executable. Yay! However when launched, it displays a Gooey window, allows you to enter the arguments, but once you hit start it outputs an error that always sticks to these lines :

File "c:\.....\appdata\temp\tmp_xxxxx.py", line 1
SyntaxError : Non-ASCII character '\x90' in file
c:\......\tmp_xxxxx,py on line 1, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details.

So on I go to see what this says. And it is due to python believing all files are encoded in ascii since nothing else was specified. Very well. I meddled with site.py to set the default encoding to utf-8 and see if that would help. It did not. (Printing sys.getdefaultencoding() returns utf-8 so i know it has been set and that the character in question is among the utf-8 set.)
As for adding the # -*- encoding : utf-8 -*- to every file (gooey and all included) i didn't have the courage so i do not know if it could help.

As far as trying to do a directory build (and not a --onefile which is wht my spec file does) I could not figure out a way to bypass "missing python27.dll". Adding it to binaries did not work, it is present in both sys directories (32 and 64) so i must be doing something wrong on that side and thus cannot really test it that way.

But if the people who can manage a clean build without --onefile could throw in the lines that i added to fetch the language/image packs in the .spec file, it might solve the problem noted by @thoppe

commented

@Roshgar, found the issue!

In gooey\python_bindings\config_generator.py, change:

run_cmd = 'python {}'.format(source_path)

to

if hasattr(sys, 'frozen'):
    run_cmd = source_path
else:
    run_cmd = 'python {}'.format(source_path)

Gooey is trying to launch your file as if it were a python file, ie python myfile.exe, leading to the weird encoding issues. Just tell it to launch as-is instead of prepending python, and it works great.

Combining the solutions by @Roshgar and @daranguiz works great for me.

@daranguiz: Will you be creating a PR for this fix? I can do so instead if it's easier.

I'm also going to try to take a look at helping PyInstaller work out of the box with Gooey. They seem like a perfect combination.

commented

@8BitAce: It'd be easier for me if you submitted the PR, thank you!

commented

I also have the issue where the language file are not found at runtime - @Roshgar 's method of editing the spec file does not help. The only difference I can see is that I'm using Linux, but I've adjusted the paths accordingly.

commented

@iodbh There's a pull request by @Shura1oplot here ( #118) that says it has fixes for the numerous path issues. Do you wanna check out that branch and see if it fixes your problem?

commented

Done. The fix works if I copy the languages and images directories into dist/gooey; but the files are not found if I add them to pyInstaller's collect files (via @Roshgar 's edits in the spec file). The new error message is more explicit :

IOError: cannot locate Gooey resources. It seems that the program was frozen, but resource files were not copied to directory of the executable file. Please copy `languages` and `images` folders from gooey module directory into `/home/user/projects/gooeytest/dist/gooey/` directory.

So the generated executable is now runnable if the directories are copied.

I had this same issue as @iodbh today, @Roshgar's method was not working with the latest version 0.8.14.0. Unfortunately copying the directories dist/gooey directory is not an option when using PyInstaller onefile.

I downgraded to 0.8.12.0 and it started working again. This is on Windows.

commented

@tandreas : (

Arg... Alright, next task at the top of my TODO is to solve all these packaging woes!

Please try this #123.

commented

@tandreas

Minor progress! I figured out how to make --onefile play nice with the external resources! No more manual copying stuff. Turns out that part of the magic of onefile is that it unpacks all of the resources into a temp directory on startup. See here: https://pythonhosted.org/PyInstaller/#run-time-operation

With that info, a quick update to @Shura1oplot's get_resource_handler so that it grabs the _MEIPASS directory when frozen and all seems to work nicely now.

I'm still facing missing import issues with multiprocessing, but.. at least the non-code resources load!

@chriskiehl
Commit 660b0b0 breaks support of cx_freeze as it does not set sys._MEIPASS. Both freezers should work with PR #123.

commented

@Shura1oplot Doh! I hadn't looked at that pull. I'll revert f0c3771 and merge in #123.

I think we can almost call this issue officially solved! I can package using both PyInstaller and cxFreeze on both Windows and Linux. Wiki entry on the topic is in progress (On my win8 machine, I'm needing a small hack to force stdout to flush when using pyinstaller).

The last piece of this is just sanity checking that it packages okie-dokie on OSX. Once that's confirmed, this issue is done!

@chriskiehl Has OSX packaging been confirmed? If so, are there special instructions I need to follow? I can't get it to work for me.

I had the same issue as the binary would not run as it complained that it was missing the image folder and language folders. I followed the spec file that @Roshgar referenced above and it works as one file now. This has saved me a lot of work. Thank you @Roshgar .

I tried to build a simple demo using pyinstaller. It compiles without errors, and the UI entry form comes up when I run the .exe, but nothing happens when I click the start button. No error message. The window just stays as is (except the start button does "depress" when it is clicked)
The script works if not compiled.
Environment: Windows 7. Python 2.7, 64 bit. Gooey 0.9.2.3, pyinstaller 3.1.1
I tried the spec file as detailed under "Packaging Gooey as a Distributable Application", and the one at https://github.com/chriskiehl/Gooey/files/29568/build.spec.txt. (They are different by a couple lines. Same result for both)
If I add the stdout fix lines, I get fatal error: ....exe returned -1
If no entry is made for a required argument, then the expected error popup does come up after I click start.
Any thoughts on what's wrong, or suggestions to try, would be a huge help. Thank you. - Chris

commented

I tried to build a simple demo using pyinstaller. It compiles without errors, and the UI entry form comes up when I run the .exe, but nothing happens when I click the start button. No error message. The window just stays as is (except the start button does "depress" when it is clicked)
The script works if not compiled.

^ Im having the EXACT same problem, its been driving me nuts....would love to find a solution to get rid of the error or the console window. In addition, I had to compile with pyinstaller 3.1 instead of 3.2.

My own module uses subprocess and I ran into the same issue. However, a strange thing happens (which is unrelated) where if I issue subprocess.call when frozen, a console comes up for every call instance. My program works as intended though.

Actually I fixed my own subprocess issue by following the comment here:
https://groups.google.com/d/msg/pyinstaller/-4Fdy7suh0U/0o9Yqa78zCEJ

Turns out you just need to addd a startupinfo object to your subprocess call.

It's also documented here on the PyInstaller website: https://github.com/pyinstaller/pyinstaller/wiki/Recipe-subprocess

So after all this, my frozen Gooey executable works perfectly. Thanks so much for this project!

"but nothing happens when I click the start button"

I'm also having this issue, anyone have any ideas?

I managed to track this a bit further.

It seems ProcessController.run hits an exception when calling subprocess.Popen, if the --noconsole option is supplied when running pyinstaller.
http://stackoverflow.com/questions/33020644/python-subprocess-popen-with-pyinstaller

It works for me if I enable console in the build.spec
console=True,

Of course, that enables a big console window in the background :( but it's a workaround

To use cx_freeze with Gooey on OSX, I had to specify the language/image resources to include:

import os
import gooey
from cx_Freeze import setup, Executable


def get_resources():
    target_prefix = 'gooey'
    source_dir = os.path.dirname(gooey.__file__)
    subdirs = ['languages', 'images']
    includes = []
    for directory in subdirs:
        path = os.path.join(source_dir, directory)
        for file in os.listdir(path):
            file_path = os.path.join(path, file)
            relative_path = os.path.join(target_prefix, directory, file)
            includes.append((file_path, relative_path))
    return includes


setup(
    name="my_gooey_app",
    version="0.1",
    description="My Gooey App",
    options={"build_exe": {'include_files': get_resources()}},
    executables=[
        Executable("my_gooey_app.py", base=base),
    ]
)

I also to make sure to use a python version compiled with support for GUI applications (--enable-shared or --enable-framework). I use pyenv, so I had to follow these instructions.

I guess this confirms it for OSX.