Pyinstaller:试图排除子文件夹中的所有模块,但 pyinstaller 仍然继续编译它们

Pyinstaller: trying to exclude all modules in subfolder, but pyinstaller keeps compiling them in anyway

我目前正在尝试在 python 中实现纸牌游戏,我的计划是通过编译主应用程序来尝试对用户友好,而不要求用户拥有 python安装,但也通过允许编译的应用程序从特定子文件夹加载未编译的 python 文件,以合理可访问的方式支持用户修改。到目前为止,这在未编译的应用程序中运行良好。

但是,我无法让 pyinstaller 停止包含需要与编译的应用程序分开的 python 文件。

文件:

main.py
gameobj.py
data\gamedata.py
data\ais\ai.py
data\ais\dummy.py
data\effects\effect.py
data\effects\haunt.py
data\powers\power.py
data\powers\lore.py
data\spells\spell.py
data\spells\bottomlesspit.py

每个子文件夹中还有 __init__.py 个文件,但它们只是为了方便导入内容,不包含任何内容。

理想情况下,数据子文件夹中的任何内容都不应编译为可执行文件,而应作为数据文件包含在内; gamedata.py 处理加载内容,包括用户添加的额外内容。 目前,据我所知,使用以下 pyinstaller 命令(或其变体),gamedata.py 及其导入的任何内容都被编译:

pyinstaller -n Game --exclude-module gamedata --add-data "res;res" --add-data "data;data" --noconfirm main.py

在 运行 这个命令之后,我可以进入 dist\Game\data\ais\dummy.py 并更改分配给 AI 名称的值,它仍然会打印预编译版本。

我尝试排除数据、游戏数据、ais、效果、力量、法术。我不确定排除所有单个数据文件(lore.py 或 haunt.py 之类的文件)是否可行,因为我确实计划拥有更多类似稍后设置的文件,只要 gamedata.py 似乎正在被编译,无论如何它都没有实际意义;用户将无法指定更多要加载的内容。如果我能让 pyinstaller 忽略它,我将有一个(可能是 hacky)解决方案,即在没有大部分数据文件夹的情况下进行编译,然后将其余部分复制到文件夹中在 dist.


mnd.py 目前主要包含测试内容。

from gameobj import *
import data.gamedata as gamedata

# Testing power
lore_test = gamedata.lore.Lore()
print(lore_test.get_desc())

# Testing effect
haunt_test = gamedata.haunt.Haunt()
print(haunt_test.get_desc())

# Testing spell
bottomlesspit_test = gamedata.bottomlesspit.BottomlessPit()
print(bottomlesspit_test.name)

# testing AI
dummy_ai = gamedata.dummy.Dummy()
print(dummy_ai.name)

gamedata.py 是用户应该能够指定要从中导入的文件的地方。对于以上内容,我目前正在导入它。

import sys
sys.path.append(".\data")

from powers import lore

from effects import haunt

from spells import bottomlesspit

from ais import dummy

作为它导入的文件之一的示例,它们的结构如下:

from .ai import AI

class Dummy(AI):
    def __init__(self):
        super().__init__("DummyAI")

    def phase_setup(self):
        super().phase_setup()

    def phase_energize(self):
        super().phase_energize()

    def phase_prs_one(self):
        super().phase_prs_one()

    def phase_attack(self):
        super().phase_attack()

    def phase_creatures(self):
        super().phase_creatures()

    def phase_prs_two(self):
        super().phase_prs_two()

    def phase_draw(self):
        super().phase_draw()

从ai.py获得AI:

from abc import ABC, abstractmethod

class AI(ABC):
    @abstractmethod
    def __init__(self, name):
        self.name = name
        self.player = None

    @abstractmethod
    def phase_setup(self):
        # draw up to 5 cards
        # intended to be called after AI chooses whether to take starter cards
        while len(self.player.hand) < 5:
            self.player.deck.draw()
        self.player.match.next_phase()

    @abstractmethod
    def phase_energize(self):
        if self.player.match.turn != 0:
            self.player.magi.energize()
        self.player.match.next_phase()

    @abstractmethod
    def phase_prs_one(self):
        self.player.match.next_phase()

    @abstractmethod
    def phase_attack(self):
        self.player.match.next_phase()

    @abstractmethod
    def phase_creatures(self):
        self.player.match.next_phase()

    @abstractmethod
    def phase_prs_two(self):
        self.player.match.next_phase()

    @abstractmethod
    def phase_draw(self):
        self.player.draw(2)
        self.player.match.next_phase()

gameobj.py 包含游戏对象。不确定它是否相关,不会从项目本身导入任何东西。不过,如果有人认为相关,可以编辑其中的内容。

最终,我必须做的是:

  1. 将整个数据文件夹移动到一个单独的项目中,阻止 pyinstaller 获取它。 Pyinstaller 只能访问 main.py 和 gameobj.py.

  2. 更改 main.py 查找导入的方式:

import sys
sys.path.append(".\data")
sys.path.append(".\data\powers")
sys.path.append(".\data\effects")
sys.path.append(".\data\spells")
sys.path.append(".\data\ais")

from gameobj import *
import data.gamedata as gamedata

可能并非所有都是绝对必要的。其他一切都和以前一样。

  1. gamedata.py稍作修改如下:
from data.powers import lore
from data.effects import haunt
from data.spells import bottomlesspit
from data.ais import dummy
  1. 运行 pyinstaller 使用以下命令: pyinstaller -n Game --exclude-module gamedata --noconfirm main.py

  2. 运行安装pyinstaller后,复制data文件夹到dist\Game和运行Game.exe。尽管 gamedata.py 未与 main.py 和 gameobj.py 冻结,应用程序仍将 运行 通过使用数据文件夹中的内容的测试,并将获取所做的更改到那些文件。