All of the documentation for Pyinstaller talks about including individual files.
Is it possible to include a directory, or should I write a function to create the include array by traversing my include directory?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
I’m suprised that no one mentioned the official supported option using Tree():
https://stackoverflow.com/a/20677118/2230844
https://pyinstaller.readthedocs.io/en/stable/advanced-topics.html#the-toc-and-tree-classes
Method 2
Paste the following after a = Analysis() in the spec file to traverse a directory recursively and add all the files in it to the distribution.
##### include mydir in distribution #######
def extra_datas(mydir):
def rec_glob(p, files):
import os
import glob
for d in glob.glob(p):
if os.path.isfile(d):
files.append(d)
rec_glob("%s/*" % d, files)
files = []
rec_glob("%s/*" % mydir, files)
extra_datas = []
for f in files:
extra_datas.append((f, f, 'DATA'))
return extra_datas
###########################################
# append the 'data' dir
a.datas += extra_datas('data')
Method 3
The problem is easier than you can imagine
try this:
--add-data="path/to/folder/*;."
hope it helps !!!
Method 4
Yes, you can just add directories to the Analysis object and they get copied across.
a = Analysis(['main.py'],
datas = [('test/dir', 'test/dir')],
...)
Method 5
What about just using glob?
from glob import glob
datas = []
datas += glob('/path/to/filedir/*')
datas += glob('/path/to/textdir/*.txt')
...
a.datas = datas
Method 6
The accepted answer works fine if your folder doesn’t have any subfolders. However, if you folder does have any subfolders, all data will be collapsed into the your ‘dir_to_include’ path, which will mess up your imports. The below is an example, where main.py accesses music and pictures from the data folder.
. ├── data │ ├── music │ │ ├── music1.mp3 │ ├── pics │ │ ├── pic1.png │ │ ├── pic2.png │ │ ├── numbers │ │ │ ├── 0.png │ │ │ ├── 1.png │ │ │ ├── 2.png ├── main.py ├── main.spec
In this case, after we generated our main.spec file using pyinstaller main.py, we can change some arguents inside the main.spec file.
On the top of the main.spec, our we set our added_files:
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
added_files = [
('./data/*.*', 'data'),
('./data/pics/*.*', 'data/pics'),
('./data/music/*.*', 'data/music'),
('./data/pics/numbers/*.*', 'data/pics/numbers'),
]
...
Then, we set datas=added_files below:
...
a = Analysis(
['main.py'],
pathex=[],
binaries=[],
datas=added_files,
...
We have to add the path for each individual subfolder, or else they won’t get added by pyinstaller automatically. If we simply do added_files = '[(./data/*', data')], then all the pictures and audio will be added to the ‘data’ directory, which is not what we want. Thus, we use path/*.*, so folders don’t get added recursively, and define each subfolder manually.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0