简体   繁体   English

PyInstaller 致命错误:无法执行脚本

[英]PyInstaller fatal error: Failed to execute script

First of all, I want to apologize for the very long question but this is driving me crazy.首先,我想为这个很长的问题道歉,但这让我发疯了。 Saturday I have to exhibit this project to my school's open day and I have little to no time.星期六我必须在学校的开放日展示这个项目,我几乎没有时间。

I've written a snake game in Python 3.9 with a friend (using Pygame) and I'm trying to create an executable file with PyInstaller from it (using multiple python modules and additional files such as images and music), but every time I execute the command pyinstaller Game.spec and I try to run the executable I get this error:我和一个朋友(使用 Pygame)在 Python 3.9 中编写了一个蛇游戏(使用 Pygame),我正在尝试使用 PyInstaller 从它创建一个可执行文件(使用多个 python 模块和附加文件,如图像和音乐),但每次我执行命令pyinstaller Game.spec并尝试运行可执行文件我收到此错误:

PyInstaller 错误窗口

This error is very unexpected and strange to me because I already made it executable about a week ago (but it was an older version and we change lots of things) in the same way and it worked flawlessly, but now it won't work in any way, we tried everything and read every post here on Stack, so the executable gets created but it won't start.这个错误对我来说非常出乎意料和奇怪,因为我已经在大约一周前以相同的方式使其可执行(但它是一个较旧的版本,我们更改了很多东西)并且它完美地工作,但现在它无法工作无论如何,我们尝试了所有方法并阅读了 Stack 上的每一篇文章,因此创建了可执行文件,但它不会启动。

GIF Converter Module GIF 转换器模块

We changed really a lot of things since we made the first executable, but the structure of the code remained pretty much the same with the only exception of a module that I wrote, basically it automatically splits animated GIFs into separated frames and loads them into Pygame (loading every single frame by hand was too time-wasting...).自从我们制作了第一个可执行文件以来,我们确实改变了很多东西,但代码的结构几乎保持不变,唯一的例外是我编写的一个模块,基本上它会自动将动画 GIF 分割成单独的帧并将它们加载到 Pygame (手动加载每一帧太浪费时间了......)。 I suspect that this module might be one of the causes that ultimately lead to prompting that error every time I try to execute the game.我怀疑这个模块可能是最终导致我每次尝试执行游戏时都会提示该错误的原因之一。 We used this module to animate the buttons in the main menu:我们使用此模块为主菜单中的按钮设置动画:

pyWormy 菜单

How does it work?它是如何工作的?

from PIL import Image
import sys
import os
import pygame  

class PyGimager:
def __init__(self, gif):
    # Loading the desired gif image
    self.gif = Image.open(gif)

    # Variable where all the frames will be stored
    self.frames = []

    self.assetFrames_url = []

# This method divides all the frames of the gif in a .png file (in a desired folder)
def deconstructGif(self, mainName='decImage', savePath='LOCAL'):
    path = savePath + "/" + mainName
    self.assetFrames_url.append(resource_path(path))
    local = True

    if savePath != 'LOCAL':
        try:
            os.makedirs(savePath)
        except OSError as error:
            print("Path creation failed: {}".format(error))
        local = False

    for i in range(self.gif.n_frames):
        self.gif.seek(i)
        if not local:
            self.gif.save(savePath + mainName + '{}.png'.format(i), 'PNG')
        else:
            self.gif.save(mainName + '{}.png'.format(i))

# loads all the frames in a bidimensional array
def gifLoader(self, loadPath="/"):
    frame = ''
    if loadPath == "/":
        for image in os.listdir():
            if image.endswith(".png"):
                frame = pygame.image.load(image)
                self.frames.append(frame)
    else:
        for image in os.listdir(loadPath):
            if image.endswith(".png"):
                frame = pygame.image.load(loadPath + image)
                self.frames.append(frame)

def gifPlayer(self, screen, position=def_position, wait=500):
    for frame in self.frames:
        AnimatedSprite = frame
        screen.blit(AnimatedSprite, position)
        pygame.time.wait(wait)
        pygame.display.update()

def getFirstFrame(self):
    return self.frames[0]  

Sorry for the messy code but I had to learn OOP in about 3 days to write all of this and I am still a bit confused.抱歉代码乱七八糟,但我必须在大约 3 天的时间里学习 OOP 才能写出所有这些,我仍然有点困惑。 Anyway, the attributes of the class are pretty much self-explanatory, gif contains the desired animated image given by the user, the frames array will contain all the images extracted from the animated gif while assetFrames_url is a copy of frames containing the relative paths, we used it to bypass another bug in PyInstaller which didn't allow us to add our files to Game.spec , so we had to pass through this function all the additional files, here's the source of this function.无论如何,class 的属性几乎是不言自明的, gif包含用户提供的所需动画图像, frames数组将包含从动画 gif 中提取的所有图像,而assetFrames_url是包含相对路径的frames的副本,我们用它绕过了 PyInstaller 中的另一个错误,该错误不允许我们将文件添加到Game.spec ,所以我们必须通过这个 function 的所有附加文件,这里是这个 function 的来源

We had to write by hand (I tried to automate it with a script but it was a huge failure) the path of every single additional element inside Game.spec .我们不得不手动编写Game.spec中每一个附加元素的路径(我试图用一个脚本来自动化它,但这是一个巨大的失败)。 With the method deconstructGif the gif gets split (one image for each frame) in a specific folder, then all the split frames are loaded inside the frames array with the gifLoader method and finally they get animated with the method gifPlayer .使用deconstructGif方法,gif 在特定文件夹中被分割(每帧一个图像),然后使用 gifLoader 方法将所有分割帧加载到frames组中,最后使用gifLoader方法对它们进行动画gifPlayer

