首先加入3个库的钩子 hook
hook-Orange
from PyInstaller.utils.hooks import copy_metadata from PyInstaller.utils.hooks import collect_data_files from PyInstaller.utils.hooks import collect_submodules from PyInstaller.utils.hooks import collect_all datas, binaries, hiddenimports = collect_all("Orange") datas += copy_metadata('Orange3') # datas += collect_data_files("Orange") # hiddenimports = collect_submodules('Orange')
hook-orangecanvas
from PyInstaller.utils.hooks import copy_metadata from PyInstaller.utils.hooks import collect_data_files from PyInstaller.utils.hooks import collect_submodules from PyInstaller.utils.hooks import collect_all datas, binaries, hiddenimports = collect_all("orangecanvas") datas += copy_metadata('orange_canvas_core') # datas += collect_data_files("orangecanvas") # hiddenimports = collect_submodules('orangecanvas')
hook-orangewidget
from PyInstaller.utils.hooks import copy_metadata from PyInstaller.utils.hooks import collect_data_files from PyInstaller.utils.hooks import collect_submodules from PyInstaller.utils.hooks import collect_all datas, binaries, hiddenimports = collect_all("orangewidget") datas += copy_metadata('orange_widget_base') # datas += collect_data_files("orangewidget") # hiddenimports = collect_submodules('orangewidget')
保证不缺文件
改动入口文件 Orange3/canvas/__main__
def resource_path(relative_path): if getattr(sys, 'frozen', False): # 是否Bundle Resource base_path = sys._MEIPASS else: base_path = os.path.abspath(".") return os.path.join(base_path, relative_path)
解决临时temp位置读取问题
539行
if pkg_resources.resource_exists(pkg_name, resource):
开始,打包后pkg_resources功能使用有错误,需要修改为手动读取
with open(resource_path(pkg_name + '/' + resource)) as f: stylesheet_string = f.read() base = resource_path(os.getcwd() + '\\' + pkg_name + '\\' + "styles") pattern = re.compile( r"^\s@([a-zA-Z0-9_]+?)\s*:\s*([a-zA-Z0-9_/]+?);\s*$", flags=re.MULTILINE ) matches = pattern.findall(stylesheet_string) for prefix, search_path in matches: QDir.addSearchPath(prefix, os.path.join(base, search_path)) log.info("Adding search path %r for prefix, %r", search_path, prefix) stylesheet_string = pattern.sub("", stylesheet_string) dirpath = resource_path(os.getcwd() + '\\' + pkg_name) QDir.addSearchPath("canvas_icons", os.path.join(dirpath, "icons"))
然后spec打包配置文件需要修改,解决剩余问题
# -*- mode: python ; coding: utf-8 -*- block_cipher = None import pkg_resources import os hook_ep_packages = dict() hiddenimports = set() # List of packages that should have there Distutils entrypoints included. ep_packages = ["orange.widgets"] if ep_packages: for ep_package in ep_packages: for ep in pkg_resources.iter_entry_points(ep_package): if ep_package in hook_ep_packages: package_entry_point = hook_ep_packages[ep_package] else: package_entry_point = [] hook_ep_packages[ep_package] = package_entry_point package_entry_point.append("{} = {}".format(ep.name, ep.module_name)) hiddenimports.add(ep.module_name) try: os.mkdir('./generated') except FileExistsError: pass 解决pkg_resources.iter_entry_points问题,生成在线运行钩子文件 with open("./generated/pkg_resources_hook.py", "w") as f: f.write("""# Runtime hook generated from spec file to support pkg_resources entrypoints. ep_packages = {} if ep_packages: import pkg_resources default_iter_entry_points = pkg_resources.iter_entry_points def hook_iter_entry_points(group, name=None): if group in ep_packages and ep_packages[group]: eps = ep_packages[group] for ep in eps: parsedEp = pkg_resources.EntryPoint.parse(ep) parsedEp.dist = pkg_resources.Distribution(project_name='Orange3',version='3.27.1') yield parsedEp else: return default_iter_entry_points(group, name) pkg_resources.iter_entry_points = hook_iter_entry_points """.format(hook_ep_packages)) a = Analysis(['run.py'], pathex=['C:\\Users\\Lenovo\\PycharmProjects\\pythonProject'], binaries=[], datas=[], hiddenimports=list(hiddenimports)+['sklearn.utils._weight_vector','openTSNE._matrix_mul.matrix_mul'],解决部分组件缺失包问题 hookspath=[], runtime_hooks=["./generated/pkg_resources_hook.py"],在线运行钩子文件 excludes=[], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, noarchive=False) remove = ["_simple_tree", "_tree_scorers", "_contingency", "_io", "_valuecount", "_variable", "_distance", "_discretize", "_relieff", "_som", "_grid_density"] temp=a.binaries[:] for t in temp: if any(r+'.cp37-win_amd64.pyd' in t[1] for r in remove): print('Removing'+ t[1]) a.binaries.remove(t)移除无效pyd文件,解决运行前warning提示对话框问题 pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) exe = EXE(pyz, a.scripts, a.binaries, a.zipfiles, a.datas, [], name='run', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, upx_exclude=[], runtime_tmpdir=None, console=False , icon='favicon.ico')加入打包程序图标