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 the include array by traversing my include directory?

0

6 Answers

I'm suprised that no one mentioned the official supported option using Tree():

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')
2

The problem is easier than you can imagine

try this: --add-data="path/to/folder/*;."

hope it helps !!!

1

Yes, you can just add directories to the Analysis object and they get copied across.

a = Analysis(['main.py'],
             datas = [('test/dir', 'test/dir')],
             ...)
1

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Marcus Vance

Marcus Vance

Cybersecurity & Digital Privacy Researcher

Marcus Vance is a cybersecurity auditor and technology writer dedicated to educating the public about online safety, data privacy regulations, enterprise security, and emerging cyber threats.

Share this article
Twitter Facebook Pinterest