tipos excepciones diferentes python c++ exception boost boost-python

diferentes tipos de excepciones en python



Manejo de excepciones polimórficas: ¿cómo detectar la excepción de subclase? (2)

Mis habilidades con Python están oxidadas y no lo he probado, por lo que es posible que necesiten más mejoras, pero intente agregar el método de traducción de excepción para manejar el tipo de excepción de la clase base:

static PyObject *clusterExecutionAsClusterExceptionType = NULL; static void translateClusterExecutionAsClusterException(ClusterException const &exception) { ClusterExecutionException* upcasted = dynamic_cast<ClusterExecutionException*>(&exception); if (upcasted) { assert(clusterExecutionAsClusterExceptionType != NULL); boost::python::object pythonExceptionInstance(*upcasted); PyErr_SetObject(clusterExecutionAsClusterExceptionType, pythonExceptionInstance.ptr()); } } register_exception_translator<ClusterException>(&translateClusterExecutionAsClusterException);

Tengo la siguiente jerarquía simple de dos excepciones de C ++:

class LIB_EXP ClusterException : public std::exception { public: ClusterException() { } ClusterException(const std::string& what) { init(what); } virtual const char* what() const throw() { return what_.c_str(); } virtual ~ClusterException() throw() {} virtual ClusterException* clone() { return new ClusterException(*this); } protected: void init(const std::string& what) { what_ = what; } private: std::string what_; }; class LIB_EXP ClusterExecutionException : public ClusterException { public: ClusterExecutionException(const std::string& jsonResponse); std::string getErrorType() const throw() { return errorType_; } std::string getClusterResponse() const throw() { return clusterResponse_; } virtual ~ClusterExecutionException() throw() {} virtual ClusterExecutionException* clone() { return new ClusterExecutionException(*this); } private: std::string errorType_; std::string clusterResponse_; };

Luego los exporto a Python con Boost-Python de la siguiente manera. Tenga en cuenta mi uso de las bases para asegurarse de que la relación de herencia se conserve en la traducción:

class_<ClusterException> clusterException("ClusterException", no_init); clusterException.add_property("message", &ClusterException::what); clusterExceptionType = clusterException.ptr(); register_exception_translator<ClusterException>(&translateClusterException); class_<ClusterExecutionException, bases<ClusterException> > clusterExecutionException("ClusterExecutionException", no_init); clusterExecutionException.add_property("message", &ClusterExecutionException::what) .add_property("errorType", &ClusterExecutionException::getErrorType) .add_property("clusterResponse", &ClusterExecutionException::getClusterResponse); clusterExecutionExceptionType = clusterExecutionException.ptr(); register_exception_translator<ClusterExecutionException>(&translateClusterExecutionException);

Entonces el método de traducción de excepción:

static PyObject *clusterExceptionType = NULL; static void translateClusterException(ClusterException const &exception) { assert(clusterExceptionType != NULL); boost::python::object pythonExceptionInstance(exception); PyErr_SetObject(clusterExceptionType, pythonExceptionInstance.ptr()); } static PyObject *clusterExecutionExceptionType = NULL; static void translateClusterExecutionException(ClusterExecutionException const &exception) { assert(clusterExecutionExceptionType != NULL); boost::python::object pythonExceptionInstance(exception); PyErr_SetObject(clusterExecutionExceptionType, pythonExceptionInstance.ptr()); }

Creé la siguiente función C ++ de prueba que arroja las excepciones:

static void boomTest(int exCase) { switch (exCase) { case 0: throw ClusterException("Connection to server failed"); break; case 1: throw ClusterExecutionException("Error X while executing in the cluster"); break; default: throw std::runtime_error("Unknown exception type"); } }

Finalmente, el código de prueba de Python que llama a mi C ++ boomTest :

