Estoy escribiendo un contenedor SWIG en torno a una biblioteca personalizada de C++ 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?¿Cómo se propagan las excepciones de C++ a Python en una biblioteca de contenedor SWIG?
Respuesta
Desde el swig documentation
%except(python) {
try {
$function
}
catch (RangeError) {
PyErr_SetString(PyExc_IndexError,"index out-of-bounds");
return NULL;
}
}
¿Está el swig exception documentation ayuda? Menciona defining different exception handlers ..
Sé que esta pregunta tiene algunas semanas pero la encontré porque estaba buscando 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 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 usted quiere lanzar la siguiente excepción de su C++ módulo de código, mylibrary.cpp, junto con un mensaje de error poco de estar atrapado en su código Python:
throw MyException("Highly irregular condition..."); /* C++ code */
MiExcepción es una excepción definida por el usuario en otra parte.
Antes de comenzar, anote cómo se debe capturar esta excepción en su python. Para nuestros propósitos aquí, digamos que tiene código python como el siguiente:
import mylibrary
try:
s = mylibrary.do_something('foobar')
except mylibrary.MyException, e:
print(e)
Creo que esto describe su problema.
Mi solución consiste en realizar cuatro adiciones a su archivo de interfaz trago (mylibrary.i) de la siguiente manera:
Paso 1: En la directiva de encabezado (el% por lo general no identificado {...}% bloque) añadir una declaración para el puntero a la excepción de python aware, que llamaremos pMyException. Paso 2 a continuación va a 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: Agregar una directiva inicialización (la "m" es particularmente atroz, pero eso es lo swig v1.3.40 actualmente necesita en ese momento en su archivo de envoltura construida) - pMyException fue declarado 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 un post anterior, necesitamos una directiva excepción - en cuenta "% excepto (pitón)" está en desuso. Esto envolver el +++ función c "hacer_algo" en un try-excepto bloque que atrapa el C++ excepción y la convierte en la excepción pitón 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 trago establece un pitón envolviendo (un módulo 'sombra') alrededor de .pyd dll, también necesitamos asegurarnos de que nuestro código python pueda 'ver a través' del archivo .pyd. Los siguientes trabajó para mí y es preferible editar el código trago py envoltorio directamente:
%pythoncode %{
MyException = _mylibrary.MyException
%}
Es probable que sea demasiado tarde para ser de mucha utilidad para el cartel original, pero tal vez alguien más va a encontrar las sugerencias anteriores de alguna utilidad .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.
Agregado:
En mi archivo de interfaz lista anterior, que omite la directiva módulo estándar porque yo sólo quería describir las adiciones necesarias para hacer excepciones funcionan. Sin embargo, su línea de módulo debe verse como:
%module mylibrary
Además, su setup.py (si está utilizando distutils, que recomiendo al menos para empezar) debe tener un código similar al siguiente, de lo contrario el paso 4 se producirá un error cuando _mylibrary no se reconoce:
/* 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"],)
Nota de 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.
Esto parece muy prometedor, lo intentaré. No es demasiado tarde, por cierto, porque por ahora solo estamos detectando RuntimeError y examinando el texto de los mensajes de error - ¡puaj! – Barry
Es más genérico reemplazar "return NULL" que después de llamar "PyErr_SetString" en su ejemplo con una macro llamada "SWIG_fail", que siempre debería funcionar, es decir, independientemente del tipo de datos devuelto. – Hermes
Voy a añadir un poco aquí, ya que el ejemplo dado aquí ahora dice que "a excepción% (pitón)" es obsoleta ...
Ahora puede (a partir de trago 1.3.40, de todos modos) hacer una traducción totalmente genérica, independiente de las secuencias de comandos. 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 programación compatible, incluyendo Python, sin conseguir la materia específica de pitón en sus otras cabeceras.
Debe poner este antes de las llamadas que desean este manejo de excepciones.
+1, solo hay que asegurarse de tener% incluir excepción.i en su archivo de interfaz SWIG (introduciendo la macro SWIG_exception) –
U también puede utilizar:
capturas: http://www.swig.org/Doc3.0/SWIGPlus.html#SWIGPlus_catches
Ejemplo:
%catches(std::exception, std::string, int, ...);
que genera para cada función de un bloque catch try:
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");
}
-1: Esto no funciona, Python se cuelga. '% capturas' no es suficiente a menos que especifique' throw() 'dentro de las declaraciones de funciones. Y el '% de capturas' es superfluo en ese caso. La documentación vinculada de SWIG solo menciona el uso de la directiva '% capturas' junto con un nombre de función. – Melebius
% atrapa en realidad "excepciones envueltas" más funciones envueltas en swims luego% excepción. – hugo24
- 1. SWIG: Informar excepciones Python del código C++
- 2. Contenedor C++ a C usando SWIG (para FLTK)
- 3. Excepciones que no se propagan desde una llamada a un método reflejado en C#
- 4. Cómo manejar excepciones de C++ a través de SWIG a Java
- 5. Crear un contenedor para una biblioteca C en Python
- 6. ¿Cómo puedo descifrar un objeto de C++ desde un contenedor SWIG de python?
- 7. ¿Cómo paso las matrices de Java a C++ usando Swig?
- 8. Accediendo a typedef de C++ en Python usando SWIG
- 9. ¿Cómo se modifican las funciones en tiempo de ejecución y luego se propagan a varios subprocesos?
- 10. Contenedor de Python para la biblioteca UDT C++
- 11. Envolver una clase de C++ en Python usando SWIG
- 12. Se detectó fuga de memoria Swig/Python
- 13. Hacer un contenedor Objective-C para una biblioteca en C++
- 14. Enlazar una biblioteca de Python TO C
- 15. ¿Cómo se detectan las excepciones en una implementación de EventMachine?
- 16. C#: ¿Cómo manejar las excepciones del finalizador de una biblioteca de terceros?
- 17. Python: excepciones en las asignaciones
- 18. ¿Cuáles son las mejores prácticas al usar SWIG con C#?
- 19. Clase/biblioteca de contenedor para C
- 20. Asignación de matriz de tipo SWIG C++ desde Python
- 21. depurando una biblioteca compartida envuelta por SWIG en perl
- 22. depuración extensiones para Python swig
- 23. Escribir un contenedor C++ para una biblioteca C
- 24. ¿Cómo puedo encontrar una lista de todas las excepciones que arroja una función de biblioteca dada en Python?
- 25. Captura de todas las excepciones en Python
- 26. SWIG Python Structure Array
- 27. Una pregunta trivial de error de SWIG de Python
- 28. ¿Cómo generar una interfaz multiplataforma con SWIG?
- 29. Python función de devolución de llamada ctypes a SWIG
- 30. ¿Cómo puedo generar C wrappers sobre API C++ utilizando SWIG?
Esto está cerca. Conserva el tipo de la excepción, pero ¿cómo encapsulo tipos de excepción personalizados? Tal vez los ejemplos de SWIG lo cubran. – Barry