I\'ve begun using Pyinstaller over Py2Exe. However I\'ve rather quickly run into a problem. How do I exclude modules that I don\'t want, and how do I view the ones that are
Although better solutions may have been given but there is one more method: You can use the '--exclude-module' attribute with the 'pyinstaller' command but this method is quite lengthy when you have to exclude many modules.
To make the work easier, you can write a batch script file with all the libraries worth skipping and use it again and again.
Something like this:
@echo off
pyinstaller --onefile a.py --exclude-module matplotlib ^
--exclude-module scipy ^
--exclude-module setuptools ^
--exclude-module hook ^
--exclude-module distutils ^
--exclude-module site ^
--exclude-module hooks ^
--exclude-module tornado ^
--exclude-module PIL ^
--exclude-module PyQt4 ^
--exclude-module PyQt5 ^
--exclude-module pydoc ^
--exclude-module pythoncom ^
--exclude-module pytz ^
--exclude-module pywintypes ^
--exclude-module sqlite3 ^
--exclude-module pyz ^
--exclude-module pandas ^
--exclude-module sklearn ^
--exclude-module scapy ^
--exclude-module scrapy ^
--exclude-module sympy ^
--exclude-module kivy ^
--exclude-module pyramid ^
--exclude-module opencv ^
--exclude-module tensorflow ^
--exclude-module pipenv ^
--exclude-module pattern ^
--exclude-module mechanize ^
--exclude-module beautifulsoup4 ^
--exclude-module requests ^
--exclude-module wxPython ^
--exclude-module pygi ^
--exclude-module pillow ^
--exclude-module pygame ^
--exclude-module pyglet ^
--exclude-module flask ^
--exclude-module django ^
--exclude-module pylint ^
--exclude-module pytube ^
--exclude-module odfpy ^
--exclude-module mccabe ^
--exclude-module pilkit ^
--exclude-module six ^
--exclude-module wrapt ^
--exclude-module astroid ^
--exclude-module isort
Or you can always use a new python installation, just change the path of the new python installation while installing.
Just to summarise the options here as I use them.
PyInstaller TOC's - are, as the documentation says:
A TOC appears to be a list of tuples of the form (name, path, typecode). In fact, it's an ordered set, not a list. A TOC contains no duplicates, where uniqueness is based on name only.
In otherwords, simply:
a_toc = [('uname1','/path/info','BINARY'),('uname2','/path/to','EXTENSION')...]
So, in your .spec file - once you've got the Analysis results of the script - you can then further modify the respective TOC's by either:
For specific files/modules use the difference (-) and intersection (+) operations to modify a TOC. *
For adding/removing lists of files/modules iterate over the the TOC and compare with pattern matching code.
(* As an aside, for the difference to work it seems you must explicitly cast to TOC()
and note that since it is only the name that uniquely defines the element of the set, you only need to specify that - hence ('sqlite3', None, None)
etc.)
An illustrative example (taken from a .spec file) is below where - for better or worse - I remove all references to scipy, IPython and zmq; delete specific sqlite, tcl/tk and ssl .DLL's; insert a missing opencv .DLL; and finally remove all data folders found apart from matplotlib ones...
Whether the resulting Pyinstaller .exe will then work when an .pyc file tries to load an expected .DLL is moot:-/
# Manually remove entire packages...
a.binaries = [x for x in a.binaries if not x[0].startswith("scipy")]
a.binaries = [x for x in a.binaries if not x[0].startswith("IPython")]
a.binaries = [x for x in a.binaries if not x[0].startswith("zmq")]
# Target remove specific ones...
a.binaries = a.binaries - TOC([
('sqlite3.dll', None, None),
('tcl85.dll', None, None),
('tk85.dll', None, None),
('_sqlite3', None, None),
('_ssl', None, None),
('_tkinter', None, None)])
# Add a single missing dll...
a.binaries = a.binaries + [
('opencv_ffmpeg245_64.dll', 'C:\\Python27\\opencv_ffmpeg245_64.dll', 'BINARY')]
# Delete everything bar matplotlib data...
a.datas = [x for x in a.datas if
os.path.dirname(x[1]).startswith("C:\\Python27\\Lib\\site-packages\\matplotlib")]
You can manipulate the lists produced by the Analysis class using Python. Note that these are in PyInstaller's TOC format.
a = Analysis(...)
...
# exclude anything from the Windows system dir
a.binaries = [x for x in a.binaries if not
os.path.dirname(x[1]).startswith("C:\\Windows\\system32")]
I've seen a lot of questions like this, but no one teaches you how to debug by yourself.
document of pyinstaller may have useful for beginner, but once you need more ...
personally, think the pyinstaller documentation is not friendly (Too few examples) and lacks updates.
for example, The document shows the version of the pyinstaller is 3.2. (3.5 is available now (2019/10/5))
I want to say that you should find the answer from source code
# run_pyinstaller.py
from PyInstaller.__main__ import run
run()
before you run this script you can assign parameters, like "--clean your.spec"
set breakpoint at {env_path}/Lib/site-packages/PyInstaller/building/build_main.py -> def build(...) ... -> exec(code, spec_namespace)
like below:
note: If you are not using the virtual environment, the actual path should be {Python}/Lib/site-packages/PyInstaller/building/build_main.py
then you can watch any variables that you interested in.
also, you will learn more about pyinstaller.exe actually do what.
for example, you learn the class of TOC is inherits to list, and see more the detail than the document from PyInstaller.building.datastruct
eventually, you can use any python way to set a.binaries
and a.datas
that is you really wanted
from PyInstaller.building.datastruct import TOC, Tree
from PyInstaller.building.build_main import Analysis
from PyInstaller.building.api import EXE, PYZ, COLLECT, PKG, MERGE