ejecutar codigo python exception swig

codigo - ejecutar c en python



¿Cómo puedo propagar las excepciones de C++ a Python en una biblioteca de contenedor SWIG? (5)

Sé que esta pregunta tiene algunas semanas pero la encontré mientras investigaba una solución para mí. Así que voy a echar una ojeada a una respuesta, pero advertiré de antemano que puede no ser una solución atractiva, ya que los archivos de la interfaz de intercambio pueden ser más complicados que la codificación manual del contenedor. Además, hasta donde puedo decir, la documentación del trago nunca trata directamente con las excepciones definidas por el usuario.

Digamos que desea lanzar la siguiente excepción desde su módulo de código c ++, mylibrary.cpp, junto con un pequeño mensaje de error para que quede atrapado en su código python:

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

MyException es una excepción de usuario definida en otro lugar.

Antes de comenzar, anote cómo se debe capturar esta excepción en su python. Para nuestros propósitos aquí, digamos que tienes código python como el siguiente:

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

Creo que esto describe tu problema.

Mi solución consiste en hacer cuatro adiciones a su archivo de interfaz swig (mylibrary.i) de la siguiente manera:

Paso 1: en la directiva de encabezado (el bloque usualmente sin nombre% {...%}) agregue una declaración para el puntero a la excepción de python aware, que llamaremos pMyException. El paso 2 a continuación definirá esto:

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

Paso 2: Agregue una directiva de inicialización (la "m" es particularmente atroz, pero eso es lo que swig v1.3.40 necesita actualmente en ese punto en su archivo envoltorio construido) - pMyException se declaró en el paso 1 anterior:

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

Paso 3: Como se mencionó en una publicación anterior, necesitamos una directiva de excepción: la nota "% except (python)" está en desuso. Esto ajustará la función c +++ "do_something" en un bloque try-except que captura la excepción c ++ y la convierte a la excepción python definida en el paso 2 anterior:

%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*);

Paso 4: Debido a que Swig configura una envoltura de Python (un módulo ''sombra'') alrededor de la .pyd dll, también necesitamos asegurarnos de que nuestro código python pueda ''ver a través'' del archivo .pyd. Lo siguiente funcionó para mí y es preferible editar el código swig py wrapper directamente:

%pythoncode %{ MyException = _mylibrary.MyException %}

Es probable que sea demasiado tarde para ser de gran utilidad para el póster original, pero tal vez alguien más encuentre útiles las sugerencias anteriores. Para trabajos pequeños, puede preferir la limpieza de una envoltura de extensión de c ++ codificada a mano a la confusión de un archivo de interfaz swig.

Adicional:

En mi listado de archivo de interfaz anterior, omití la directiva de módulo estándar porque solo quería describir las adiciones necesarias para que las excepciones funcionen. Pero su línea de módulo debería verse así:

%module mylibrary

Además, su setup.py (si está utilizando distutils, que recomiendo al menos para comenzar) debería tener un código similar al siguiente; de ​​lo contrario, el paso 4 fallará cuando _mylibrary no se reconozca:

/* 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"],)

Tenga en cuenta la bandera de compilación / EHsc, que necesitaba en Windows para compilar excepciones. Su plataforma puede no requerir esa bandera; google tiene los detalles.

He probado el código usando mis propios nombres que he convertido aquí en "mylibrary" y "MyException" para ayudar a generalizar la solución. Con suerte, los errores de transcripción son pocos o ninguno. Los puntos principales son las directivas% init y% pythoncode junto con

static PyObject* pMyException;

en la directiva de encabezado.

Espero que aclare la solución.

Estoy escribiendo un contenedor SWIG en torno a una biblioteca C ++ personalizada que define sus propios tipos de excepción C ++. Los tipos de excepciones de la biblioteca son más completos y específicos que las excepciones estándar. (Por ejemplo, una clase representa errores de análisis y tiene una colección de números de línea.) ¿Cómo puedo propagar esas excepciones de vuelta a Python conservando el tipo de excepción?



De la documentación del trago

%except(python) { try { $function } catch (RangeError) { PyErr_SetString(PyExc_IndexError,"index out-of-bounds"); return NULL; } }


Agregaré un poco aquí, ya que el ejemplo dado aquí ahora dice que "% except (python)" está en desuso ...

Ahora puede (a partir del swig 1.3.40, de todos modos) hacer una traducción totalmente genérica, independiente del lenguaje de script. Mi ejemplo sería:

%exception { try { $action } catch (myException &e) { std::string s("myModule error: "), s2(e.what()); s = s + s2; SWIG_exception(SWIG_RuntimeError, s.c_str()); } catch (myOtherException &e) { std::string s("otherModule error: "), s2(e.what()); s = s + s2; SWIG_exception(SWIG_RuntimeError, s.c_str()); } catch (...) { SWIG_exception(SWIG_RuntimeError, "unknown exception"); } }

Esto generará una excepción RuntimeError en cualquier lenguaje de scripting soportado, incluyendo Python, sin obtener cosas específicas de Python en sus otros encabezados.

Debe poner esto antes de las llamadas que quieren este manejo de excepciones.


U también puede usar:

capturas: http://www.swig.org/Doc3.0/SWIGPlus.html#SWIGPlus_catches

Ejemplo:

%catches(std::exception, std::string, int, ...);

que genera para cada función un bloque try catch:

try { result = (namespace::Function *)new namespace::Function ((uint16_t const *)arg1); } catch(std::exception &_e) { SWIG_exception_fail(SWIG_SystemError, (&_e)->what()); } catch(std::string &_e) { SWIG_Python_Raise(SWIG_From_std_string(static_cast< std::string >(_e)), "std::string", 0); SWIG_fail; } catch(int &_e) { SWIG_Python_Raise(SWIG_From_int(static_cast< int >(_e)), "int", 0); SWIG_fail; } catch(...) { SWIG_exception_fail(SWIG_RuntimeError,"unknown exception"); }