import cluster reload(cluster) from cluster import ClusterException, ClusterExecutionException def test_exception(exCase): try: cluster.boomTest(exCase) except ClusterException as ex: print ''Success! ClusterException gracefully handled:'' / ''/n message="%s"'' % ex.message except ClusterExecutionException as ex: print ''Success! ClusterExecutionException gracefully handled:'' / ''/n message="%s"'' / ''/n errorType="%s"'' / ''/n clusterResponse="%s"'' % (ex.message, ex.errorType, ex.clusterResponse) except: print ''Caught unknown exception: %s "%s"'' % (sys.exc_info()[0], sys.exc_info()[1]) def main(): print ''/n************************ throwing ClusterException ***********************************************************************'' test_exception(0) print ''/n************************ throwing ClusterExecutionException **************************************************************'' test_exception(1) print ''/n************************ throwing std::runtime_error *********************************************************************'' test_exception(2) if __name__ == "__main__": main()

Hasta aquí todo funciona. Sin embargo, si ClusterExecutionException controlador de captura de ClusterExecutionException de Python, esta excepción se detectará y se ClusterExecutionException a una excepción desconocida en lugar de ser capturada como su ClusterException base.

He intentado en Boost-Python al registrar la traducción de excepción de ClusterExecutionException para registrarla como su ClusterException base y luego queda atrapada "polimórficamente", pero luego no se ClusterExecutionException como ClusterExecutionException . ¿Cómo se puede hacer para que ClusterExecutionException quede atrapada como ClusterException y ClusterExecutionException ? Por supuesto, he intentado registrar esta excepción ClusterExecutionException como ClusterException y ClusterExecutionException pero sigue una última estrategia de ganancias, y solo una funciona, no ambas.

¿Hay alguna otra forma de resolver esto?

ACTUALIZACIÓN 1: El verdadero grial de este problema es descubrir en el lado de C ++ el tipo de la declaración except Python, por ejemplo, except ClusterException as ex: que es desconocida una vez dentro del lado de C ++. La excepción se traduce por Boost.Python llamará a la función de traducción que corresponde al tipo dinámico de la excepción y el tipo estático de captura de Python no se conoce.

ACTUALIZACIÓN 2: Como se sugiere cambiar el código de Python a lo siguiente, es decir, agregar print(type(ex).__bases__) da:

def test_exception(exCase): try: cluster.boomTest(exCase) except ClusterException as ex: print(type(ex).__bases__) print ''Success! ClusterException gracefully handled:'' / ''/n message="%s"'' % ex.message except ClusterExecutionException as ex: print(type(ex).__bases__) print ''Success! ClusterExecutionException gracefully handled:'' / ''/n message="%s"'' / ''/n errorType="%s"'' / ''/n clusterResponse="%s"'' % (ex.message, ex.errorType, ex.clusterResponse) except: print ''Caught unknown exception: %s "%s"'' % (sys.exc_info()[0], sys.exc_info()[1])

y el resultado:

************************ throwing ClusterException *********************************************************************** (<type ''Boost.Python.instance''>,) Success! ClusterException gracefully handled: message="Connection to server failed" ************************ throwing ClusterExecutionException ************************************************************** (<class ''cluster.ClusterException''>,) Success! ClusterExecutionException gracefully handled: message="Error X while executing in the cluster" errorType="LifeCycleException" clusterResponse="{ "resultStatus": "Error", "errorType": "LifeCycleException", "errorMessage": "Error X while executing in the cluster" }"

Lo que significa que la relación de herencia se "ve" desde Python. Pero el manejo polimórfico aún no funciona.

ACTUALIZACIÓN 3 Este es el resultado de ejecutar VS dumpbin.exe :

El comando que utilicé es:

dumpbin.exe /EXPORTS /SYMBOLS C:/ClusterDK/x64/Debug/ClusterDK.dll > c:/temp/dumpbin.out

y las partes relevantes de la salida:

