微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

pyinstaller 可执行文件的差异更新修改嵌入式 PYZ-00.pyz

如何解决pyinstaller 可执行文件的差异更新修改嵌入式 PYZ-00.pyz

我打算创建一个巨大的可执行目录并将其安装在某些设备上。

想象一下,后来我在我的一个 Python 模块中发现了一个错误。 有没有什么办法只传输/复制修改后的字节码,然后用新的字节码替换原来的字节码。

我想这样做的原因是,在我的上下文中带宽非常昂贵,我想远程修补代码

示例:我有一个包含两个文件的项目: prog.py:(以下三行)

import mod1
if __name__ == "__main__":
    mod1.hello()

mod1.py:(以下两行)

def hello():
    print("hello old world")

现在我使用 PYTHONHASHSEED=2 pyinstaller prog.py 创建我的目录并将其复制到我的设备

现在我修改mod1.py

def hello():
    print("hello new world")

然后我用 PYTHONHASHSEED=2 pyinstaller prog.py 重新编译 完整目录(去皮和压缩)大小约为 10M 文件 dist/prog/prog 的大小约为 1M

使用 pyi-archive_viewer 我可以从我的可执行文件 PYZ-00.pyz提取 dist/prog/progPYZ-00.pyz 中,我可以找到并提取仅使用 133 个字节的 mod1

现在,如果我将该文件复制到我的设备上,我该如何更新旧的 dist/prog/prog 这样,它具有新的 PYZ-00.pyz:mod1 字节码。

我可以用什么代码来分解,在替换一个特定的文件(模块)后我可以用什么代码来重新组装?

解决方法

这是一个相当复杂的问题,但我认为这可能至少是您正在寻找的一部分。

根据您的示例,我更改了 prog.py,因此它在从源代码运行时可以正常导入,但在使用 pyinstaller 冻结时直接从 pyc 文件运行。

import sys

def import_pyc(name):
    import py_compile
    import types
    import marshal
    
    pyversion = f"{sys.version_info.major}{sys.version_info.minor}"
    filename = f"{name}.cpython-{pyversion}.pyc"
    
    with open(filename,"rb") as pyc_file:
        # pyc files have 16 bytes reserved at the start in python 3.7+
        # due to https://www.python.org/dev/peps/pep-0552/
        # may change again in the future
        pyc_file.seek(16) 
        code_obj = marshal.load(pyc_file)

    module = types.ModuleType(name)
    exec(code_obj,module.__dict__)

    globals()[name] = module

def import_py(name):
    import importlib
    
    globals()[name] = importlib.import_module("mod1")
    
def import2(name):
    if getattr(sys,"frozen",False):
        import_pyc(name)
    else:
        import_py(name)


import2("mod1")

if __name__ == "__main__":
    mod1.hello()

这很大程度上基于精彩的答案here

这意味着 mod.py 不是由 PyInstaller 打包的,您必须将 mod1.cpython-38.pyc 作为数据文件包含在内。

一种方便的方法是使用命令 PyInstaller --add-data "__pycache__/*;." prog.py(尽管如果您不是在 Windows 上,请将分号切换为冒号)。这会将 __pycache__ 文件夹中的所有内容(所有导入的模块)放入您的结尾 dist/prog 文件夹中。请注意,如果您多次运行此程序,PyInstaller 会将主 python 文件夹的 pyc 放在 __pycache__ 中,以便在后续运行时将其捆绑。

根据您捆绑和运行项目的方式,您可能会遇到当前工作目录关闭的问题,这将导致在您尝试加载 FileNotFound 时出现 pyc。我不能给你一个灵丹妙药来找到你想要的路径,因为这取决于你最终如何做事,但我通常用来找到应该是当前工作目录的绝对路径的方法是 os.path.dirname(sys.executable)os.path.dirname(os.path.abspath(__file__))

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。