Pyinstaller binary not working with PRAW config - python

I have download and installed Pyinstaller via pip with the goal of making an .exe binary that will be usable stand-alone on windows. My app/script is mostly similar to this one, downloading images from a certain subreddit (which is accessible without a reddit account).
Running the .py script via console or through my IDE works as expected, both on Linux and Windows. According to the PRAW documentation there has to be a C:\Users\myName\AppData\praw.ini config file post-PRAW's installation but it's currently missing from my system, yet, as I mentioned, the script runs just fine when on the python interpreter.
Packaging it into an .exe with Pyinstaller works fine but running it (with or w/o admin rights) fails with the following error
C:\Users\John\IdeaProjects\monsteraday-subreddit-image-downloader\dist>monsteraday-image-downloader.exe
Traceback (most recent call last):
File "<string>", line 5, in <module>
File "C:\Python27\Lib\site-packages\PyInstaller\loader\pyimod03_importers.py",
line 363, in load_module
exec(bytecode, module.__dict__)
File "C:\Python27\lib\site-packages\praw\__init__.py", line 40, in <module>
from praw.settings import CONFIG
File "C:\Python27\Lib\site-packages\PyInstaller\loader\pyimod03_importers.py",
line 363, in load_module
exec(bytecode, module.__dict__)
File "C:\Python27\lib\site-packages\praw\settings.py", line 47, in <module>
CONFIG = _load_configuration()
File "C:\Python27\lib\site-packages\praw\settings.py", line 45, in _load_configuration .format(locations))
Exception: Could not find config file in any of: [u'C:\\Users\\John\\AppData\\Local\\Temp\\_MEI52442\\praw\\praw.ini', u'C:\\Users\\John\\AppData\Roaming\\praw.ini', u'praw.ini']
monsteraday-image-downloader returned -1
At this point I should clarify that both
running python myscript.py in the console
executing the pyinstaller generated myscript.exe via console or double-clicking
Were tried on the same Win8.1 x64 machine, with all required libraries (including PRAW) installed, Python 2.7 32-bit (for compatibility of the target .exe) and the user praw.ini config missing from /AppData/ dir, while the global praw.ini properly in C:\Python27\Lib\site-packages\praw\praw.ini
Pyinstaller documentation mentions the usage of the .spec file to include external files in the wrapped .exe but I don't see how this play any role since I already lack/don't need the praw.ini configuration. Py2exe also produces the same results. How can I fix this and produce a straightforward way to use this tool?

Based on the last line of the output
Exception: Could not find config file in any of: [u'C:\\Users\\John\\AppData\\Local\\Temp\\_MEI52442\\praw\\praw.ini', u'C:\\Users\\John\\AppData\Roaming\\praw.ini', u'praw.ini']
It seems that PRAW, when run from a packaged .exe, is looking for its config file 'praw.ini' in 3 distinct locations
A temp folder created in the user's system directories, presumably
as instructed by pyinstaller
The user's Roaming folder (in Windows)
., in the same path the .exe is run from
Now, let's see what we can do to qualify for at least one of these cases.
It might be possible to tweak pyinstaller's settings and .spec file in a way that it takes a certain praw.ini file (like the global one found in Pytho's installed packages folder for PRAW) and places it in the temp folder so that the script can use but there doesn't seem to be an easy/direct way to do that. It definitely seems the most "proper" way to do it though.
Having each user place a config file there is bad for UX and should be avoided, unless of course there is an automated installation involved to do it, which might be overkill if we're talking about a small program.
The last is not ideal, but it's a decent compromise and definitely easy to roll with developer-side. All it takes is for the user to have the praw.ini in the same folder he/she is running the .exe from. The executable can be shared within a .zip archive containing a copy of the praw.ini as well, so that when run by the user it will be fully operational without extra effort on their behalf.
Even though it's actually a workaround, the last option will provide enough simplicity for the tool to be working out-of-the-box for an average user.

Related