Microsoft (R) COFF/PE Dumper Version 11.00.50727.1 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file C:/ClusterDK/x64/Debug/ClusterDK.dll File Type: DLL Section contains the following exports for ClusterDK.dll 00000000 characteristics 5A1689DA time date stamp Thu Nov 23 09:42:02 2017 0.00 version 1 ordinal base 78 number of functions 78 number of names ordinal hint RVA name 8 7 00004485 ??0ClusterException@cluster@@QEAA@AEBV01@@Z = @ILT+13440(??0ClusterException@cluster@@QEAA@AEBV01@@Z) 9 8 00001659 ??0ClusterException@cluster@@QEAA@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z = @ILT+1620(??0ClusterException@cluster@@QEAA@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) 10 9 00001F1E ??0ClusterException@cluster@@QEAA@XZ = @ILT+3865(??0ClusterException@cluster@@QEAA@XZ) 11 A 00004D4F ??0ClusterExecutionException@cluster@@QEAA@AEBV01@@Z = @ILT+15690(??0ClusterExecutionException@cluster@@QEAA@AEBV01@@Z) 12 B 000010AA ??0ClusterExecutionException@cluster@@QEAA@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z = @ILT+165(??0ClusterExecutionException@cluster@@QEAA@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) 27 1A 000035D0 ??1ClusterException@cluster@@UEAA@XZ = @ILT+9675(??1ClusterException@cluster@@UEAA@XZ) 28 1B 00003C7E ??1ClusterExecutionException@cluster@@UEAA@XZ = @ILT+11385(??1ClusterExecutionException@cluster@@UEAA@XZ) 37 24 00002BD5 ??4ClusterException@cluster@@QEAAAEAV01@AEBV01@@Z = @ILT+7120(??4ClusterException@cluster@@QEAAAEAV01@AEBV01@@Z) 38 25 000034D1 ??4ClusterExecutionException@cluster@@QEAAAEAV01@AEBV01@@Z = @ILT+9420(??4ClusterExecutionException@cluster@@QEAAAEAV01@AEBV01@@Z) 46 2D 000D2220 ??_7ClusterException@cluster@@6B@ = ??_7ClusterException@cluster@@6B@ (const cluster::ClusterException::`vftable'') 47 2E 000D2248 ??_7ClusterExecutionException@cluster@@6B@ = ??_7ClusterExecutionException@cluster@@6B@ (const cluster::ClusterExecutionException::`vftable'') 52 33 00004BB5 ?clone@ClusterException@cluster@@UEAAPEAV12@XZ = @ILT+15280(?clone@ClusterException@cluster@@UEAAPEAV12@XZ) 53 34 00004D31 ?clone@ClusterExecutionException@cluster@@UEAAPEAV12@XZ = @ILT+15660(?clone@ClusterExecutionException@cluster@@UEAAPEAV12@XZ) 61 3C 00001D43 ?getErrorType@ClusterExecutionException@cluster@@QEBA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ = @ILT+3390(?getErrorType@ClusterExecutionException@cluster@@QEBA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ) 69 44 0000480E ?init@ClusterException@cluster@@IEAAXAEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z = @ILT+14345(?init@ClusterException@cluster@@IEAAXAEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) 78 4D 000032FB ?what@ClusterException@cluster@@UEBAPEBDXZ = @ILT+8950(?what@ClusterException@cluster@@UEBAPEBDXZ) Summary 4000 .data 5000 .idata 12000 .pdata 54000 .rdata 2000 .reloc 1000 .rsrc C9000 .text 1000 .tls


No sé sobre su código C ++. Pero hay un pequeño problema con tu código python. ClusterExecutionException antes de ClusterException . Siempre debe colocar el manejador de excepciones hijo antes de la excepción base.

En test_exception si ClusterExecutionException provocó, será capturado por ClusterException antes de que pueda llegar a ClusterExecutionException .

el código debe ser el siguiente código

def test_exception(exCase): try: cluster.boomTest(exCase) except ClusterExecutionException as ex: print ''Success! ClusterExecutionException gracefully handled:'' / ''/n message="%s"'' / ''/n errorType="%s"'' / ''/n clusterResponse="%s"'' % (ex.message, ex.errorType, ex.clusterResponse) except ClusterException as ex: print ''Success! ClusterException gracefully handled:'' / ''/n message="%s"'' % ex.message except: print ''Caught unknown exception: %s "%s"'' % (sys.exc_info()[0], sys.exc_info()[1])

ahora I have tried in Boost-Python while registering the exception translation of ClusterExecutionException to register it as its base ClusterException , lo que ha mencionado en cuestión.