Py2App 在 Zip 文件中放置 PIL Dylibs

Py2App Placing PIL Dylibs in Zip file

我有一个 python 应用程序,它使用 Python 图像库 (PIL) 并使用 Py2app 打包。 Numpy dylib 位于应用内容目录中:

demo.app/Contents/Resources/lib/python3.8/numpy/.dylibs/libgcc_s.1.dylib

可以在其中搜索和签名,但 PIP 动态库位于 python3.8.zip 文件中

demo.app/Contents/Resources/lib/python3.zip -> ./PIL/.dylibs/libfreetype.6.dylib

其中必须解压缩、签名并重新压缩它们。为什么会发生这种情况,我该如何预防才能避免另眼相待?

py2app 通过一种称为 "recipes". It comes with built-in recipes for certain packages including numpy, which is why numpy is excluded from the .zip file. (Here's the built-in numpy recipe.)

的机制实现对某些包的特殊处理

除了内置的食谱外,您还可以define your own recipes供py2app使用。只需定义一个具有 check 方法的 class,并将其作为属性猴子修补到 py2app.recipes:

# In setup.py

class PIL_recipe:
    def check(self, cmd, mf):
        m = mf.findNode("PIL")
        if m is None or m.filename is None:
            return None

        # Exclude from site-packages.zip
        return {"packages": ["PIL"]}

py2app.recipes.PIL = PIL_recipe()

...

setup(...)

如果您需要对多个库执行此操作,您可以推广这个技巧,这样它就不会对包的名称进行硬编码:

class ExcludeFromZip_Recipe(object):
    def __init__(self, module):
        self.module = module

    def check(self, cmd, mf):
        m = mf.findNode(self.module)
        if m is None:
            return None

        # Don't put the module in the site-packages.zip file
        return {"packages": [self.module]}

for module in ['PIL', 'skimage', 'sklearn', 'jsonschema']:
    setattr( py2app.recipes, module, ExcludeFromZip_Recipe(module) )

免责声明:这就是我过去解决这个问题的方法。但我不确定为什么你的 zip 文件被命名为 python3.zip 而不是 site-packages.zip.