PyInstaller file fails to execute script - DistributionNotFound

I'm trying to convert my python file to an executable using PyInstaller. The program uses the Google Cloud Translate API to translate given text between languages. When running python quicktrans.py in the terminal, the program works fine. Then I ran pyinstaller quicktrans.py, SHIFT + right-clicked the directory the executable was in, and ran the .exe file in the terminal. This is the traceback that it spit out (Note this is not the whole traceback because it is a little lengthy):
File "c:\users\kalab\realpython\quicktrans\google\cloud\connection.py", line 31, in <module>
get_distribution('google-cloud-core').version)
File "site-packages\pkg_resources\__init__.py", line 559, in get_distribution
File "site-packages\pkg_resources\__init__.py", line 433, in get_provider
File "site-packages\pkg_resources\__init__.py", line 970, in require
File "site-packages\pkg_resources\__init__.py", line 856, in resolve
pkg_resources.DistributionNotFound: The 'google-cloud-core' distribution was not found and is required by the application
Failed to execute script quicktrans
I've tried looking into this and some reason it's giving me a pip-like error. I've been trying to fix this for hours and no luck.
Note: To install its client library, as per the documentation, you must run pip install --upgrade google-cloud-translate
I'm thinking this might have something to do with this because the last application I used dealt with the Facebook client module and you only had to do pip install facebook-sdk and the executable made by PyInstaller ran with no issues.
If you want to examine my code used in my program, it's hosted on my GitHub.
Thanks to anyone helping me out here!
It is basically package building name issue. Pyinstaller tries to import
google.cloud
where Google cloud package is now called
gcloud
. So you need to create a hook file for that names
C:\Users\\AppData\Local\Programs\Python\Python36-32\Lib\site-packages\PyInstaller\hooks\hook-gcloud.py
File contents:
from PyInstaller.utils.hooks import copy_metadata
datas = copy_metadata('gcloud')
In my experience base on the helps in https://github.com/GoogleCloudPlatform/google-cloud-python/issues/1187 :
Go \Anaconda3\Lib\site-packages\PyInstaller\hooks folder (if you use anaconda otherwise you need to find it under python folder)
Find the hook-google-cloud.py (If exist, otherwise you need to creat the hook.
Write to existing code as shown below
'''
Copyright (c) 2017, PyInstaller Development Team.
Distributed under the terms of the GNU General Public License with exception
for distributing bootloader.
The full license is in the file COPYING.txt, distributed with this software.
'''
from PyInstaller.utils.hooks import copy_metadata
datas = copy_metadata('google-cloud-core')
datas += copy_metadata('google-cloud-translate')
datas += copy_metadata('google-api-core')
Hope you find this explaination helpful. Thank you.
Alternate hook tweak
I'm running into this same essential problem with the Google speech engine.
It's odd how everyone here seems to have success with slightly alternate solutions to this. I really don't understand how the "patches" to the hook which leave copy_metadata('google-cloud-core') in place can work? The error thrown back reads The 'google-cloud-core' distribution was not found..., so how can one execute that line as is?
This is my replacement for the file content of hook-google.cloud.py, in order to build an exe using google speech:
# PATCH: PROVIDED ALTERNATE PACKAGE NAME
from PyInstaller.utils.hooks import copy_metadata
try:
datas = copy_metadata('google-cloud-core')
except:
datas = copy_metadata('google-cloud-speech')
My personal solution:
Change all calls to get_distribution with it returned values (0.21.0 in my case)
Remove from pkg_resources import get_distribution from import
for all files in the package.
I had the exact same issue. I solved it by doing this:
Goto the Pyinstaller hooks folder (~\Lib\site-packages\PyInstaller\hooks)
Find the file hook-google.cloud.py, open it, and add the following code to it
datas += copy_metadata('google-cloud-translate')
datas += copy_metadata('google-api-core')
The issue seems to be that get_distribution is not working with the default google.cloud.translate hook, so I just added this to a hook that was working.
Hope this helps someone.
I was using PyCharm venv for my project, and the only solution that worked for me is changing the project over to a system interpreter (and install the required packages to that).
Today, when I tried to build an EXE out of my Python script, I got the same error:
pkg_resources.DistributionNotFound: The 'google-cloud-core' distribution was not found and is required by the application
I thought the reason was one of the listed ones in this thread, since I was sure I had all dependencies installed with pipenv because my code compiled and I could debug and run the code without issues. Note I used pipenv shell in an empty folder and created my app in it, installing all necessary libraries using pipenv install ..., and one of the libraries was google-cloud-dialogflow (the app is a chatbot manager).
The solution was simply to run pipenv install google-cloud-core.
Now, pyinstaller chatbot_manager.py --onefile --windowed created the c:\Users\...\dist\chatbot_manager.exe file without issues.

python- behave: generate step functionality throws list index out of range

this is my first question here, so any tips on improvement on that are welcome :)
I am figuring out how to write tests using: Sublime Text 3, python, and behave.
What works now is that my feature file is recognised: has all the right colours, as far as I can tell.
Now next I want to generate step functions. The desired behaviour is the that when I when I do so (right clicking on a function==> generate step function, or through the command palette, it opens a popup where I can specify that I want it to create a new file, and then creates that file.
The error I get is:
When I do, it does nothing except throw some exception in the console:
Traceback (most recent call last):
File "behave_toolkit.commands.highlight_unimplemented_steps in /Users/chai/Library/Application Support/Sublime Text 3/Installed Packages/Behave Toolkit.sublime-package", line 18, in run_async
File "behave_toolkit.mixins.steps in /Users/chai/Library/Application Support/Sublime Text 3/Installed Packages/Behave Toolkit.sublime-package", line 50, in get_unimplemented_steps
File "behave_toolkit.mixins.steps in /Users/chai/Library/Application Support/Sublime Text 3/Installed Packages/Behave Toolkit.sublime-package", line 82, in _get_step_data
File "behave_toolkit.behave_command in /Users/chai/Library/Application Support/Sublime Text 3/Installed Packages/Behave Toolkit.sublime-package", line 27, in behave
File "behave_toolkit.behave_command in /Users/chai/Library/Application Support/Sublime Text 3/Installed Packages/Behave Toolkit.sublime-package", line 73, in _launch_process
IndexError: list index out of range
I have tried some suggestions about defining a path to behave in package settings but that did not help.
I am not very experienced with these things, so any answer with details would be very welcome.
Any ideas ?
On the "Getting Started" page of the Sublime plugin Behave Toolkit's documentation, the very first thing it talks about is setting up your project's directory, then opening it in Sublime. You are getting this error because the file(s) you are editing do(es) not belong to a Sublime project. This in turn is causing an error on this line of the code, which throws an IndexError because view.window().folders()[0] is looking for the first folder present in the project (it returns a list of the folders associated with the project), which in your case does not exist.
This error is not caught, propagates, and eventually leads to the traceback you put in your question. IMO this is not a very good example of plugin programming, both because there is no error handling, and because the plugin assumes that a project (which has to have at least one folder) is active. A better method would be to abstract this line into a function which contains the error checking and a method of warning the user upon invocation what the problem is, instead of (relatively) silently failing.
So, the workaround is to always run this plugin in a project that contains only one folder, as if you have multiple folders, the plugin will by default choose the first one in the list (the zeroth element).
Follow up
I submitted a bug report and a pull request to fix this issue. Hopefully it will get merged and pushed out fairly quickly. If you want to use it right away, here's how:
Open the Command Palette and select Package Control: Disable Package, then scroll down and select Behave Toolkit. Now, close Sublime. Next, on the command line (assuming you have git installed and on your path), change to your Packages folder, which is the one opened in your operating system's file manager when selecting Preferences → Browse Packages…:
Linux: ~/.config/sublime-text-3/Packages
OS X: ~/Library/Application Support/Sublime Text 3/Packages
Windows Regular Install: C:\Users\YourUserName\AppData\Roaming\Sublime Text 3\Packages
Windows Portable Install: InstallationFolder\Sublime Text 3\Data\Packages
Run the following commands:
git clone https://github.com/MattDMo/BehaveToolkit.git
cd BehaveToolkit
git checkout -b issue-17
You can now restart Sublime, and my version of the plugin will become active. Please keep in mind that since it was installed manually, it will not be automatically updated by Package Control. Keep an eye on the Package Control page for Behave Toolkit and the MODIFIED field on the left side at the top under Details. If it updates, open your user preferences (Preferences → Settings—User) and modify the "Behave Toolkit" line in "ignored_packages" to "BehaveToolkit" (i.e., remove the space). Save the file, and the cloned directory in Packages will be ignored, while the Package Control-installed version will not. Finally, you'll need to open the Command Palette and select Package Control: Upgrade Package → Behave Toolkit to get the latest version.
Good luck!

Py2exe, Tkinter, and Setup File Problems?

I just finished creating a python program in 2.7 and I converted it to a .exe with py2exe.
Everything works fine when I run the converted executable file in the folder I placed it in with all of the images in it. After converting the python program to .exe, I proceeded to creating a setup file for it. I added all of the files associated with my project including tkinter in the setup file. I added pretty much everything that let me run the executable.
Once I finished creating the setup file, I opened it. I went through everything and finished installing it on my system and created a shortcut on my Desktop. When I tried to open it, it would not work. Instead of running the program, it tells me to open a log file in its folder in the Program Files. When I open the log file, I noticed an error. How do I fix this?
Error:
Traceback (most recent call last):
File "gui.py", line 10, in <module>
File "Tkinter.pyc", line 1764, in __init__
_tkinter.TclError: Can't find a usable init.tcl in the following directories:
{C:/Program Files (x86)/lib/tcl8.5} {C:/Program Files (x86)/lib/tcl8.5} C:/lib/tcl8.5 {C:/Program Files (x86)/library} C:/library C:/tcl8.5.15/library C:/tcl8.5.15/library
This probably means that Tcl wasn't installed properly.
I found a bug on the virutalenv site which suggested the following https://github.com/pypa/virtualenv/issues/93
I imagine that you are encountering the same issue just without virtualenv
the following set the correct paths which can then be included in the application please find the right path to TCL and TK for your python version
set "TCL_LIBRARY=C:\Python27\tcl\tcl8.5"
set "TK_LIBRARY=C:\Python27\tcl\tk8.5"
restart your cmd or shell
I believe that the TCL location have changed from there default ones.

Debugging python in Aptana 3

I have a pydev project going in aptana studio 3.
In the image below, you can see my project structure and the fact that my nosetests are all passing.
If I click on a file scheduled.py that has a breakpoint in it, and hit debug as > python run it fails to be able to import my modules.
pydev debugger: starting
Traceback (most recent call last):
File "C:\Users\mapserv\AppData\Local\Aptana Studio 3\plugins\org.python.pydev_2.7.0.2012110722\pysrc\pydevd.py", line 1397, in <module>
debugger.run(setup['file'], None, None)
File "C:\Users\mapserv\AppData\Local\Aptana Studio 3\plugins\org.python.pydev_2.7.0.2012110722\pysrc\pydevd.py", line 1090, in run
pydev_imports.execfile(file, globals, locals) #execute the script
File "C:\Users\mapserv\Desktop\Projects\Aptana\AutomatedCaching\agrc\caching\scheduled.py", line 1, in <module>
from agrc.caching.commands import cache
ImportError: No module named agrc.caching.commands
I've noticed that aptana has the notion of packages/modules. Is there something wrong with my project structure that is causing this? Should my folders be packages? Do I need to setup more things with my interpreter which looks like?
Edited
If I try to run scheduled.py from the command line it has the same problem. How is nose running my tests and making everything happy yet it doesn't work outside of that?
Well the answer was to update your PYTHONPATH. On windows, put the path to the AutomatedCaching folder inside the automated_caching.pth file.
eg: C:\Projects\AutomatedCaching
Then move the file into your site packages folder. For arcgis users it will be something like
C:\Python27\ArcGISx6410.1\Lib\site-packages
or
C:\Python27\ArcGIS10.1\Lib\site-packages
depending if you installed server and desktop. I'm thinking the last install wins the PATH war? I installed server then desktop and it uses the second in the path without the x64.
running
import sys
for i in sys.path:
print i
should verify that your location has been added.
Now the fact that arcgis for server and desktop install two different pythons into c:\python27 is a whole different story.
Now aptana shows my package explorer like it is a package
Did you try putting it in your "PyDev - PYTHONPATH" project properties? Project -> Properties -> PyDev - PYTHONPATH -> Source Folders(tab) -> Add source folder.
Then you don't have to mess with your system PYTHONPATH.
It worked for me.
Tried to post an image but I guess I don't have enough reputation points.

Eclipse Pydev not loading an external module, terminal works fine

I'm running Eclipse Juno with Pydev. I compiled an egg package that imports a C library using ctypes. It works fine from the terminal, but when run from inside Eclipse I get
/usr/local/lib/python2.7/dist-packages/PhreeqPy-0.1.0-py2.7.egg/phreeqpy/iphreeqc
Traceback (most recent call last):
File "/src/pywork/fddarcy/src/fddarcy.py", line 75, in <module>
sys.exit(main())
File "/src/pywork/fddarcy/src/fddarcy.py", line 35, in main
freak =phreeqc_mod.IPhreeqc()
File "/usr/local/lib/python2.7/dist-packages/PhreeqPy-0.1.0-py2.7.egg/phreeqpy/iphreeqc/phreeqc_dll.py", line 28, in __init__
self.phreeqc = ctypes.cdll.LoadLibrary(dll_path)
File "/usr/lib/python2.7/ctypes/__init__.py", line 443, in LoadLibrary
return self._dlltype(name)
File "/usr/lib/python2.7/ctypes/__init__.py", line 365, in __init__
self._handle = _dlopen(self._name, mode)
OSError: libimf.so: cannot open shared object file: No such file or directory
After reloading all libraries in Pydev Eclipse is not even giving errors when importing the module, but it doesn't load the module. Just to be extra clear, everything works fine from the terminal.
EDIT: I think that the problem is in the way Eclipse is calling python. Is it any different from the way python is called from the terminal?
Cheers
If you haven't already, you may need to add it to the PYTHONPATH within Eclipse.
Window -> Preferences -> PyDev -> Interpreter - Python
Add your python.exe or run autoconfig and then add the libraries you need.
Eclipse is seeing the ctypes module, it's just that ctypes can't find the DLL.
The reason for this is that eclipse doesn't necessarily use your system's environment variables. To remedy this problem, you need to set the LD_LIBRARY_PATH within Eclipse.
Step 1. Figure out where "libimf.so" is on your system. On Linux, you can use:
locate libimf.so
in a terminal. That should give you the directory. For example, say the file is at "/home/sweetlibraries/libimf.so" .
Step 2. Set LD_LIBRARY_PATH in Eclipse*:
Right click on the python file that you're running that gives this error.
Click "properties"
Click "Run/Debug Settings"
You should see some configuration for the file. For me, it's "project_name python_file_name.py". Select it.
Click "Environment"
Click "New"
Set Name to "LD_LIBRARY_PATH"
Set Value to wherever you found libimf.so, e.g. "/home/sweetlibraries/"
Click "OK" to get out of all those menus.
Now when you run it, it should work. If not, make sure you use the right "run configuration". Click the little down arrow next to the big, green "run" arrow. and select the configuration name (e.g. "project_name python_file_name.py").
*I'm using LiClipse, but I think the menu structure should be identical.

Categories