首页 > 解决方案 > 忽略导入中的异常并继续模块的其余部分?

问题描述

我正在开发的 python 包有一个依赖项(pyfluidsynth),它通过在导入时抛出 AttributeError 来破坏我的系统。Pyfluidsynth 是 C 库“fluidsynth”的包装器,它破坏的原因是它试图包装库中不存在的几个 C 函数,至少对于我系统上的流体合成器版本。

这些是有问题的代码行:

fluid_synth_set_reverb_full = cfunc('fluid_synth_set_reverb_full', c_int,
                                    ('synth', c_void_p, 1),
                                    ('set', c_int, 1),
                                    ('roomsize', c_double, 1),
                                    ('damping', c_double, 1),
                                    ('width', c_double, 1),
                                    ('level', c_double, 1))

fluid_synth_set_chorus_full = cfunc('fluid_synth_set_chorus_full', c_int,
                                    ('synth', c_void_p, 1),
                                    ('set', c_int, 1),
                                    ('nr', c_int, 1),
                                    ('level', c_double, 1),
                                    ('speed', c_double, 1),
                                    ('depth_ms', c_double, 1),
                                    ('type', c_int, 1))

...我得到的错误是:

AttributeError:/lib64/libfluidsynth.so.1:未定义符号:fluid_synth_set_reverb_full

它很容易修复:我不使用该功能,所以我可以在我的流体合成库副本中用 try/except 包围这两个语句。但是在分发我自己的包时,我不能依赖 pypi 中的 pyfluidsynth 版本,因为它至少会在某些人的机器上崩溃。

这个问题已经提交了,但是pyfluidsynth的开发者还没有修复它。同时,有没有一种方法可以导入 pyfluidsynth 以便它捕获异常,忽略它们,然后继续导入模块的其余部分?

标签: pythonexceptionimport

解决方案


您可以分叉 pyfluidsynth 并依赖它,直到它得到修复。这可能是比猴子补丁更好的选择。如果你不想把它放在 PyPI 上,Pip 可以安装托管在 GitHub 上的包。使用git+https存储库(和分支,如有必要)的 URL,而不仅仅是包名称。


也就是说,您可能可以使用unittest.mock.patch替换ctypes.CFUNCTYPE为返回包装函数原型的版本,该原型在这些情况下检查fluid_synth_set_reverb_fullfluid_synth_set_chorus_full并返回一个虚拟值,但在其他情况下委托给真正的原型。

也许像

from unittest.mock import patch
from cytpes import CFUNCTYPE

def patched_CFUNCTYPE(*args):
    real_prototype = None
    def wrapped_prototype(*a):
        nonlocal real_prototype
        if a[0][0] in {
            'fluid_synth_set_reverb_full',
            'fluid_synth_set_chorus_full',
        }:
            return None
        if not real_prototype:
            real_prototype = CFUNCTYPE(*args)
        return real_prototype(*a)
    return wrapped_prototype

try:
    import fluidsynth
except AttributeError:
    with patch('ctypes.CFUNCTYPE', patched_CFUNCTYPE):
        import fluidsynth

没有测试过这个。


推荐阅读