Including a Directory Using Pyinstaller
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...
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?
6 Answers
I'm suprised that no one mentioned the official supported option using Tree():
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')
The problem is easier than you can imagine
try this:
--add-data="path/to/folder/*;."
hope it helps !!!
Yes, you can just add directories to the Analysis object and they get copied across.
a = Analysis(['main.py'],
datas = [('test/dir', 'test/dir')],
...)
What about just using glob?
from glob import glob
datas = []
datas += glob('/path/to/filedir/*')
datas += glob('/path/to/textdir/*.txt')
...
a.datas = datas
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.