En la anterior sesión vimos los conceptos básicos de Python.
¿Cómo sabemos si nuestro código funciona correctamente?
No se debe hacer esto
Causan
Errores dificiles de encontrar y corregir
Cuando
Se usan técnicas que no son adecuadas para el propósito que se pretende
Nosotros, como ingenieros del software, debemos ser capaces de identificar estas malas prácticas y evitarlas.
El método print
…
Gestión de informes para controlar el flujo del programa
Python tiene un sistema de mensajes por nivel de importancia.
import logging
logging.debug("Este es un mensaje de depuración.")
logging.info("Este es un mensaje informativo.")
logging.warning("Este es una advertencia.")
logging.error("Este es un mensaje de error.")
logging.critical("Este es un error crítico.")
print("Esto es un mensaje normal.")
WARNING:root:Este es una advertencia.
ERROR:root:Este es un mensaje de error.
CRITICAL:root:Este es un error crítico.
Esto es un mensaje normal.
Python tiene un sistema de mensajes por nivel de importancia.
¿Dónde están los mensajes debug e info?
No aparecen porque el nivel predeterminado de logging es WARNING.
Nivel | Valor | Descripción |
---|---|---|
DEBUG | 10 | Mensajes para depuración interna. |
INFO | 20 | Información general sobre el programa. |
WARNING | 30 | Advertencias que no detienen el programa. |
ERROR | 40 | Errores que pueden interrumpir la ejecución. |
CRITICAL | 50 | Errores graves que requieren atención inmediata. |
¿Cómo mostrar los mensajes de nivel DEBUG e INFO?
Cada uno de los niveles muestra los mensajes de su nivel y los de los niveles superiores.
Podemos cambiar el nivel de logging para mostrar mensajes de nivel DEBUG e INFO.
Si ejecutamos el anterior código…
DEBUG:root:Este es un mensaje de depuración.
INFO:root:Este es un mensaje informativo.
WARNING:root:Este es una advertencia.
ERROR:root:Este es un mensaje de error.
CRITICAL:root:Este es un error crítico.
Esto es un mensaje normal.
De forma habitual, los logs se escriben en un archivo.
Para ello, hay que especificar el parámetro filename
en la función basicConfig
.
Consejo
Si se especifica un archivo, los mensajes se escribirán en él y no se mostrarán por pantalla.
Dentro de un proyecto, es recomendable usar un logger propio que nos permitirá ver de dónde provienen los mensajes.
INFO:mi_inventario:Se ha añadido un nuevo producto.
Consejo
Es habitual especificar el nombre del logger con el nombre del modulo usando __name__
.
Python proporciona un mecanismo para gestionar errores de forma estructurada.
Si añadimos un bloque else
, se ejecutará si no se produce ningún error.
Si añadimos un bloque finally
, se ejecutará siempre, haya error o no.
Si no se especifica el tipo de error, se capturarán todos los errores.
Consejo
No es recomendable capturar todos los errores, ya que puede ocultar errores graves.
Para capturar el error y mostrarlo, se puede usar la variable as
.
Para capturar el error y mostrarlo, se puede usar la variable as
.
Consejo
Podemos acumular varios bloques except
para gestionar diferentes tipos de errores que puedan surgir dentro del bloque try
.
Podemos lanzar un error cuando detectamos una situación inesperada.
Utilizamos la instrucción raise
seguida del tipo de error que queremos lanzar.
Utilizamos la instrucción raise
seguida del tipo de error que queremos lanzar.
Consejo
Podemos crear nuestros propios tipos de error en Python, pero necesitaremos saber más sobre clases y herencia.
Un depurador es una herramienta de programación que nos permite inspeccionar el código y controlar su ejecución.
Encontrar errores
Entender nuestro programa
Vamos a utilizar el depurador de Visual Studio Code para depurar nuestro código.
Consideraciones
Existen otros depuradores y herramientas, seleccionamos ésta porque se utiliza en entornos de trabajo reales.
Vamos a utilizar el depurador de Visual Studio Code para depurar nuestro código.
F5
o hacemos clic en el botón de Run and Debug
.Tenemos dos opciones:
Consejo
Recomendamos crear un archivo de configuración para poder ejecutar el depurador a distintos niveles.
{
"version": "0.2.0",
"configurations": [
{
"name": "Ejecuta test.py",
"type": "python",
"request": "launch",
"program": "test.py",
"console": "integratedTerminal"
},
]
}
{
"version": "0.2.0",
"configurations": [
{
"name": "Ejecuta test.py",
"type": "python",
"request": "launch",
"program": "test.py",
"console": "integratedTerminal"
},
// ...
]
}
Consejo
Es recomendable que indaguéis más sobre las posibles configuraciones https://code.visualstudio.com/docs/editor/debugging#_launch-configurations
F5
Hemos ejecutado el depurador ¿Y ahora qué?
Esto no hace nada
Python no me quiere
Me voy a casa
😭
👎
✨ Breakpoints ✨
Nos permite detener la ejecución y analizar el estado del programa.
Sin ellos, el depurador no se detendrá y no podremos inspeccionar el código.
Podemos añadir un breakpoint haciendo clic en la barra lateral izquierda del editor.
Si ejecutamos el depurador, el programa se detendrá en el breakpoint.
Para movernos por el programa, podemos usar los botones de la barra de herramientas.
Para movernos por el programa, podemos usar los botones de la barra de herramientas.
Consideraciones
Podemos usar los atajos de teclado para movernos por el programa.
Podemos inspeccionar las variables en cualquier momento.
Importante
Solo podemos “ver” las variables que estén en el ámbito actual.
La pestaña Watch nos permite inspeccionar fragmentos cortos de código.
La pestaña Call Stack nos muestra el flujo de ejecución del programa.
Ocurre un dilema cuando inspeccionamos bucles.
Con un breakpoint normal, el programa se detiene en cada iteración.
Podemos añadir condiciones a los breakpoints para que se detengan solo cuando se cumplan.
Edit Breakpoint
.Existen cuatro tipos de condiciones de parada:
Expression
: Se detiene si la condición es verdadera.Hit Count
: Se detiene si el contador es igual al valor.Log Message
: Muestra un mensaje cada vez se alcanza.Wait for Breakpoint
: Se activa solo tras alcanzar otro breakpoint.No es escalable probar nuestro código manualmente.
No es escalable probar nuestro código manualmente.
No es escalable probar nuestro código manualmente.
No es escalable probar nuestro código manualmente.
No es escalable probar nuestro código manualmente.
Verifican que nuestro código funciona correctamente.
Y lo más importante… son automáticas
En un proyecto, las pruebas se suelen guardar en un directorio llamado tests
.
Y son independientes del código principal.
Para crear pruebas, necesitamos un framework de testing.
Python tiene el suyo propio, llamado unittest
.
Un test en Python en un clase que hereda de unittest.TestCase
…
… y cuyos métodos, que empiezan por test_
, son los tests.
… y cuyos métodos, que empiezan por test_
, son los tests.
Hay funciones predefinidas para validar variables y resultados.
Consideraciones
Podéis ver todos los métodos de aserción en la documentación oficial https://docs.python.org/3/library/unittest.html#assert-methods
Para ejecutar los tests debemos llamar a la función unittest.main()
.
Para ejecutar los tests debemos llamar a la función unittest.main()
.
test_true (__main__.SimpleTest.test_true) ... ok
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
Podemos ejecutar los tests desde la terminal…
…o podemos utilizar VSCode para ejecutarlos.
Consideraciones
Solo voy a explicar cómo ejecutar los tests desde VSCode. Podéis revisar la interfaz por terminal en la documentación oficial. https://docs.python.org/3/library/unittest.html#test-discovery
import unittest
class StringTests(unittest.TestCase):
def test_upper(self):
"""Comprueba que 'hola' en mayúsculas es 'HOLA'"""
self.assertEqual("hola".upper(), "HOLA")
def test_startswith(self):
"""Comprueba que 'Python' empieza con 'Py'"""
self.assertTrue("Python".startswith("Py"))
if __name__ == "__main__":
unittest.main()
Consideraciones
Más adelante veremos en profundidad este tema. Cómo asegurar que los tests son independientes, que se prueban todas las posibles combinaciones, etc.
Se ha estudiado cómo mantener un código limpio y ordenado a la vez que se generan informes de errores y advertencias mediante el sistema de logging de Python.
También hemos visto la importancia de manejar y generar nuestros propios errores de manera estructurada.
Por último, hemos aprendido a depurar nuestro código con el depurador de Visual Studio Code y a generar pruebas automatizadas con el framework unittest
.
Fuentes de documentación
Expansión de la temática
Los ejercicios para practicar estos conceptos están disponibles en la web de la asignatura.
Ingeniería del Software para Inteligencia Artificial