我可以告诉PyInstaller打包我的整个源代码树吗?

时间:2015-11-02 13:09:23

标签: python pyinstaller python-3.5

目前我的PyInstaller规范看起来像这样:

import sys
import os
import re
from pathlib import Path

DEBUG = True

lib = Path("lib/alpha")

hidden_imports = []
hidden_imports += lib.glob("processes/**/*.py")
hidden_imports += lib.glob("ui/config_panels/**/*.py")
hidden_imports += lib.glob("ui/logic/**/*.py")
hidden_imports = list(str(x) for x in hidden_imports)

for index, path in enumerate(hidden_imports):
    path = re.sub(r"lib(\\|\/)", "", path)

    if "__init__.py" in path:
        path = re.sub(r"(\\|\/)__init__.py", "", path)
    else:
        path = re.sub(r"\.py", "", path)

    hidden_imports[index] = ".".join(re.split(r"\\|\/", path))

block_cipher = None

a = Analysis(
    ["app.pyw"],
    pathex=["lib"],
    binaries=None,
    datas=[
        ("icons/*", "icons")
    ],
    hiddenimports=hidden_imports,
    hookspath=None,
    runtime_hooks=None,
    excludes=None,
    win_no_prefer_redirects=None,
    win_private_assemblies=None,
    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="alpha",
    debug=DEBUG,
    strip=None,
    upx=True,
    console=DEBUG,
    icon="icons\\foo.ico"
)

丑陋,对吧?

我的源代码树中有一些目录,其文件名遵循特定的命名约定,并使用importlib按需导入。出于显而易见的原因,我不想将所有这些模块的名称硬编码到我的规范中。

当使用“hiddenimports”选项时,参数必须是模块名称列表,因此我必须glob获取文件名,循环结果列表并“模块化”文件名,考虑Windows和Linux支持。

必须有更好的方法。有什么方法可以告诉PyInstaller只包含我的整个源代码树,即lib/alpha下的每个文件?

1 个答案:

答案 0 :(得分:0)

您可以使用Tree() function包含整个目录树,但这不会完全符合您的要求。由于您正在添加源文件,因此您需要PyInstaller以递归方式对其进行分析,以确保包含所有依赖项。最好的方法是通过hiddenimports。

我不会详细解释,而是从我自己的specfile中共享一个片段,我用它来包含我的应用程序不直接包含的模块,但是提供给用户创建的插件使用。这非常适合您的用例。

# Files under mcedit2.synth are used only by plugins and not internally.
support_modules = []
for root, dirnames, filenames in os.walk(os.path.join('src', 'mcedit2', 'synth')):
    for filename in fnmatch.filter(filenames, '*.py'):
        if filename == "__init__.py":
            filepath = root
        else:
            filepath = os.path.join(root, filename)
            filepath = filepath[:-3]  # discard ".py"

        components = filepath.split(os.path.sep)
        components = components[1:]  # discard 'src/'

        if "test" in components or components == ["mcedit2", "main"]:
            continue

        modulename = ".".join(components)  # dotted modulename
        support_modules.append(modulename)

hiddenimports.extend(support_modules)