I've been repeatedly making good PyInstaller executables of a Tkinter utility program, and suddenly this morning the resulting executable fails with a "can't import" error for modules in C:\Python27\Lib, such as "timeit" and "bisect".
The script runs fine on its own. Only the executable has problems.
Any ideas what could have changed to cause this behavior? Or how to force a fix?
[EDIT] Here's the specific error reported by the executable:
Traceback (most recent call last):
File "<string>", line 35, in <module>
File "../..\utils\InterpolatedArray.py", line 12, in <module>
import bisect
ImportError: No module named bisect
When I comment-out the use of this module (to bypass the import of bisect), it next fails on an import of timeit. None of these errors occur when running the script itself.
[EDIT2] Pyinstaller creates the directories it needs (./build and ./dist), and has no permission problems. The pyinstaller build completes without error.
[EDIT3] Here's the build command I'm using:
pyinstaller -F MyMainModule.py
Found a fix, if not the cause. Here's my updated build line:
pyinstaller --hidden-import=timeit --hidden-import=bisect -F MyMainModule.py
Still not sure why PyInstaller suddenly forgot how to find these two modules (and only these two modules) among over 20 other modules correctly included in the build.
I encounter similar issues while packaging a Python script imported openpyxl. Here is my solution.
Step 1: install the python module, openpyxl
$ wine python.exe Scripts/pip.exe install openpyxl
Step 2: add the openpyxl path
Append the openpyxl path (~/.wine/drive_c/Python27/Lib/site-packages) to pathex in the Analysis object in the application spec file (e.g.,ProcessSpreadsheet.spec).
a = Analysis(['ProcessSpreadsheet.py'],
pathex=['C:\\Python27\\Scripts', '~/.wine/drive_c/Python27/Lib/site-packages'],
binaries=None,
datas=None,
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher)
Step 3: rebuild
$ wine pyinstaller.exe ProcessSpreadsheet.spec
Refer to here for the detailed description.
For unix/linux users, make sure the that you are referencing the same packages when compiling as the application do. This issue mainly occurs when using a virtual environment. For that purpose spot the installed package folder and edit the myapp.spec.
Then run
pyinstaller myapp.spec
I found that pyinstaller and PyInstaller differ in this.
Use PyInstaller when non standard modules/libraries should be included in the executable. PyInstaller needs to be installed using pip/pip3 (I'm unning MacOS) Then just run: PyInstaller -F <script.py>
Related
So, I've had some trouble setting up my application through Inno setup Compiler, at first I assumed it was a problem within Inno itself but on further inspection I think it is my actual exe. I am able to create a working exe file that runs my program properly but only on my own pc. I am able to create the setup file that also works through Inno setup but it only works on my own pc. I have sent both the actual exe file and the Inno setup file to another computer and downloaded it there and ran it, both meet the same "Fatal Error: failed to run script tk_app.py". Therefore, the problem must be that I have not been able to pavkage the app properly with pyinstaller.
My prgoram has 5 files in total (all in the same folder): main.py, file1.py, file2.py file3.py, tk_app.py
All of them importing each other and using python libraries. I know that pyinstaller supports librarires such as pandas, tkinter and many more without needing the --hidden-impoort= command and that it will pick up all files within the program if there are files that are importing each other.
So I use the file tk_app.py (which contains my tkinter UI and imports main.py which then goes onto import file1.py which import another file so on)
The pyinstaller command line I use to make the exe is as follows:
PS C:\Users\ripta\Desktop\CODING\CSV_Upload> pyinstaller -w --hidden-import=bs4 --hidden-import=fake_useragent --hidden-import=urllib.prase --hidden-import=urllib.request --hidden-import=os --hidden-import=pandas.io.parsers --icon=trademark_icon.ico --onefile tk_app.py
My question is, will pyinstaller tell me when it needs a given --hidden-import='name' when running becuase it doesn not throw up any errors and does produce a spec file, a build folder and a dist folder containing the exe file.
I have noticed that it throws up WARNINGs or Exceptions (also not sure why it mentions django as I do not import or use it at all inthe application) :
59182 INFO: Loading module hook 'hook-django.db.backends.py' from 'c:\\users\\ripta\\appdata\\local\\programs\\python\\python36-32\\lib\\site-packages\\PyInstaller\\hooks'... 61711 WARNING: Hidden import "django.db.backends.__pycache__.base" not found! 61712 INFO: Loading module hook 'hook-django.py' from 'c:\\users\\ripta\\appdata\\local\\programs\\python\\python36-32\\lib\\site-packages\\PyInstaller\\hooks'... Traceback (most recent call last): File "<string>", line 21, in walk_packages File "c:\users\ripta\appdata\local\programs\python\python36-32\lib\site-packages\django\contrib\gis\admin\__init__.py", line 5, in <module>
Or show Hidden-import not found (Of imports I have no idea about):
149329 WARNING: Hidden import "pkg_resources.py2_warn" not found! 149330 WARNING: Hidden import "pkg_resources.markers" not found!
The fact that the script fails to run on any other computer besided my own leads me to think that it must be lacking a dependency that is only found on my computer, therefore I am not using pyinstaller correctly but am not too sure where exactly I am making the mistake.
First I've uninstalled Setuptools and reinstalled it with specific version. Then, I've imported pkg_resources.py2_warn as hidden import :
pip uninstalled setuptools
pip install --upgrade 'setuptools<45.0.0'
pyinstaller --hidden-import='pkg_resources.py2_warn' tk_app.py
It worked for me.
I have a python script that uses scrapy and I want to make it into an exe file using pyinstaller. The exe file is generated without any error but when I open it an error occurs.
FileNotFoundError: [Errno 2] No such file or directory: '...\\scrapy\\VERSION'
I have tried reinstalling scrapy but that did not help. I am using windows 10 with python3
Full Disclosure: This is a repost of my answer to a duplicate, similar question. I am just putting it here for visiblity. This genuinely answers the question asked; so it is relevant.
You did not use Pyinstaller properly when you had built your stand-alone program. Here is a short, layman's description of how Pyinstaller works: Pyinstaller bundles the Python interpreter, necessary DLLs (for Windows), your project's source code, and all the modules it can find into a folder or self-extracting executable. Pyinstaller does not include modules or files it cannot find in the final .exe (Windows), .app (macOS), folder, etc. that results when you run Pyinstaller.
So, here is what happened:
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/_MEIbxALM3/scrapy/VERSION'
You ran your frozen/stand-alone program. As soon as you did this, your program was 'extracted' to a new, temporary folder on your computer /temp/_MEIbxALM3/. This folder contains the Python interpreter, your program's source code, and the modules Pyinstaller managed to find (plus a couple other necessary files).
The Scrapy module is more than just a module. It is an entire framework. It has its own plain text files (besides Python files) that it uses. And, it imports a lot of modules itself.
The Scrapy framework especially does not get along with Pyinstaller because it uses many methods to import modules that Pyinstaller cannot 'see'. Also, Pyinstaller basically makes no attempt to include files in the final build that are not .py files unless you tell it to.
So, what really happened?
The text file 'VERSION' that exists in the 'normal' scrapy module on your computer (that you had installed with pip or pipenv) was not included in the copycat scrapy module in the build of your program. Scrapy needs this file; Python is giving you the FileNotFoundError because it simply was never included. So, you have to include the file in the build of your program with Pyinstaller.
How do you tell Pyinstaller where to find modules and files?
This guy says to just copy the missing files from where they are installed on your computer into your build folder spit out from Pyinstaller. This does work. But, there is a better way and Pyinstaller can do more of the work for you (preventing further ImportErrors and FileNotFoundErrors you may get). See below:
build.spec Files are Your Friend
spec files are just Python files that Pyinstaller uses like a configuration file to tell it how to build your program. Read more about them here. Below is an example of a real build.spec file I used recently to build a Scrapy program with a GUI for Windows (my project's name is B.O.T. Bot):
import gooey
gooey_root = os.path.dirname(gooey.__file__)
gooey_languages = Tree(os.path.join(gooey_root, 'languages'), prefix = 'gooey/languages')
gooey_images = Tree(os.path.join(gooey_root, 'images'), prefix = 'gooey/images')
a = Analysis(['botbotgui.py'],
pathex=['C:\\Users\\Colton\\.virtualenvs\\bot-bot-JBkeVQQB\\Scripts', 'C:\\Program Files (x86)\\Windows Kits\\10\\Redist\\ucrt\\DLLs\\x86'],
hiddenimports=['botbot.spiders.spider'],
hookspath=['.\\hooks\\'],
runtime_hooks=None,
datas=[('.\\spiders\\','.\\spiders\\'), ('.\\settings.py','.'),
('.\\scrapy.cfg','.'), ('.\\items.py','.'), ('.\\itemloaders.py','.'),
('.\\middlewares.py','.'), ('.\\pipelines.py','.')
]
)
pyz = PYZ(a.pure)
options = [('u', None, 'OPTION'), ('u', None, 'OPTION'), ('u', None, 'OPTION')]
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
options,
gooey_languages, # Add them in to collected files
gooey_images, # Same here.
name='BOT_Bot_GUI',
debug=False,
strip=None,
upx=True,
console=False,
windowed=True,
icon=os.path.join(gooey_root, 'images', 'program_icon.ico'))
#coll = COLLECT(exe,
#a.binaries,
#a.zipfiles,
#a.datas,
#options,
#gooey_languages, # Add them in to collected files
#gooey_images, # Same here.
#name='BOT_Bot_GUI',
#debug=False,
#strip=False,
#upx=True,
#console=False,
#windowed=True,
#icon=os.path.join(gooey_root, 'images', 'program_icon.ico'))
Uncomment the last region if you want to build a folder instead of a stand-alone .exe. This is a configuration file specific to my computer and project structure. So in your file, you would have to change a few things (for example pathex to tell Pyinstaller where to find DLLs on Windows 10. But, the premise is the same.
My project directory looks like this:
botbotgui.py botbot.py hooks images __init__.py itemloaders.py items.py middlewares.py pipelines.py __pycache__ scrapy.cfg settings.py spiders
Pay special attention to the hooks/ directory. Using hooks will save you from a lot of headaches down the road. Read more about Pyinstaller's hooks feature here. In the hooks/ directory there is a hook file for Scrapy. This will tell Pyinstaller to include many modules and files it would have otherwise missed if you did not use a .spec file. This is the most important thing I have wrote here so far. If you do not do this step, you will keep getting ImportErrors every time you try to run a Scrapy program built using Pyinstaller. Scrapy imports MANY modules that Pyinstaller misses.
hook-scrapy.py (Note: Your hook file must be named just like this.):
from PyInstaller.utils.hooks import collect_submodules, collect_data_files
# This collects all dynamically imported scrapy modules and data files.
hiddenimports = (collect_submodules('scrapy') +
collect_submodules('scrapy.pipelines') +
collect_submodules('scrapy.extensions') +
collect_submodules('scrapy.utils')
)
datas = collect_data_files('scrapy')
After you finished writing a proper build.spec file, all you need to do is run Pyinstaller like this in your shell prompt:
pyinstaller build.spec
Pyinstaller should then spit out a proper build of your program that should work. Problem solved.
You can find that file in scrapy package. Go to this Path: Python/Lib/site-packages/scrapy, and you will find that file. Here are the steps that you are gonna do next:
Go to the directory where your exe file is, and create a folder named scrapy.
Copy VERSION and mime.types from the Path above. (If you don't copy mime.types, there will just be another no such file error. I'm just saving your time)
Paste those two files to the scrapy folder you created in step 1.
Now open your exe file. If No Module Error shows up, you just need to import the corresponding module in the file to which you want to use Pyinstaller.
Good luck. :)
I am having issues getting python to import the _analog_swig gnuradio module in order to run gnuradio code on a Windows 8.1 64bit machine.
Some background: I am running Python 2.7.10 (installed in C:\Python27) and have installed the latest gnuradio binary (v3.7.11.1/v1.3 64-Bit Any CPU) from here: http://www.gcndevelopment.com/gnuradio/downloads.htm. I have installed gnuradio to C:\Program Files\GNURadio-3.7 .
I can run gnuradio companion and run flowgraphs from GRC successfully (which calls "C:\Program Files\GNURadio-3.7\bin\run_gr.bat" gnuradio-companion.py).
I have added & verified the following system variables are set:
Path: C:\Program Files\GNURadio-3.7\bin
PYTHONPATH: C:\Program Files\GNURadio-3.7\lib\site-packages
GRC_BLOCKS_PATH: C:\Program Files\GNURadio-3.7\share\gnuradio\grc\blocks
Now to the problem: If I run e.g. CMD and type:
python C:\test\top_block.py
I am returned the following ImportError:
File "C:\test\top_block.py", line 22, in <module>
from gnuradio import analog
File "C:\Program Files\GNURadio-3.7\lib\site-packages\gnuradio\analog\__init__.py", line 33, in <module>
from analog_swig import *
File "C:\Program Files\GNURadio-3.7\lib\site-packages\gnuradio\analog\analog_swig.py", line 17, in <module>
_analog_swig = swig_import_helper()
File "C:\Program Files\GNURadio-3.7\lib\site-packages\gnuradio\analog\analog_swig.py", line 16, in swig_import_helper
return importlib.import_module('_analog_swig')
File "C:\Python27\lib\importlib\__init__.py", line 37, in import_module
__import__(name)
ImportError: No module named _analog_swig
The folder content of C:\Program Files\GNURadio-3.7\lib\site-packages\gnuradio\analog is as follows:
Comparing this to the folder content on a linux machine, which has a working install of gnuradio that works with python as I want it:
The difference seems to be that the folder in windows contains only a _analog_swig.pyc file, whereas the folder in linux contains a _analog_swig_.so file.
Any idea why the _analog_swig module can apparently not be imported in windows?
My plan is to be able to run gnuradio code directly from my python interpreter and being able to create compiled gnuradio executables so any help on how this could be fixed is much appreciated.
I've been struggling with this for the past few days, but I finally figured it out. I was trying to run GnuRadio Companion generated code in IDLE and also in PyCharm. I kept failing miserably with this same error. I finally figured it out:
-As Flexo says, the PYD file (_analog_swig.pyd) is actually a Windows DLL. The error makes it sound like Python is not finding that file, but that is not at all what was happening. The PYD file, being a DLL, has dependencies itself. Python is able to find _analog_swig.pyd just fine, but it could not find the DEPENDENCIES of that library.
-To verify if that's what wrong in your installation, download and use DependencyWalker (Google it) to check if your system can find the dependencies to _analog_swig.pyd.
-The fix for me was to add the GnuRadio-3.7/bin folder to my PATH environment variable. Inside that folder are a number of DLLs that the _analog_swig.pyd library needs to load. If you don't have the folder in your PATH, the module will fail to load in Python and throw the error you see above.
-I see that you verified that this folder is in your PATH, so this is apparently not the same problem, although your symptoms are exactly the same as mine. i.e. the GRC code would run just fine when you start with "run_gr.bat", but not when you run from a normal CMD window.
Hopefully that helps someone else that wants to use GNURadio Python code on Windows.
Friend,
As you mentioned, the GNU Companion calls \bin\run_gr.bat gnuradio-companion.py. That batch script does quite a bit of work on windows environment variables (try opening it in a text editor if you're curious).
In a sense, the run_gr.bat script puts together a temporary, custom python workspace for gnuradio so it can import anything it needs. It receives python scripts to run in this environment as command line arguments; hence, you can use it to run any GNU radio python code you want in your windows command prompt. Generally, you would call
<gnuradio_install_path>\bin\run_gr.bat <gnu_radio_code>.py
To test your import, you can try
# test.py
from gnuradio import analog
try calling the following from the command prompt, in the test.py directory:
<gnuradio_install_path>\bin\run_gr.bat test.py
I am on Windows 10, I have anaconda installed but I want to create an executable independently in a new, clean minimal environment using python 3.5. So I did some tests:
TEST1:
I created a python script test1.py in the folder testenv with only:
print('Hello World')
Then I created the environment, installed pyinstaller and created the executable
D:\testenv> python -m venv venv_test
...
D:\testenv\venv_test\Scripts>activate.bat
...
(venv_test) D:\testenv>pip install pyinstaller
(venv_test) D:\testenv>pyinstaller --clean -F test1.py
And it creates my test1.exe of about 6 Mb
TEST 2: I modified test1.py as follows:
import pandas as pd
print('Hello World')
I installed pandas in the environment and created the new executable:
(venv_test) D:\testenv>pip install pandas
(venv_test) D:\testenv>pyinstaller --clean -F test1.py
Ant it creates my test1.exe which is now of 230 Mb!!!
if I run the command
(venv_test) D:\testenv>python -V
Python 3.5.2 :: Anaconda custom (64-bit)
when I am running pyinstaller I get some messages I do not understand, for example:
INFO: site: retargeting to fake-dir 'c:\\users\\username\\appdata\\local\\continuum\\anaconda3\\lib\\site-packages\\PyInstaller\\fake-modules'
Also I am getting messages about matplotlib and other modules that have nothing to do with my code, for example:
INFO: Matplotlib backend "pdf": added
INFO: Matplotlib backend "pgf": added
INFO: Matplotlib backend "ps": added
INFO: Matplotlib backend "svg": added
I know there are some related questions:
Reducing size of pyinstaller exe, size of executable using pyinstaller and numpy
but I could not solve the problem and I am afraid I am doing something wrong with respect to anaconda.
So my questions are:
what am I doing wrong? can I reduce the size of my executable?
I accepted the answer above but I post here what I did step by step for complete beginners like me who easily get lost.
Before I begin I post my complete test1.py example script with all the modules I actually need. My apologies if it is a bit more complex than the original question but maybe this can help someone.
test1.py looks like this:
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.image as image
import numpy as np
import os.path
import pandas as pd
import re
from matplotlib.ticker import AutoMinorLocator
from netCDF4 import Dataset
from time import time
from scipy.spatial import distance
from simpledbf import Dbf5
from sys import argv
print('Hello World')
I added matplotlib.use('Agg') (as my actual code is creating figures)
Generating a PNG with matplotlib when DISPLAY is undefined
1) Install a new version of python independently from anaconda.
downloaded python from:
https://www.python.org/downloads/
installed selecting 'add python to path' and deselecting install launcher for all users (I don't have admin rights)
check that I am using the same version from CMD, just writing python I get:
Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017,
06:04:45) [MSC v.1900 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
2) Create and activate the environment, from CMD
D:\> mkdir py36envtest
...
D:\py36envtest>python -m venv venv_py36
...
D:\py36envtest\venv_py36\Scripts>activate.bat
3) Install in the environment all the modules needed in the script
Making sure they are compatible to the python version with the command:
(from Matplotlib not recognized as a module when importing in Python)
(venv_py36) D:\py36envtest> python -m pip install nameofmodule
NB: in my case I also had to add the option --proxy https://00.000.000.00:0000
for the example I used development version of py installer:
(venv_py36) D:\py36envtest> python -m pip install https://github.com/pyinstaller/pyinstaller/archive/develop.tar.gz
and the modules: pandas, matplolib, simpledbf, scipy, netCDF4. At the end my environment looks like this.
(venv_py36) D:\py36envtest> pip freeze
altgraph==0.15
cycler==0.10.0
future==0.16.0
macholib==1.9
matplotlib==2.1.2
netCDF4==1.3.1
numpy==1.14.0
pandas==0.22.0
pefile==2017.11.5
PyInstaller==3.4.dev0+5f9190544
pyparsing==2.2.0
pypiwin32==220
python-dateutil==2.6.1
pytz==2017.3
scipy==1.0.0
simpledbf==0.2.6
six==1.11.0
style==1.1.0
update==0.0.1
4) Create/modify the .spec file (when you run pyinstaller it creates a .spec file, you can rename).
Initially I got a lot of ImportError: DLL load failed (especially for scipy) and missing module error which I solved thanks to these posts:
What is the recommended way to persist (pickle) custom sklearn pipelines?
and the comment to this answer:
Pyinstaller with scipy.signal ImportError: DLL load failed
My inputtest1.spec finally looks like this:
# -*- mode: python -*-
options = [ ('v', None, 'OPTION')]
block_cipher = None
a = Analysis(['test1.py'],
pathex=['D:\\py36envtest', 'D:\\py36envtest\\venv_py36\\Lib\\site-packages\\scipy\\extra-dll' ],
binaries=[],
datas=[],
hiddenimports=['scipy._lib.messagestream',
'pandas._libs.tslibs.timedeltas'],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
name='test1',
debug=False,
strip=False,
upx=True,
runtime_tmpdir=None,
console=True )
5) Finally make the executable with the command
(venv_py36) D:\py36envtest>pyinstaller -F --clean inputtest1.spec
my test1.exe is 47.6 Mb, the .exe of the same script created from an anaconda virtual environment is 229 Mb.
I am happy (and if there are more suggestions they are welcome)
The problem is that you should not be using a virtual environment and especially not anaconda. Please download default python 32 bit and use only necessary modules. Then follow the steps provided in the links, this should definitely fix it.
Although you created a virtual env, are you sure your spec file is not linking to old Anaconda entries?
If all this fails, then submit a bug as this is very strange.
I had a similar problem and found a solution.
I used Windows terminal preview. This program allows creation of various virtual environments like Windows Power Shell (btw. Linux Ubuntu too. Also, worth noting: you can have many terminals in this program installed and, even, open a few at once. Very cool stuff).
Inside Windows Power Shell in Windows terminal preview I installed all the necessary libraries (like numpy, pandas,re, etc.), then I opened the path to my file and tried to use this command:
pyinstaller --onefile -w 'filename.py'
...but, the output exe didn't work. For some reason, the console said that there is a lack of one library (which I had installed earlier). I've found the solution in mimic the auto-py-to-exe library. The command used by this GUI is:
pyinstaller --noconfirm --onedir --console "C:/Users/something/filename.py"
And this one works well. I reduced the size of my output exe program from 911MB to 82,9MB !!!
BTW. 911MB was the size of output made by auto-py-to-exe.
I wonder how is it possible that no one yet has created a compressor that reads the code, checks what libraries are part of the code, then putting only them inside the compression. In my case, auto-py-to-exe probably loaded all libraries that I ever installed. That would explain the size of this compressed folder.
Some suggest using https://virtualenv.pypa.io/en/stable/ but in my opinion, this library is very difficult, at least for me.
I wrote a simple application which uses selenium to nagivate through pages and download their source code. Now I would like to make my application Windows-executable.
My setup.py file:
from distutils.core import setup
import py2exe, sys, os
sys.argv.append('py2exe')
setup(
options = {'py2exe': {'bundle_files': 1,
"dll_excludes": ['w9xpopen.exe', 'MSVCP90.dll', 'mswsock.dll', 'powrprof.dll', 'MPR.dll', 'MSVCR100.dll', 'mfc90.dll'],
'compressed': True,"includes":["selenium"],
}
},
windows = [{'script': "main.py", "icon_resources": [(1, "hacker.ico")]}],
zipfile = None
)
My program (main.py) (with setup.py file) is located in C:\Documents and Settings\student\Desktop. Py2exe builds my exe in C:\Documents and Settings\student\Desktop\dist.
I copied both webdriver.xpi and webdriver_prefs.json files to C:\Documents and Settings\student\Desktop\dist\selenium\webdriver\firefox\, but I'm getting the error when trying to launch my application:
Traceback (most recent call last):
File "main.py", line 73, in <module>
File "main.py", line 58, in check_file
File "main.py", line 25, in try_to_log_in
File "selenium\webdriver\firefox\webdriver.pyo", line 47, in __init__
File "selenium\webdriver\firefox\firefox_profile.pyo", line 63, in __init__
IOError: [Errno 2] No such file or directory: 'C:\\Documents and Settings\\student\\Desktop\\dist\\main.exe\\selenium\\webdriver\\firefox\\webdriver_prefs.json'
How to solve this?
Actually, it worked with such setup.py file:
from distutils.core import setup
import py2exe, sys, os
sys.argv.append('py2exe')
wd_path = 'C:\\Python27\\Lib\\site-packages\\selenium\\webdriver'
required_data_files = [('selenium/webdriver/firefox',
['{}\\firefox\\webdriver.xpi'.format(wd_path), '{}\\firefox\\webdriver_prefs.json'.format(wd_path)])]
setup(
windows = [{'script': "main.py", "icon_resources": [(1, "hacker.ico")]}],
data_files = required_data_files,
options = {
"py2exe":{
"skip_archive": True,
}
}
)
But the problem is I need to build SINGLE executable.
Have you tried to have a look at this answer for the "bundle_files = 1" problems? It helped me solving that specific problem.
TL;DR --Please check out this tool I built: https://github.com/douglasmccormickjr/PyInstaller-Assistance-Tools--PAT
Might I suggest using PyInstaller instead of py2exe or anything else for that matter since PyInstaller does a far better job in terms of bundling a single executable. I'm on Windows about 90% of the time (no complaints here) with my python coding-- PyInstaller is a way better option than py2exe (for me at least -- I've used/test a great deal of Windows compilers in the past with varied success). Maybe other people suffering from compiling issues could benefit from this method as well.
PyInstaller Prerequisites:
Install PyInstaller from: http://www.pyinstaller.org/
After PyInstaller installation-- confirm both "pyi-makespec.exe" and "pyi-build.exe" are in the "C:\Python##\Scripts" directory on your machine
Download my PyInstaller-Assitance-Tools--PAT (it's just 2 batch files and 1 executable with the executable's source python file too -- for the paranoid)...The file are listed above:
Create_Single_Executable_with_NO_CONSOLE.bat
Create_Single_Executable_with_CONSOLE.bat
pyi-fixspec.exe
pyi-fixpec.py (optional -- this is the source file for the executable -- not needed)
Place the exectuable file called "pyi-fixspec.exe" inside the previous "Scripts" folder I mentioned above...this makes compiling much easier in the long run!
let's get it working now...some slight code changes to your python application
I use a standard function that references the location of applications/scripts that my python application needs to utilize to work while being executed/operated. This function operates both when the app is a standalone python script or when it's fully compiled via pyinstaller.
Here's the piece of code I use...
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
if hasattr(sys, '_MEIPASS'):
return os.path.join(sys._MEIPASS, relative_path)
return os.path.join(os.path.abspath("."), relative_path)
and here's my app using it....
source = resource_path("data\my_archive_file.zip")
that means the app/files look something like this in terms of directory structure:
C:\Path\To\Application\myscript_001.py <--- main application/script intended to be compiled
...
C:\Path\To\Application\data\my_archive_file.zip <---|
C:\Path\To\Application\data\images\my_picture.jpg <---| supporting files in the bundled app
C:\Path\To\Application\info\other_stuff.json <---|
...
Please note that the data/files/folders I'm bundling for my app are below the main executable/script that I'll be compiling...the "_MEIPASS" part in the function lets pyinstaller know that it's working as a compiled application...VERY IMPORTANT NOTE: Please use the function "resource_path" since the "pyi-fixspec.exe" application will be looking for that phrase/function while parsing/correcting the python application pathing
Goto the directory containing the 2 batch files mentioned above and type in either:
Option #1
C:\MyComputer\Downloads\PAT> Create_Single_Executable_with_NO_CONSOLE.bat C:\Path\to\the\python\file.py
The output executable file results in a GUI app when double clicked
Option #2
C:\MyComputer\Downloads\PAT> Create_Single_Executable_with_CONSOLE.bat C:\Path\to\the\python\file.py
The output executable file results in a WINDOWS CONSOLE app when double clicked -- expects commandline activity ONLY
Your new single-file-executable is done! Check for it in this location
C:\Original\Directory\ApplicationDistribution64bit\NameOfPythonFile\dist
If you do edit/change the original python file that has just been previously compiled, please delete the folder/contents of **\NameOfPythonFile** prior to next compile kickoff (you'll want to delete the historical/artifact files)
Coffee break -- or if you wany to edit/add ICONS to the executable (and other items too), please look at the generated ".spec" file and PyInstaller documentation for configuration details. You'll just need to kick off this again in the windows console:
pyi-build.exe C:\path\to\the\pythonfile.spec
You can build a single executable, which will run natively, by using Nuitka. It converts the Python code into C++ and then compiles it.
http://nuitka.net/
It does, however, require that you have a compiler installed. The appropriate versions of either Microsoft Visual C++ or GCC. Microsoft released "Microsoft Visual C++ Compiler for Python 2.7", which can be obtained here at https://www.microsoft.com/en-us/download/details.aspx?id=44266.
A nice installer of MinGW GCC for windows can be found at https://github.com/develersrl/gccwinbinaries with detailed instructions, including which MSVCRTXX.dll version to link with for which version of Python.
Things you will gain from this method of executable generation:
Doing this generates machine code, so it will be more difficult, but not impossible, to reverse engineer. Simply using Py2exe or PyInstaller, which are great for their intended use, only packages the byte compiled Python code, which is easily decompiled (http://www.simonroses.com/2013/10/appsec-myths-about-obfuscation-and-reversing-python/), into a zip appended executable.
Your application will also gain a bit of a speed boost. I wrote a blog post about this kind of thing at (I DO NOT receive money from click throughs or ads).
https://jaredfields83.wordpress.com/2015/12/21/squeezing-more-juice-from-python/.
The problem you have is that selenium is trying to open a file in a way that is not directly compatible with py2exe.
As you can see at line 63 here, selenium must open a preferences file that is usually shipped with the package. It uses the __file__ variable to find it, which doesn't play well with py2exe. As you have found, it is possible to work around that by also packaging up the prefs file in your distribution. However, that is now more than one file.
The py2exe wiki then has a recipe to use NSIS that will build a self-extracting executable of your complete distribution.