• pyinstaller打包包含celery任务的项目总是失败解决方式


    当我们在使用pyinstaller打包发布包含celery任务的项目时,如果出现项目打包成功了,但是运行的时候只要开启celery进程报错:exe:maximum recursion depth exceeded while calling a Python object…,即使通过sys.setrecursionlimit设置系统最大递归深度也解决不了问题时,莫慌,我教你怎么解决。

    ps:为防止某些大聪明照搬下面代码编译出现问题,我先将注意事项交代在前,项目根目录下最好别在dist文件夹下存放代码文件,因为下面的解决方式中,构建编译文件时会自动覆盖这个文件夹下的所有文件,如果你的项目根目录下有这两个文件夹,请修改为其他名称!!!

    OK,我们正式进入主题。首先,在你的项目根目录(与入口相同目录)下新建build.py(该文件名称可自由命名)文件,如下:
    在这里插入图片描述
    build.py文件中输入以下代码:

    #!/usr/bin/env python
    # cython: language_level=3
    # -*- coding: utf-8 -*-
    # @Author  : LuBowen
    # @Number  : 20210509
    # @FileName  :build
    # @Time      :2023/9/7 13:37
    # @Software: PyCharm Community Edition
    # @Version : Python3
    # ====================================
    from subprocess import call
    from distutils.core import setup
    from Cython.Build import cythonize
    import os
    import shutil
    from tqdm import tqdm
    
    # 用于编译的工程根目录绝对路径(此处替换为你的项目根目录-即入口文件所在目录的绝对路径)
    project_dir = "D:/projectsFiles/vision"
    # 非编译文件绝对路径-包含的文件将不会被编译,并会在项目编译完成后直接复制到编译后的项目目录中(如果你的项目中存在不需要编译的python文件或者其他文件,请将其绝对路径放到下面的列表中,这些文件将不会被编译且会在项目编译完成后自动复制到编译后的项目包/文件夹中)
    include_files = [
            "D:/projectsFiles/vision/.env",
            "D:/projectsFiles/vision/DockerFile",
            "D:/projectsFiles/vision/r.txt",
    ]
    
    
    # noinspection PyMissingOrEmptyDocstring
    def collect_file(project_path, direct_name=None, file_end=('pyd', 'o'), include=()):
        project_path_direct_name = os.path.basename(project_path)
        if not direct_name:
            direct_name = project_path_direct_name
        base_path = f'{project_path}/dist/{direct_name}'.replace('\\', '/')
        for root, dirs, files in os.walk(project_path):
            root_format = str(root).replace('\\', '/')
            if base_path in f'{root_format}/{direct_name}':
                continue
            if os.path.abspath('./build').replace('\\', '/') in root_format:
                continue
            if os.path.abspath('./dist').replace('\\', '/') in root_format:
                continue
            if '__pycache__' in root_format:
                continue
            files = tqdm(files)
            for file in files:
                files.set_description(f'Collecting compiled file:{root_format}')
                if str(file).split('.')[-1] in file_end or f'{root_format}/{file}' in include:
                    current_file = f'{root_format}/{file}'
                    target_direct = root_format.replace(str(project_path), base_path, 1)
                    if not os.path.exists(target_direct):
                        os.makedirs(target_direct)
                    shutil.copy(current_file, target_direct)
    
    
    # noinspection PyMissingOrEmptyDocstring
    def clear_file(project_path, file_end=('pyd', 'o', 'c', 'pyc'), direct_name=None, exclude=()):
        project_path_direct_name = os.path.basename(project_path)
        if not direct_name:
            direct_name = project_path_direct_name
        base_path = f'{project_path}/dist/{direct_name}'.replace('\\', '/')
        for root, dirs, files in os.walk(project_path):
            root_format = str(root).replace('\\', '/')
            if base_path in f'{root_format}/{direct_name}':
                continue
            if os.path.abspath('./build').replace('\\', '/') in root_format:
                continue
            if os.path.abspath('./dist').replace('\\', '/') in root_format:
                continue
            files = tqdm(files)
            for file in files:
                files.set_description(f'Clear:{root_format}')
                if f'{root_format}/{file}' in exclude:
                    continue
                if str(file).split('.')[-1] in file_end:
                    current_file = f'{root_format}/{file}'
                    os.remove(current_file)
    
    
    # noinspection PyMissingOrEmptyDocstring
    def compiling(project_path, direct_name=None, exclude=()):
        compile_file_set = set()
        project_path_direct_name = os.path.basename(project_path)
        if not direct_name:
            direct_name = project_path_direct_name
        base_path = f'{project_path}/dist/{direct_name}'.replace('\\', '/')
        for root, dirs, files in os.walk(project_path):
            root_format = str(root).replace('\\', '/')
            if base_path in f'{root_format}/{direct_name}':
                continue
            if os.path.abspath('./build').replace('\\', '/') in root_format:
                continue
            if os.path.abspath('./dist').replace('\\', '/') in root_format:
                continue
            if '__pycache__' in root_format:
                continue
            target_path = root_format.replace(str(project_path), base_path, 1)
            if not os.path.exists(target_path):
                os.makedirs(target_path)
            files = tqdm(files)
            for file in files:
                files.set_description(f'Collecting python file:{root_format}')
                if str(file).endswith('.py') and f'{root_format}/{file}' not in exclude:
                    compile_file_set.add(f'{root_format}/{file}')
        print(f'Collected python file number:{len(compile_file_set)}')
        setup(ext_modules=cythonize(compile_file_set))
    
    
    # noinspection PyMissingOrEmptyDocstring
    def pyinstaller_cmd_para(server_file, app_name):
    	#""" 
    	#	如果编译后运行时,报错:ModuleNotFoundError: No module named '模块名'
    	#	先在项目环境中导入:pip install 模块名
    	#	然后将
    	#	'--hidden-import', '模块名',
    	#	加入到cmd中,注意看示例!
    	#"""
        cmd = ['pyinstaller',
               '-y',
               f'{server_file}.py',
               '--name', f'{app_name}',
               '--hidden-import', 'celery.app.events',
               '--hidden-import', 'celery.backends.redis',
               '--hidden-import', 'celery.backends',
               '--hidden-import', 'celery.fixups',
               '--hidden-import', 'celery.app.amqp',
               '--hidden-import', 'kombu.transport.redis',
               '--hidden-import', 'celery.fixups.django',
               '--hidden-import', 'celery.concurrency.gevent',
               '--hidden-import', 'celery.apps.worker',
               '--hidden-import', 'engineio.async_gevent',
               '--hidden-import', 'gevent',
               '--hidden-import', 'psycopg2',
               '--hidden-import', 'pymysql',
               '--hidden-import', 'celery.app.log',
               '--hidden-import', 'celery.worker.components',
               '--hidden-import', 'celery.worker.autoscale',
               '--hidden-import', 'celery.worker.consumer',
               '--hidden-import', 'celery.app.control',
               '--hidden-import', 'celery.events.state',
               '--hidden-import', 'celery.worker.strategy',
               '--hidden-import', 'skimage',
               ]
        call(cmd)
    
    
    # noinspection PyMissingOrEmptyDocstring
    def build(entry_file, app_name):
        pyinstaller_cmd_para(entry_file, app_name)
        compiling(project_path=project_dir, direct_name=app_name)
        collect_file(project_path=project_dir, direct_name=app_name, include=include_files)
        clear_file(project_path=project_dir, direct_name=app_name)
        print('completed!')
    
    
    if __name__ == '__main__':
    	#此处两个参数为:入口文件名称,编译后的项目名称
        build('startup', 'startup')
        # 终端输入指令:python build.py build_ext --inplace开始编译
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159

    保存上面的代码文件,开启终端,进入到项目根目录,输入python build.py(请将此python文件名称替换为你自己命名的文件名) build_ext --inplace回车开始编译,如:
    在这里插入图片描述
    等待编译完成,如下:
    在这里插入图片描述
    显示如下表示完成:
    在这里插入图片描述
    根目录下会出现build/文件夹和dist/文件夹,其中dist文件夹下就是打包完成的项目了,如下:
    在这里插入图片描述
    在这里插入图片描述
    至此,项目打包完成!

  • 相关阅读:
    flutter开发实战-video_player播放多个视频MediaCodecVideoRenderer error问题
    GitLab CI/CD关键词(十五):服务 services,秘钥sercets,DAST配置dast_configuration
    第七节.常用Linux命令—查找文件,软硬链接,软件安装,系统信息
    【软考 系统架构设计师】案例分析⑥ Web应用系统架构设计
    mysql5.7数据库安装及性能测试
    【数据结构】建立二叉树以及哈夫曼树及哈夫曼编码
    Elasticsearch(三) Python 使用 elasticsearch 的基本操作
    第二十二篇:稳定性之服务等级协议
    Chrome之解决DevTools: Failed to load data:No resource with given identifier found
    #AcWing--合并两个排序的链表
  • 原文地址:https://blog.csdn.net/qq_38226778/article/details/132968043