我如何在SWIG包装库中将C ++异常传播到Python?

问题描述 投票:32回答:6

我正在围绕自定义C ++库编写SWIG包装程序,该库定义了自己的C ++异常类型。该库的异常类型比标准异常更丰富,更具体。 (例如,一个类表示解析错误并具有行号的集合。)如何在保留异常类型的同时将这些异常传播回Python?

python exception swig
6个回答
21
投票

我知道这个问题已有几个星期了,但是我在为自己研究解决方案时才发现它。因此,我将回答一个问题,但我会提前警告说,这可能不是一个有吸引力的解决方案,因为Swig接口文件比手工编写包装器要复杂得多。而且,据我所知,swig文档从不直接处理用户定义的异常。

假设您要从c ++代码模块mylibrary.cpp中抛出以下异常,并在Python代码中捕获一些错误消息:

throw MyException("Highly irregular condition...");  /* C++ code */

MyException是在其他地方定义的用户异常。

开始之前,请注意如何在python中捕获此异常。就我们的目的而言,假设您有以下类似的python代码:

import mylibrary
try:
    s = mylibrary.do_something('foobar')
except mylibrary.MyException, e:
    print(e)

我认为这描述了您的问题。

我的解决方案包括对swig接口文件(mylibrary.i)进行以下四个添加:

步骤1:在标头指令(通常为未命名的%{...%}块)中,为指向python感知异常的指针添加一个声明,我们将其称为pMyException。下面的第2步将对此进行定义:

%{
#define SWIG_FILE_WITH_INIT  /* for eg */
extern char* do_something(char*);   /* or #include "mylibrary.h" etc  */
static PyObject* pMyException;  /* add this! */
%}

步骤2:添加一个初始化指令(“ m”特别糟糕,但这是swig v1.3.40当前在其构造好的包装文件中所需要的)-pMyException在上面的步骤1中声明:

%init %{
    pMyException = PyErr_NewException("_mylibrary.MyException", NULL, NULL);
    Py_INCREF(pMyException);
    PyModule_AddObject(m, "MyException", pMyException);
%}

步骤3:如先前的文章所述,我们需要一个异常指令-注意“%except(python)”已被弃用。这会将c +++函数“ do_something”包装在try-except块中,该块捕获c ++异常并将其转换为上述步骤2中定义的python异常:

%exception do_something {
    try {
        $action
    } catch (MyException &e) {
        PyErr_SetString(pMyException, const_cast<char*>(e.what()));
        SWIG_fail;
    }
}

/* The usual functions to be wrapped are listed here: */
extern char* do_something(char*);

第4步:由于swig在.pyd dll周围设置了python包装(“阴影”模块),因此我们还需要确保python代码可以“透视”到.pyd文件。以下对我有用,最好直接编辑swig py包装器代码:

%pythoncode %{
    MyException = _mylibrary.MyException
%}

现在可能已经太晚了,无法对原始海报有用,但是也许其他人会在上面找到一些有用的建议。对于小型工作,您可能更喜欢手工编码的c ++扩展包装程序的简洁性,而不是swig接口文件的混乱。


添加:

在上面列出的接口文件中,我省略了标准模块指令,因为我只想描述使异常起作用所需的附加内容。但是您的模块行应如下所示:

%module mylibrary

此外,您的setup.py(如果您正在使用distutils,我建议至少开始使用它)应该具有类似于以下的代码,否则当无法识别_mylibrary时,步骤4将失败:

/* setup.py: */
from distutils.core import setup, Extension

mylibrary_module = Extension('_mylibrary', extra_compile_args = ['/EHsc'],
                    sources=['mylibrary_wrap.cpp', 'mylibrary.cpp'],)

setup(name="mylibrary",
        version="1.0",
        description='Testing user defined exceptions...',
        ext_modules=[mylibrary_module],
        py_modules = ["mylibrary"],)

注意编译标志/ EHsc,我在Windows上需要用它来编译异常。您的平台可能不需要该标志;谷歌有详细信息。

我已经使用自己的名称测试了代码,在这里我将其转换为“ mylibrary”和“ MyException”以帮助推广解决方案。希望转录错误很少或没有。要点是%init和%pythoncode指令以及

static PyObject* pMyException;

在标头指令中。

希望阐明解决方案。


12
投票

我将在此处添加一点,因为此处给出的示例现在说“%except(python)”是不推荐使用...


0
投票


0
投票

example.h


-1
投票

U也可以使用:

© www.soinside.com 2019 - 2024. All rights reserved.