For example, these are the folders of the animated buttons:例如,这些是动画按钮的文件夹:

纽扣

Game.spec游戏规范

When we compiled the first executable we had to manually insert the path for each file inside an array of tuples.当我们编译第一个可执行文件时,我们必须手动将每个文件的路径插入到元组数组中。 This is the last version:这是最后一个版本:

        # -*- mode: python ; coding: utf-8 -*-

block_cipher = None


a = Analysis(['Game.py'],
             pathex=['C:\\Users\\gianm\\Documents\\GitKraken\\pyWormy'],
             binaries=[],
             datas=[
             ('Img/Buttons/Hard/HardButton0.png','Img/Buttons/Hard/'),('Img/Buttons/Hard/HardButton1.png','Img/Buttons/Hard/'),
             ('Img/Buttons/Easy/EasyButton0.png','Img/Buttons/Easy/'),('Img/Buttons/Easy/EasyButton1.png','Img/Buttons/Easy/'),
             ('Img/Buttons/Options/OptionsButton0.png','Img/Buttons/Options/'),('Img/Buttons/Options/OptionsButton1.png','Img/Buttons/Options/'),
             ('Img/Buttons/Play/PlayButton0.png','Img/Buttons/Play/'),('Img/Buttons/Play/PlayButton1.png','Img/Buttons/Play/'),
             ('Img/Buttons/Exit/ExitButton0.png','Img/Buttons/Exit/'),('Img/Buttons/Exit/ExitButton1.png','Img/Buttons/Exit/'),
             ('Img/Buttons/BackToMenu/BacktoMenuButton0.png','Img/Buttons/BackToMenu/'),('Img/Buttons/BackToMenu/BacktoMenuButton1.png','Img/Buttons/BackToMenu/'),
             ('SF_Pixelate.ttf','.'),
             ('Sounds/difficileSottofondo.wav','Sounds/'),('Sounds/facileSottofondo.wav','Sounds/'),('Sounds/lose.wav','Sounds/'),('Sounds/slurp.wav','Sounds/'),('Sounds/musica.wav','Sounds/'),
             ('Img/background.png','Img/'),('Img/GameOver.png','Img/'),('Img/startMenu.png','Img/'), 
             ('Img/Sprites/Sprites3/CorpoSerpente.png','Img/Sprites/Sprites3/'),
             ('Img/Sprites/Sprites3/TestaDestra.png','Img/Sprites/Sprites3/'), ('Img/Sprites/Sprites3/TestaGiu.png','Img/Sprites/Sprites3/'),('Img/Sprites/Sprites3/TestaSinistra.png','Img/Sprites/Sprites3/'),('Img/Sprites/Sprites3/TestaSopra.png','Img/Sprites/Sprites3/'),
             ('Img/Sprites/Sprites3/Mela/C.png','Img/Sprites/Sprites3/Mela/'),('Img/Sprites/Sprites3/Mela/Ruby.png','Img/Sprites/Sprites3/Mela/'),('Img/Sprites/Sprites3/Mela/PHP.png','Img/Sprites/Sprites3/Mela/'),('Img/Sprites/Sprites3/Mela/JS.png','Img/Sprites/Sprites3/Mela/'), 
             ('Img/Buttons/Hard.gif','Img/Buttons/'),('Img/Buttons/Easy.gif','Img/Buttons/'),('Img/Buttons/Options.gif','Img/Buttons/'),('Img/Buttons/Exit.gif','Img/Buttons/'), 
             ('Img/Buttons/BackToMenu.gif','Img/Buttons/'),('Img/Buttons/Play.gif','Img/Buttons/'),  
             
             ],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          [],
          name='pyWormy',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          upx_exclude=[],
          runtime_tmpdir=None,
          console=False , icon='Icon.ico')

Inside the datas array, I inserted a tuple for each file, the first argument is the relative path of the image while the second is the relative path of the folder.datas数组中,我为每个文件插入了一个元组,第一个参数是图像的相对路径,第二个参数是文件夹的相对路径。 The local paths are represented by a point ('.').本地路径由点 ('.') 表示。

Things I've tried:我尝试过的事情:

  • First of all, I tried to locate the "source" of the problem, so I opened the .spec file generated with the execution of the command pyinstaller -i Icon.Ico --onefile Game.py (with Ico.ico being the icon of the executable and Game.py the main module) and I activated the console debug, like this:首先,我试图找到问题的“根源”,所以我打开了执行命令pyinstaller -i Icon.Ico --onefile Game.py生成的.spec文件(其中 Ico.ico 是图标可执行文件和 Game.py 主模块),我激活了控制台调试,如下所示:

     console=True, icon='Icon.ico')

This is the error that i get in detail:这是我详细得到的错误:

命令错误

  • I tried to pass in the data array the path for all the frames, it didn't work.我试图在数据数组中传递所有帧的路径,但没有成功。
  • I tried to pass in the paths of all the GIFs, it didn't work.我试图传递所有 GIF 的路径,但没有成功。

I apologize if this question may seem confusing and if the grammar is really bad but English is not my primary language and I need to fix this fast and I don't have time to correct all the mistakes.如果这个问题可能看起来令人困惑,并且语法真的很糟糕,但英语不是我的主要语言,我需要快速解决这个问题,我没有时间纠正所有错误,我深表歉意。 Thanks in advance!提前致谢!

Finally, I managed to solve this.最后,我设法解决了这个问题。

Basically, there is a compatibility issue between Pygame and PIL (Python Imaging Library), I had to rewrite the entire pyGimager class and I was not able to make a single executable file but in the end, it works.基本上,Pygame 和 PIL(Python 图像库)之间存在兼容性问题,我不得不重写整个 pyGimager class 并且我无法制作单个可执行文件,但最终它可以工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM