-
Notifications
You must be signed in to change notification settings - Fork 2
L1: Python y VScode
Puesta en marcha del Visual Code para su uso con el lenguaje de programación Python: Ejecución y depuración de programas "hola mundo", Gestión e instalación de paquetes python, Formateado de código y tests unitarios. Todo desde el entorno VSCode
- Introducción
- Extensiones de VScode
- Programa Hola mundo
- Segundo programa: Imprimiendo mensajes en la consola
- Tercer programa: Imprimiendo mensajes desde funciones
- Cuarto programa: Variables
- Quinto programa: Bucles
- Configuraciones de depuración
- Arquitectura del depurador
- Entornos virtuales
- Gestión de paquetes python
- Formateado automático de código
- Verificación del estilo y calidad del código
- Tests Unitarios
- Conclusiones
- Autor
- Licencia
- Enlaces
En esta sesión de laboratorio supondremos que ya tienes instalado en tu ordenador el VSCode y el intérprete de python. Aprenderemos a configurar el visual code para utilizar python. Empezaremos con la ejecución y depuración de programas python, para aprender la mecánica y comprobar que todo está bien instalado y funcionando. Los programas python que usaremos serán los hola mundo: programas extremadamente sencillos
Seguiremos con la instalación de entornos virtuales de python, en los que aprenderemos a instalar paquetes. Instalaremos el paquete Black que permite hacer un formateado automático del código, así como el Flake8 para comprobar el estilo del código y garantizar que cumple con las reglas definidas por la comunidad python
Por último aprenderemos a configurar el entorno para hacer pruebas unitarias utilizando el módulo estándar de python unnittest
El objetivo de esta sesión es poner todo en funcionamiento y aprender a usar las herramientas desde VScode. No profundizaremos todavía en nada relativo a python ni a técnicas de programación ni pruebas unitarias (más allá de los ejemplos hola mundo)
La versión utilizada para la creación de este tutorial es la: 1.97.2

Aquí está toda la información en formato texto para poder hacer copy y paste
Version: 1.97.2
Commit: e54c774e0add60467559eb0d1e229c6452cf8447
Date: 2025-02-12T23:20:35.343Z
Electron: 32.2.7
ElectronBuildId: 10982180
Chromium: 128.0.6613.186
Node.js: 20.18.1
V8: 12.8.374.38-electron.0
OS: Linux x64 6.11.0-17-generic
Para trabajar con Python desde VScode instalamos las siguientes extensiones:
Este es el resultado. Así se puede comprobar que están instaladas

Con estas extensiones podemos ejecutar y depurar programas python, crear entornos virtuales y definir pruebas unitarias. Más adelante usaremos las siguientes extensiones adicionales:
- Pip Manager: Gestión de paquetes python desde Pypi
- Black formatter. Formatear el código automáticamente utilizando el paquete python Black
- Flake8. Comprobar el estilo del código usando el paquete python Flake8
De momento no hace falta que instales estas extensiones adicionales. Se incará cómo hacerlo en el apartado correspondiente
🚧 TODO 🚧
- Extensión: Python Environments: https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-python-envs
Empezamos por lo más básico: hacer el programa hola mundo para comprobar que todo funciona. Este programa sólo tiene una instrucción: print(), para imprimir una cadena en la consola
print("Hola mundo")Abrimos el fichero hola_mundo.py (o lo escribimos desde cero). Supondremos que tenemos abierto el repositorio de este tutorial. Todos los directorios los usaremos relativamente a este repo

Como están las extensiones de python instaladas vemos que vscode resalta la sintáxis. En la parte inferior se indica que es un programa en python. También aparece, a su derecha, la versión de python instalada en el sistema, y es la que usará la extensión por defecto. Todo esto se ha hecho automáticamente
En los siguientes apartados vamos a ejecutar este mini-programa y depurarlo. El objetivo es aprender la mećanica de ejecución, y también la mecánica de la depuración. Los conceptos de depuración que vamos a aprender son Dar un paso y terminar la depuración
Para ejecutar el programa pinchamos en el botón de Play que hay en la esquina superior derecha

Se abre un terminal en la parte derecha del visual code, en el directorio raiz del repositorio, que en este caso es ~/develop/Learn-python. Se ejecuta el fichero hola_mundo.py especificando su ruta relativa

Efectivamente comprobamos que el mensasje Hola mundo aparece, y se vuelve al terminal. El proceso es muy rápido.
Esto es lo que aparece en el terminal:
obijuan@JANEL:~/Develop/Learn-python$ /bin/python3 /home/obijuan/Develop/Learn-python/wiki/L1/Ejemplos/hola_mundo.py
Hola mundo
obijuan@JANEL:~/Develop/Learn-python$Si volvemos a pinchar en el botón de ejecución se ejecuta de nuevo, en el propio terminal. De manera similar a como lo hubiésemos hecho manualmente

¡Y ya está! Así de fácil es ejecutar un programa básico en python, desde el vscode
En esta animación se muestra el proceso completo de ejecución del Hola mundo

Lo más interesante de la extensión de python es que podemos depurar el programa, ejecutándolo paso a paso. El programa hola mundo apenas tiene nada que depurar, pero lo usaremos para mostrar el proceso
El primer paso es establecer al menos un punto de ruptura. Es la línea donde queremos que se detenga la ejecución del programa, para examinar las variables y ejecutar instrucciones paso a paso. En el caso del hola mundo sólo hay una línea. Colocamos ahí el punto de ruptura (Breakpoint), pinchando a la izquierda del número de línea

Ahora pinchamos en el desplegable que hay a la derecha del botón de ejecución y seleccionamos la opción Python Debugger: Debug Python File

El programa se empieza a ejecutar, en modo depuración, hasta que se alcanza el breakpoint y se detiene. La línea con el breakpoint se marca con un fondo diferente para resaltar el hecho de que esta será la siguiente instrucción a ejecutar

El comando usado para ejecutar el programa lo vemos en la nueva consola que aparece. Este comando es diferente al que se muestra cuando se ejecuta el programa normalmente. Esto es lo que aparece:
obijuan@JANEL:~/Develop/Learn-python$ /usr/bin/env /bin/python /home/obijuan/.vscode/extensions/ms-python.debugpy-2024.14.0-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher 57367 -- /home/obijuan/Develop/Learn-python/wiki/L1/Ejemplos/hola_mundo.pyLo que hace este comando es arrancar el intérprete de python en modo servidor, y se queda a la espera de recibir las instrucciones del vscode. Como parámetro se le pasa el fichero python a depurar: hola_mundo.py
Lo siguiente es ejecutar la instrucción marcada. Esta acción se denomina dar un paso (step over). Para hacerlo hay que pinchar en el icono indicado que aparece en la parte superior

Al hacerlo se ejecuta la instrucción, que en este caso es la que produce la impresión de "hola mundo" en la consola,y como es la última instrucción se termina automáticamente la depuración, obteniéndose el mismo resultado que cuando se ejecuta del tirón

Una vez realizada la primera depuración, el icono de la esquina superior derecha cambia al modo depuración. Si queremos volver a depurar basta con pinchar directamente en este icono

En la misma consola de depuración se ejecuta de nuevo el comando, a continuación del mostrado en la depuración anterior

La depuración la podemos terminar en cualquier momento apretando el botón de stop

En este ejemplo el programa está detenido en la única línea que hay. Si paramos la depuración, el programa termina y NO se ejecuta la instrucción marcada

Vemos cómo en la segunda depuración NO aparece el mensaje "Hola mundo"
En esta animación se resume el proceso de depurado del Hola mundo. Se abre el hola mundo, se coloca un punto de ruptura (Breakpoint) en la única línea que tiene, se ejecuta en modo depuración, el programa se detiene, se selecciona la instrucción donde se ha parado, damos un paso y la depuración termina

En esta otra animación se realiza una primera depuración completa. Al terminarla se observa cómo el botón de ejecución se ha cambiado por el botón de comenzar la depuración. Se realiza una segunda depuración. Al realizar la tercera depuración se detiene, antes de terminar el programa, por lo que no sale el último mensaje hola mundo

En este segundo programa sólo utilizamos la instrucción print(), pero muchas veces. De esta forma podremos situar puntos de ruptura en sitios diferentes, y practicaremos mejor la depuración. También aprovechamos para incluir comentarios y caracteres unicode
# ──────────────────────────────────────────────────────
# ── Hola mundo 2: Imprimiendo mensajes en la consola
# ──────────────────────────────────────────────────────
print("══════════════════════════════")
print("Mensaje 1")
print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
print("Mensaje 2")
print("──────────────────────────────")
print("Mensaje 3")
print("┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅")
print("Mensaje 4")
print("┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄")
print("Mensaje 5")
print("╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌")
print("Mensaje 6")
print("╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶")
print("Mensaje 7")
print("▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁")
print("Mensaje 8")
print("▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂")
print("Mensaje 9")
print("▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃")
print("Mensaje 10")
print("▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄")
print("Mensaje 11")
print("▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅")
print("✅ OK")Lo primero es ejecutar el programa como ya sabemos. Este es el resultado

Lo interesante del proceso de depuración es que podemos ejecutar el programa, pararlo en un sitio concreto, ejecutar instrucciones paso a paso y reanundar la ejecución en cualquier momomento
Como ejemplo, vamos a poner un punto de ruptura. Luego ejecutaremos dos instrucciones paso a paso y finalmente reanudaremos la ejecución del programa
El punto de ruptura (Breakpoint) lo ponemos en la línea 10

Entramos en el modo depuración. Se empieza a ejecutar el programa y se para al llegar a la línea 10 (que no se ejecuta todavía)

Damos un paso. Se imprime el siguiente mensaje y se para

Damos otro paso más. Se imprime el mensaje y se para

Para reanudar la ejecución del programa hay que pinchar en el icono de continuar:

Al hacerlo se completa la ejecución y se muestran el resto de mensajes

En esta animación se muestra el proceso completo

En cualquier momento podemos volver a reiniciar la depuración, sin necesidad de terminarla primero. Para hacerlo hay que pinchar en el icono de restart

Al hacerlo el programa se termina (por eso no se imprimen el resto de mensajes en la consola), y se vuelve a ejecutar desde el comienzo. Al ejecutarse se detiene en el primer punto de ruptura

En esta animación lo vemos en funcionamiento

En nuestros programas podemos poner TODOS LOS BREAKPOINTS QUE QUERAMOS. En nuestro ejemplo vamos a situar dos puntos de ruptura, uno en la línea 10 y otro en la línea 20

Al ejecutar el programa se para en el primer punto de ruptura

Si ahora pinchamos en el botón de continuar, se continua la ejecución hasta que se alcanza el segundo punto de ruptura, donde se vuelve a parar

En esta animación vemos el proceso en funcionamiento:

En este tercer programa "hola mundo" refactorizamos el código para que los mensajes se impriman desde tres sitios diferentes: desde dos funciones y desde el programa principal
Este es el programa:
# ──────────────────────────────────────────────────────
# ── Hola mundo 3: Imprimiendo mensajes en la consola
# ── desde funciones
# ──────────────────────────────────────────────────────
def print_bloque1():
print("Mensaje 3")
print("┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅")
print("Mensaje 4")
print("┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄")
print("Mensaje 5")
print("╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌")
def print_bloque2():
print("Mensaje 7")
print("▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁")
print("Mensaje 8")
print("▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂")
print("Mensaje 9")
print("▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃")
# ──────────────────────────────────────────────────────
# ── MAIN
# ──────────────────────────────────────────────────────
print("══════════════════════════════")
print("Mensaje 1")
print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
print("Mensaje 2")
print("──────────────────────────────")
print_bloque1()
print("Mensaje 6")
print("╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶")
print_bloque2()
print("Mensaje 10")
print("▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄")
print("Mensaje 11")
print("▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅")
print("✅ OK")Lo ejecutamos para comprobar que funciona. La salida en la consola es exactamente la misma que el ejemplo anterior. Son los mismos mensajes, pero se imprimen desde diferentes ámbitos de nuestro programa

La operación de dar un paso (step) se produce dentro del ámbito en el que nos encontramos. Inicialmente el ámbito es el del programa principal. Si el punto de ruptura está en el programa principal, TODOS los pasos dados harán que estemos siempre en ese ámbito
Así, si el siguiente paso es la llamada a una función, y ejecutamos la operación de step, se ejecutará la función completamente y se parará en la siguiente instrucción a continuación de la llamada. NO se depurará dentro de la función
Para comprobarlo ponemos un breakpoint en la linea 32, que es donde se llama a la función print_bloque1()

Ahora arrancamos la depuración. El programa comienza a ejecutarse, se imprimen los primeros mensajes y se para en el breakpoint que hemos colocado

Ahora ejecutamos el paso. La función print_bloque1() se ejecuta totalmente, por ello en la consola aparecen de golpe los mensajes del 3 al 5

Efectivamente hemos comprobado que al ejecutar una función (dar un paso) el depurador nos mantiene en el mismo ámbito en el que estábamos. En este caso el depurador se mantiene dentro del programa principal
En esta animación se muestra el proceso completo. Se pone el breakpoint en la línea 32 y se ejecutan todas las instrucciones paso a paso hasta llegar al final. Entre esas instrucciones están las llamadas a las funciones print_bloque1() y print_bloque2() que se ejecutan de golpe

Mientas depuramos nos puede interesar entrar en la función, para seguir ejecutando las instrucciones paso a paso dentro de la función. Cuando el programa está detenido sobre la llamada a la función, pulsamos la opción step into en los botones de depuración. El depurador entra en la función y se detiene en su primera instrucción
Para comprobarlo usamos el mismo escenario que el apartado anterior. Colocamos un breakpoint en la línea 32, sobre la instrucción print_bloque1()

Comenzamos la depuración hasta que se pare en el breakpoint. Lo siguiente será pinchar en el botón de step into, que está marcado en rojo en el pantallazo

Al ejecutar step into el depurador se mete en la función y se para en su primera instrucción. En la parte de la izquierda vemos el ámbito en el que estamos, en la sección call stack. Comprobamos que ahí está el nombre de la función: print_bloque1()

¡Estamos dentro de la función! Ahí podemos ejecutar las instrucciones paso a paso con normalidad. En el siguiente paso se imprime el mensaje, y se para.

Seguimos ejecutando las instrucciones paso a paso, viendo cómo aparecen los mensajes en la consola, uno por cada paso, hasta llegar a la última instrucción de la función

Al ejecutar ese paso, el depurador automáticamente sale de la función y entra en el ámbito anterior, donde fue llamada la función. El depurador se queda señalando el nombre de la función, pero ¡ojo!, la función ya se ha ejecutado

Al ejecutar el siguiente paso ya se marca la siguiente instrucción. Este es el realidad un paso virtual. No ha ejecutado nada, simplemente nos está informando de cuál es la siguiente instrucción a ejecutar

En esta animación se muestra el proceso completo. Se pone un breakpoint en la línea 32 y se entra en la función (step into). Se ejecutan las instrucciones paso a paso hasta llegar al ámbito principal, donde se continúa ejecutando el resto de instrucciones del tirón

Los puntos de ruptura se pueden colocar en cualquier instrucción. Por ejemplo podemos poner uno dentro de una instrución de una función. En ese caso el programa se ejecuta igualmente y se para en esa instrucción dentro de la función
Para comprobarlo situamos un breakpoint en la línea 10, que está dentro de la función print_bloque1()

Depuramos el programa, y se para en el breakpoint, dentro de la función. En el call stack vemos que estamos en el ámbito de la función print_bloque1()

En esta animación se muestra el resultado. Se coloca un breakpoint dentro de la función print_bloque1() (Línea 10) y se comprueba que la ejecución se detiene ahí. Luego se continúa con la ejecución completa

Cuando estamos depurando dentro de una función podemos ejecutar las instrucciones paso a paso (step). También podemos entrar en otras funciones (step into). Y por supuesto, podemos ejecutar todas las instrucciones dentro de la función hasta que termine. Esto es lo que se llama salir de la función (step out)
Partiemos del apartado anterior, en el que la función se ha detenido en el Breakpoint dentro de la función print_bloque1(). Vamos a pulsar el botón step out, marcado en rojo en el pantallazo

Al apretarlo se ejecutan todas las instrucciones que quedan en la función, por lo que se imprimen los mensajes pendientes, y se retorna al ámbito anterior

En esta animación se muestra el proceso. Se pone un breakpoint dentro de la función print_bloque1() y se llega al ámbito anterior apretando el botón de step out

En los programas podemos poner todos los puntos de ruptura que queramos, y en cualquiera de los ámbitos. Se puede llegar de uno a otro fácilmente mediante la opción de continuar
Para comprobar el funcionamiento ponemos 5 puntos de ruptura, en las líneas 10, 18, 28, 34 y 41. Tres de ellos están en el programa principal, uno en la función print_bloque1() y otro en print_bloque2()
En este pantallazo sólo se ven los 3 primeros breakpoints

Lanzamos la depuración, y se detiene en el primer breakpoint: el de la línea 28, que es el que está en el ámbito del main. En la parte de la izquierda, en la sección que pone Breakpoints vemos todos los breakpoints activos. Los checkslist que tienen se usan para activar/desactivar cada breakpoint, sin tener que navegar a su número de línea

Si ahora pulsamos en el botón de continue, se ejecutan las instrucciones hasta llegar al segundo breakpoint, el de la línea 10 que ahora está en la función print_bloque1()

Volvemos a pulsar en continue. Ahora se para en el tercer breakpoint, en la línea 35 del ámbito main

Pulsamos en continue una vez más. El cuarto breakpoint es el de la línea 18 en la función print_bloque2()

Volvemos a apretar en continue. El quinto breakpoint en el de la línea 15 en el ámbito main

Si apretamos continue una última vez se termina el programa y se imprimen los últimos mensajes

En esta animación vemos el proceso completo

En este programa se definen variables, de tipo entero y cadena, y se imprimen. El objetivo es aprender cómo el depurador nos muestra el valor de estas variables según se van creando
Este es el programa:
# ──────────────────────────────────────────────────────
# ── Hola mundo 4: Imprimiendo variables
# ──────────────────────────────────────────────────────
print("══════════════════════════════")
#── Variable cadena
msg1 = "Mensaje 1"
print(msg1)
#── Variables enteras
a = 2
b = 10
c = a + b
print(c)
print("──────────────────────────────")Este es el resultado de la ejecución del programa

Vamos a depurar el programa y fijarnos en las variables especiales. Son variables que están disponibles en TODOS los programas python, y forman parte del propio lenguaje python
Comenzamos ponemos un punto de ruptura en la línea 8 y lanzando el depurador

Comprobamos que se ha impreso la primera línea (la doble) y se ha detenido en la línea 8. En este punto nos fijamos en la parte superior izquierda donde pone VARIABLES. Nos fijamos en las variables locales (locals), que al ser las que están en el ámbito main también son globales
Desplegamos la opción que dice special variables, para ver qué hay ahí dentro

Vemos todas las variables a las que tenemos acceso en el ámbito actual (que es el main). Por ejemplo, comprobamos que efectivamente existe una variable llamada __name__ cuyo valor es __main__. Es la variable que contiene el nombre del ámbito en el que estamos, que en este caso es el programa principal
Además vemos que hay una variable llamada __builtins__. Se trata de un módulo que tiene atributos y funciones. Ahí es donde están todas las funciones incorporadas de python. Y que se pueden usar directamente sin necesidad de importarlas. Lo desplegamos para comprobarlo:

Comprobamos, por ejemplo, que la función abs() es una de las funciones disponibles en python
Lanzamos la misma depuración anterior (breakpoint en la línea 8) y comenzamos a depurar paso a paso el programa fijándonos en las variables locales. Al ejecutarse la instrucción de la línea 8, aparece la primera variable: msg. Antes de la línea 8 todavía no había ninguna variable local creada. Ahora ya la vemos, con el valor que tiene asignado

Ejecutamos hasta la línea 13, donde ya se ha creado la variable a. La vemos en la parte izquierda, con su valor asignado

Damos un paso más, y vemos la variable b

Y por último vemos la variable c

Cuando tenemos muchas variables en nuestro programa, todas ellas aparecen en el apartado de variables, lo que hace que esté muy poblado. En algunas circunstancias nos interesa fijarnos sólo en unas pocas variables o expresiones. Las podemos añadir en la sección Watch del depurador
Como ejemplo, ponemos dos breakpoints, en las líneas 8 y 15

Lanzamos la depuración, y se detiene en el primer breakpoint. Nos vamos a la parte de Watch y pinchamos en el símbolo + para añadir una expresión

Al hacerlo se nos abre un recuadro donde escribir la variable o la expresión a visualizar. En este ejemplo nos vamos a fijar en la variable a

Pulsamos ENTER. La variable a se añade en la sección Watch. Como valor aparece este mensaje: name error: 'a' is not defined. Esto es debido a que la variable a no todavía no está definida en ese instante de la ejecución

Pinchamos en continue para pasar al segundo breakpoint

Ahora ya sí que vemos el valor de a
Todas las expresiones y variables que metemos en Watch quedan registradas, y no se borran al terminar la depuración. Se pueden reutilizar de una depuración a otra. Si las queremos eliminar hay que hacerlo explícitamente pinchando en el símbolo X que hay a su derecha

La consola de depuración nos permite ejecutar comandos python durante la depuración. Para abrirla hay que pinchar en View/Debug console

Nos aparece una nueva sección en la parte inferior del editor, donde está la pestaña Debug console

Lanzamos la depuración y nos paramos en el segundo breakpoint. En la parte inferior de la consola de depuración introducimos los comandos. En nuestro caso vamos a introducir msg1, para ver el contenido de esa variable

Pulsamos ENTER y se muestra la variable

También se pueden incocar métodos asociados a esas variables. Por ejemplo, como la variable msg1 es una cadena, podemos invocar el método msg1.upper()

Los breakponts que hemos usado hasta ahora son los básicos. Cuando el programa alcanza el breakpoint, se detiene la ejecución. Sin embargo hay más tipos de Breakpoints. Uno de ellos es del de tipo LOG que no para la ejecución sino que simplemente emite un mensaje en la consola de depuración
Partimos del ejemplo anterior donde tenemos dos breakpoinits, en las líneas 8 y 15. El primer Breakpoint lo vamos a convertir a un LOG Breakpoint. Para ello nos ponemos encima de él y pulsamos el botón derecho del ratón para desplegar su menú de propiedades. Pinchamos en la opción Edit Breakpoint

Aparece un menú desplegable. Pinchamos en él para abrirlo

Pinchamos en la opción Log Message

En la parte de la derecha escribimos el mensaje que queremos que aparezca en la consola de Debug cuando el programa pase por ese Breakpoint (sin detenerse)

Pulsamos ENTER. El símbolo del breakpoint ha cambiado, ahora se ha transformado en un cuadrado, para indicar visualmente que se trata de un LOG POINT

Arrancamos la depuración. Ahora se detiene directamente en el segundo breakpoint, porque el primero es un logpoint. En la consola de Debug vemos el mensaje: ¡¡PASA POR AQUI!!, indicando que se ha pasado por el logpoint

En este ejemplo definimos un bucle para probar los breakpoints condicionales
Este es el programa:
# ──────────────────────────────────────────────────────
# ── Hola mundo 5: Bucles
# ──────────────────────────────────────────────────────
print("══════════════════════════════")
#-- Variable i va de 4 a 20, de 2 en 2
#-- (El ultimo valor no se incluye)
for i in range(4,20, 2):
print(i)
print("──────────────────────────────")El programa modifica la variable i para que vaya desde el valor 4 hasta el 20 de 2 en 2. El 20 es el límite superior y no se asigna a la variable. Esta es la salida que se produce al ejecutarlo
══════════════════════════════
4
6
8
10
12
14
16
18
──────────────────────────────Aquí se muestra la ejecución en VSCode

Colocamos un breakpoint en la línea 10, que es la instrucción que se repite en el bucle y lanzamos la depuración. Comprobamos que la variable i inicialmente vale 4. También vemos en la propia línea 10 que el valor de i es 4

Damos un paso. En la consola se imprime 4

Damos un paso más. Se repite la misma instrucción de la línea 10, pero ahora la variable i se ha incrementado en 2 unidades

Como el breakpoint está en una línea dentro del bucle, si le damos a continuar vuelve a la misma instrucción, pero con la variable i incrementanda

Ejecutamos una vez más (dando en continue). Ahora la variable vale 10

En esta Animación vemos el proceso completo

Es posible poner Breakpoints condicionaldes que se activen cuando una variable tenga un valor determinado, o en general cuando se evalúe una expresión a True. Por ello, estos breakpoints están asociados a una expresión que hay que introducir cuando se crean
Vamos a colocar un Breakpoint para que se active cuando la variable i tenga el valor 12. La expresión a utilizar es i==12
Editamos el breakpoint y seleccionamos la opción expression. Escribimos i==12

Pulsamos ENTER y arrancamos la depuración. Comprobamos que efectivamente la ejecución se detiene cuando i vale 12

Si ahora pulsamos en continuar se ejecuta hasta el final (sin otras detenciones)
En esta animación lo vemos en funcionamiento

Es posible poner otro tipo de Breakpoints que se activen por Número de repeticiones. Estos puntos de ruptura tiene un contador interno asociado, que se incrementa cada vez que la ejecución pasa por ahí. Cuando este contador alcanza el número especificado se realiza la parada
En este ejemplo vamos a poner un valor de 3, de manera que se va a detener en la línea 10 la tercera vez que llegue
Editamos el breakpoint y seleccionamos la opción hit count. Colocamos el valor 3

Pulsamos ENTER y lanzamos la depuración. Efectivamente al llegar la tercera vez el programa se detiene. En la consola están impresos los dos números anteriores: 4 y 6, y en la vuelta actual la variable vale 8

Si ahora le damos a continuar se ejecuta hasta el final
En esta animación se muestra el proceso

Hasta ahora estamos usando la configuración de depuración que viene por defecto, que lanza el depurador desde el directorio principal del repositorio, y sin pasar parámetros. Además, la salida de la depuración se muestra en la consola integrada del Visual Code. Todo esto se puede cambiar mediante las configuraciones
Es posible depurar los ficheros sin crear ninguna configuración en un fichero. Esto permite hacer una prueba rápida. Primero entramos en el depurador pinchando en el icono correspondiente. El depurador todavía no está configurado, por lo que nos salen opciones para hacerlo

Vamos a ejecutar el ejemplo actual (hola_mundo5.py). Para ello pinchamos en el botón Run and Debug. Como no hay puntos de ruptura configurados, el efecto será que se ejecutará el programa hasta el final

Como es la primera vez que ejecutamos en esta sesión, nos pide que indiquemos qué configuración usar. Seleccionamos Python File

Como no hay puntos de ruptura, el programa se ejecuta completamente, y vemos la salida en la consola integrada del visual. Se ha ejecutado de manera similar a como lo hemos hecho hasta ahora, apretando el botón que había en la parte superior derecha del editor

Si ahora volvemos a pinchar en Run and Debug ya no nos pregunta la configuración a usar. Directamente lo ejecutará. Este comportamiento permanecerá así durante toda la sesión. La próxima vez que ejecutemos el visual code nos volverá a pedir que seleccionemos la configuración
Si colocamos un punto de ruptura, entonces el programa se detendrá al alcanzarlo, y podremos depurar como ya sabemos

En esta animación se muestra el funcionamiento

La primera configuración que vamos a crear es la que viene por defecto, que es la misma que hemos estado utilizando hasta ahora. Las configuraciones se guardan en el archivo launch.json que se encuentra en la carpeta .vscode en el directorio principal del repositorio
Este archivo lo podemos crear a mano, o podemos utilizar un asistente. Entramos en el modo depuración y pinchamos en la opción Create a launch.json file

Seleccionamos la opción Python Debugger

Y ahora la opción Python File

Se crea automáticamente el fichero launch.json, se abre en una pestaña y aparece un asistente para rellenar
el fichero por nosotros. Pinchamos en la opción Python Debugger

Ya tenemos el fichero creado y guardado. Podemos cerrar la pestaña y probarlo

Este es la configuración por defecto que se ha creado. Nos fijamos en el nombre que le hemos dado, que se encuentra en la propiedad name. Es "Python Debugger: Current File"
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python Debugger: Current File",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal"
}
]
}Nos vamos al depurador. En la parte superior vemos un botón de play con el nombre que tiene la configuración por defecto: Python Debugger: Current File. Pinchamos en el botón de Play para ejecutarlo

Se ejecuta el programa, y la salida se muestra en la consola integrada en el VSCode

Si tenemos un Breakpoint y ejecutamos, el programa se detiene en el punto de parada

Editamos la configuración por defecto para crear una nueva, que llamaremos Run File y es la que usaremos para ejecutar/depurar programas en python. La diferencia con la que viene por defecto es que la ejecutaremos desde su propio directorio (en vez desde el directorio principal del repo). Además, utilizaremos la consola del VSCode en vez de la consola integrada
Este es el nuevo archivo de configuración (launch.json). Aprovechamos para meter comentarios explicando cada uno de los campos utilizados
{
"version": "0.2.0",
"configurations": [
{
//-- Nombre de la configuracion
"name": "RUN file",
//-- Depurador de Python
"type": "debugpy",
//-- Lanzar el depurador
"request": "launch",
//-- Programa a depurar: Fichero en la pestaña activa
"program": "${file}",
//-- Dónde lanzar el depurador
"console": "internalConsole",
//-- Depurar sólo el código del usuario (no del sistema)
"justMyCode": true,
//-- Directorio de trabajo donde ejecutar el programa
"cwd": "${workspaceFolder}/${relativeFileDirname}"
}
]
}Ahora nos vamos la zona de depuración. Abrimos la consola de depuración (View/Debug Console) y pinchamos en el botón de Play para ejecutar RUN File

El programa se ejecuta totalmente, y vemos su salida en la consola de depuración del VSCode

Si ponemos un Breakpoint y repetimos el proceso, el programa se detiene, y lo podemos ejecutar paso a paso como ya sabemos

En esta animación se muestra el proceso

Esta es la configuración que vamos a utilizar siempre para hacer pruebas. La configuración RUN File no la cambiaremos: está para lo que está: ejecutar un programa python desde su propio directorio
Abrimos el fichero launch.json y añadimos una nueva configuración. Esto se puede hacer con el asistente, pinchando en el botón Add Configuration. En esta animación se muestra el proceso:

Editamos la nueva configuración para ponerla como esta. Ahora en vez de en el terminal interno de vscode queremos que se ejecute en el terminal integrado (integratedTerminal)
{
"name": "RUN file 2",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"justMyCode": true,
"cwd": "${workspaceFolder}/${relativeFileDirname}"
},Guardamos el fichero launch.json, que ahora tiene las dos configuraciones. Nos vamos a la zona de depuración y seleccionamos en el desplegable la nueva configuración RUN File 2

Ejecutamos el programa. Efectivamente ahora la salida sale en la consola integrada de VSCode, en lugar de en la consola de depuración

Modificamos la configuración RUN File 2 para ejecutar en la consola externa, y comprobar las diferencias. Este es la nueva configuración:
{
"name": "RUN file 2",
"type": "debugpy",
"request": "launch",
"program": "${file}",
//-- Terminal ejecutar el programa
"console": "externalTerminal",
//"console": "integratedTerminal",
//"console": "internalConsole",
"justMyCode": true,
"cwd": "${workspaceFolder}/${relativeFileDirname}"
},Cuando se ejecuta en un terminal externo, este se cierra en cuanto la simulación finaliza. Por ello ponemos un Breakpoint en la última línea, y logramos que no se cierre. Para ejecutarlo seleccionamos la configuración RUN File 2 y pinchamos en el botón de play

Se abre un terminal externo y se ejecuta el programa. Se para en la última línea (donde hemos puesto el Breakpoint)

Si ahora le damos a continuar, la ejecución termina y el terminal se cierra
En esta animación lo vemos en acción:

Note
Esta es una sección más avanzada, para conocer los detalles internos del depurador. La puedes saltar si quieres
La arquitectura del depurador integrado del VScode se basa en el protocolo DAP (Debug Adapter Protocol). La idea es dividir la depuración en dos partes: un front end y un back end. El front-end es la parte visual, que integra la interfaz gráfica. En nuestro caso es la que provee el VSCode. El back-end es un servidor que escucha en un puerto las peticiones del front-end, y que implementa el motor de depuración: el depurador en sí. Ambas partes, front-end y back-end se comunican siguiendo las reglas definidas en el protocolo DAP
La parte del servidor que implementa el protocolo DAP se denomina adaptador. La idea es crear adaptadores para cada uno de los depuradores ya existentes, que todavía no implementan el protocolo DAP (por ejemplo el GDB)
En esta figura se muestra la arquitectura
Para el caso de python, el back-end que se usa es Debugpy
El funcionamiento es el siguiente: Cuando se lanza el servidor queda a la escucha en un puerto. El VSCode, cuando entra en modo depuración, se conecta con el servidor, a través de ese puerto. Utilizando el protocolo DAP el VSCode se comunica con el depurador. Se intercambian información como por ejemplo la posición de los Breakpoints, que se ejecute un paso de depuración, cuándo se ha alcanzado un breakpoint, etc...
El servidor de depuración lo tiene que lanzar alguien antes de que el cliente se conecte para iniciar la depuración. Cuando trabajamos con el VSCode este lanzamiento se puede hacer de las siguientes formas:
- Automático: El servidor lo arranca el propio VSCode, en un puerto elegido por él, y se conecta a él al iniciar la depuración. Esto se hace de manera transparente al usuario
- Manual: El servidor lo lanza el usuario. En este caso el VSCode sólo tiene que conectarse a él (attach). El modo manual es el que permite realizar una depuración remota. El servidor se puede ejecutar en una máquina diferente (como por ejemplo una raspberry), y la depuración se hace desde el propio VSCode en la máquina local
La ejecución automática es la que hemos estado haciendo hasta ahora, en sus dos modalidades: Directa y usando configuraciones. Cuando lo ejecutamos usando la configuración por defecto, se usa el terminal integrado de VSCode, y en él podemos ver el comando usado por el VSCode para lanzar (launch) el servidor

El comando que se ejecuta es el siguiente:
/usr/bin/env /bin/python /home/obijuan/.vscode/extensions/ms-python.debugpy-2025.0.0-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher 38055 -- /home/obijuan/Develop/Learn-python/wiki/L1/Ejemplos/hola_mundo5.py El servidor que se ejecuta es el que está instalado en la extensión debugpy del VSCode, y en este caso se lanza en el puerto 38055 (pero el puerto cambia cada vez). Como argumento se le pasa el código fuente del programa a depurar. En este caso hola_mundo5.py
Cuando se utiliza una configuración, hay que especificar el modo de lanzamiento. Para que sea una ejecución automática hay que especificiar que la propiedad request sea del tipo launch. Así es como lo hemos hecho con la configuración RUN File
{
"name": "RUN file",
"type": "debugpy",
//-- Lanzar el depurador
"request": "launch",
"program": "${file}",
"console": "internalConsole",
"justMyCode": true,
"cwd": "${workspaceFolder}/${relativeFileDirname}"
}Normalmente usaremos la ejecución automática, pero es interesante conocer la ejecución manual para realizar depuraciones remotas y para comprender mejor la arquitectura del depurador. Para usuarios más avanzandos esta información permite entender cómo podrías construirte tu propio depurador para manejarlo desde la interfaz de VSCode!
Lo primero es crear una configuración para la depuración remota. La llamamos RUN File (remote). Vamos a utilizar el puerto 5678. Ahora especificamos que resquest es de tipo attach, para que se conecte al servidor en vez de lanzarlo
{
"name": "RUN File (remote)",
"type": "debugpy",
//-- Depuración remota: Conectarse al servidor
"request": "attach",
"connect": {
"host": "localhost",
"port": 5678
},
"pathMappings": [
{
"localRoot": "${workspaceFolder}/${relativeFileDirname}",
"remoteRoot": "."
}
]
},Lo siguiente es instalar el paquete debugpy desde Pypi
python -m pip install --upgrade debugpy --break-system-packagesComprobamos que se ha instalado bien. Abrimos un terminal y escribimos el comando python -m debugpy
obijuan@JANEL:~$ python -m debugpy
0.00s - Debugger warning: It seems that frozen modules are being used, which may
0.00s - make the debugger miss breakpoints. Please pass -Xfrozen_modules=off
0.00s - to python to disable frozen modules.
0.00s - Note: Debugging will proceed. Set PYDEVD_DISABLE_FILE_VALIDATION=1 to disable this validation.
debugpy 1.8.12
See https://aka.ms/debugpy for documentation.
Usage: debugpy --listen | --connect
[<host>:]<port>
[--wait-for-client]
[--configure-<name> <value>]...
[--log-to <path>] [--log-to-stderr]
<filename> | -m <module> | -c <code> | --pid <pid>
[<arg>]...
Error: missing target: <filename> | -m <module> | -c <code> | --pid <pid>
obijuan@JANEL:~$Desde un terminal externo lanzamos el servidor (debugpy) pasándole como argumento el fichero que queremos ejecutar/depurar. En este ejemplo utilizaremos el hola_mundo2.py
Este es el comando a ejecutar desde el directorio donde está el fichero hola_mundo.py: python -m debugpy --listen 5678 --wait-for-client ./hola_mundo2.py
Esto es lo que aparece en la consola
obijuan@JANEL:~/Develop/Learn-python/wiki/L1/Ejemplos$ python -m debugpy --listen 5678 --wait-for-client ./hola_mundo2.py
0.00s - Debugger warning: It seems that frozen modules are being used, which may
0.00s - make the debugger miss breakpoints. Please pass -Xfrozen_modules=off
0.00s - to python to disable frozen modules.
0.00s - Note: Debugging will proceed. Set PYDEVD_DISABLE_FILE_VALIDATION=1 to disable this validation.Ahora desde el VSCode abrimos el hola_mundo2.py, entramos en la sección de depuración y seleccionamos la configuración RUN File (remote)

Pinchamos en el botón verde de play para ejecutar el programa. Vemos que se ejecuta con normalidad:

Y en la consola comprobamos que también se ha ejecutado, y vemos la salida:

Al terminar la ejecución el servidor también termina. Si ahora intentamos volver a ejecutar desde el VSCode se produce un error de conexión: No hay servidor al que conectarse

Vamos a repetir el proceso pero poniendo un punto de ruptura desde el VSCode, en la linea 14. Arrancamos el servidor igual que antes y lanzamos la depuración. Desde el VSCode depuramos como ya sabemos. En la consola veremos también la salida actual

En los botones de depuración vemos que el botón para finalizar ya no es el de stop (el cuadrado), sino que es diferente. Esto es debido a que estamos conectados a un servidor externo. El icono simboliza que queremos desconectarnos de ese servidor

Si lo pinchamos, el servidor se detiene, y el VSCode sale del modo de depuración
Cuando se trabaja con Python solemos instalar paquetes externos, que NO forman parte del núcleo de python. Cada proyecto usa sus propias bibliotecas externas, instalando los paquetes correspondientes. Para que no se produzcan problemas con las diferentes versiones de los paquetes instalados, para cada proyecto se crea un entorno virtual de python
Dentro de cada entorno virtual podemos instalar los paquetes que queramos para el proyecto en el que trabajamos, sin influir en el resto de proyectos. Si la instalación se hace global, entonces es cuando ocurrirían problemas de dependencias que queremos evitar
Partimos de un ejemplo que ya tenemos abierto en una pestaña del VSCode (Por ejemplo el hola_mundo5.py). En la parte inferior derecha vemos que nos pone la versión de python que se está utilizando actualmente. En nuestro caso es la que está instalada en el sistema (Python 3.12.3). Pinchamos con el ratón en ella. Se nos abre una ventana nueva donde seleccionamos el intérprete de python a utilizar. Como lo que queremos es crear un entorno virtual nuevo, pinchamos en la opción Create Virtual Environment...

Nos aparece una nueva ventana. Indicamos que queremos crear un entorno virtual Venv

Ahora seleccionamos qué versión de python, de las que tenemos instaladas en el sistema, queremos utilizar. Lo normal es usar la que viene marcada por defecto:

Se nos crea el entorno virtual, y se empieza a usar automáticamente. En la parte inferior derecha vemos que efectivamente lo que se está usando es el entorno virtual

En la parte izquierda, en el navegador de ficheros, vemos que se ha creado una carpeta nueva: .venv. Ahí es donde se encuentra instalado el entorno virtual. Se añade automáticamente un fichero .gitignore para que ese directorio no se incluya como parte del proyecto

Una vez creado el entorno virtual, VSCode lo utilizará por defecto. Todas las ejecuciónes y depuraciones que hagamos se harán dentro de ese entorno virtual
Si abrimos un terminal integrado, observamos en el prompt que aparece el prefijo (.venv), que indica que estamos dentro de ese entorno virtual

Para comprobar que funciona ejecutamos el comando python --version para ver la versión, y ejecutamos el hola mundo directamente desde la consola integrada: python hola_mundo.py

Todos los paquetes de python creados por la comunidad están disponibles en el repositorio Pypi y se gestionan a través de la herramienta pip, que funciona en la línea de comandos
Esta herramienta queda instalada cuando creamos el entorno virtual. Desde VSCode no hay más que abrir un terminal integrado y ejecutar el comando pip correspondiente
Sin embargo, desde VSCode también tenemos la opción de utilizar la extensión pip manager que nos permite gestionar los paquetes utilizando la interfaz gráfica
La instalación de pip manager es directa. Basta con ir a las extensiones, localizar el pip-manager e instalarlo

Una vez instalado, veremos que en la parte izquierda aparece un nuevo icono. Si pinchamos sobre él nos aparecen todos los paquetes instalados en el entorno virtual de python. Si lo acabamos de crear y todavía no hemos instalado nada adicional, el único paquete que aparecerá sera pip

Para comprobar el funcionamiento de los paquetes, y hacer pruebas de instalación, vamos a usar el paquete Colorama que permite imprimir texto en color en la consola. En la siguiente sesión veremos más detenidamente cómo imprimir en colores
Este es el programa:
# ──────────────────────────────────────────────────────
# ── Hola mundo 6: Usando el paquete colorama
# ──────────────────────────────────────────────────────
# ── Imprimir mensajes "Hola mundo" en colores...
# ──────────────────────────────────────────────────────
import colorama
print("══════════════════════════════")
print("Hola mundo normal...")
print(f"{colorama.Fore.RED}Hola mundo en rojo...")
print(f"{colorama.Fore.GREEN}Hola mundo en verde...")
#-- Reseteamos el color
print(colorama.Style.RESET_ALL, end="")
print("──────────────────────────────")Como todavía no tenemos el paquete colorama instalado esto es lo que ocurre al abrir el ejemplo:

Se marca en amarillo el nombre del paquete, para indicar que hay un error. También se pone en amarillo el nombre del fichero. Si pasamos el cursor por encima vermos el mensaje de error:

Si ejecutamos el programa, aparece un mensaje de error, y se ABORTA la ejecución:

La solución es instalar el paquete colorama
La herramienta pip es un gestor de paquetes. Esto significa que nos permite instalar un paquete junto a todas sus dependencias. No hace falta instalar las dependencias, se instalan automáticamente
Como ejemplo vamos a instalar el paquete colorama
La instalación de paquetes se realiza con el comando pip install <nombre paquete>. Abrimos un terminal integrado de VSCode y ejecutamos el comando pip install colorama. Como no hemos especificado la versión por defecto se instala la última

Entramos en el pip-manager y pinchamos en el botón + para añadir paquetes

En la caja que aparece escribimos el paquete a instalar: colorama en nuestro caso

Comienza la instalación...

Al cabo de unos segundos se instala el paquete y lo podemos ver en la parte de la izquierda. Este paquete no tiene dependencias. Si así fuese, veríamos también todas las dependencias instaladas

Ahora que ya está instalado el paquete colorama abrimos el ejemplo 6 y vemos que ya NO aparece ningún mensaje de error

Procedemos a ejecutarlo. En vez de ejecutarlo dando al botón de play, lo vamos a ejecutar directamente desde el terminal integrado para que se muestren los colores de manera correcta (en la consola de depuración los colores cambian)

Ahora se ejecuta el programa correctamente, y vemos los mensajes en los diferentes colores
También lo podemos ejecutar normalmente desde la ventana de depuración, pero ahora los colores cambian ligeramente

Los paquetes instalados en el entorno virtual se pueden ver directamente desde pip-manager, en la parte de la izquierda

Pero también lo podemos hacer desde la consola integrada ejecutando el comando pip list

Los paquetes también los podemos eliminar desde la línea comandos o bien gráficamente desde pip-manager
Para eliminar paquetes desde la línea de comando hay que ejecutar el comando: pip uninstall <nombre-paquete>. Por ejemplo, si queremos desinstalar el paquete colorama ejecutamos pip uninstall colorama

Nos metemos primero en el pip-manage donde vemos todos los paquetes instalados. Ponemos el ratón sobre el paquete que queremos eliminar (colorama en nuestro caso) y pulsamos el botón derecho. En las propiedades que aparecen pinchamos en remove

El paquete se elimina automáticamente

Cuando trabajamos en un proyecto vamos añadiendo paquetes manualmente, según los vamos necesitando. Llega un momento en el que ya tenemos varios instalados, junto a todas sus dependencias. Normalmente son bastantes paquetes
En cualquier instante podemos obtener un listado de TODOS los paquetes necesarios para nuestro proyecto. Para ello utilizamos el comando pip freeze
Como ejemplo hemos instalado el paquete black (que es un formateador de código python, que usaremos en la siguiente sección). Este paquete tiene varias dependencias. Estos son los paquetes que tenemos instalados:

Utilizando el comando pip freeze obtenemos un listado en modo texto, junto con las versiones:

Típicamente esta salida la redirigimos al fichero requirements.txt, que luego usamos para instalar todos esos paquetes de golpe. El comando que ejecutamos es pip freeeze > requirements.txt. Este fichero de texto lo podemos abrir y explorar

Este es su contenido:
black==25.1.0
click==8.1.8
colorama==0.4.6
mypy-extensions==1.0.0
packaging==24.2
pathspec==0.12.1
platformdirs==4.3.6
Si partimos de un proyecto recién clonado del github, hay que crear el entorno virtual e instalar TODOS los paquetes necesarios para su funcionamiento. Eso lo hacemos fácilmente con este comando: pip install -r requirements.txt

Existen herramientas que formatean el código automáticamente por nosotros. Esto garantiza que sea más legible, y con un estilo unificado. Se llaman formateadores de código. Existen muchos. Uno muy popular en python es Black
Black está disponible como un paquete en Pypi, por lo tanto se instala como ya hemos visto en la sección anterior. Bien gráficamente o bien en la consola ejecutando el comando pip install black
Una vez instalado lo veremos entre los paquetes, junto a sus dependencias. En el pantallazo se muestra tanto en el modo gráfico como en la consola:

Además vamos a instalar la extensión Black formatter de VSCode

Para comprobar el funcionamiento vamos a usar este programa que está sin formatear
# ──────────────────────────────────────────────────────
# ── Programa de prueba para Black (sin formatear) ───
# ──────────────────────────────────────────────────────
import colorama
def test ( ) :
print ( "Mensaje 1" )
print( "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" )
print ( "Mensaje 2")
print ( "──────────────────────────────" )
print( "══════════════════════════════" )
print( f"{colorama.Fore.RED}Hola mundo en rojo..." )
for i in range(4,20,2) :
print( i )
test ( )
print( "──────────────────────────────" )Lo abrimos desde VSCode. Este es el aspecto que tiene:

Para formatearlo desde la línea de comandos abrimos el terminal integrado de vSCode desde el directorio donde está el programa a formatear y ejecutamos el comando black Black-test.py. El código se reformaterará automáticamente y se refrescará en el editor:

Así es como queda el código ya formateado:
# ──────────────────────────────────────────────────────
# ── Programa de prueba para Black (sin formateear) ───
# ──────────────────────────────────────────────────────
import colorama
def test():
print("Mensaje 1")
print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
print("Mensaje 2")
print("──────────────────────────────")
print("══════════════════════════════")
print(f"{colorama.Fore.RED}Hola mundo en rojo...")
for i in range(4, 20, 2):
print(i)
test()
print("──────────────────────────────")Desde la pestaña donde tenemos abierto el programa a formatear pinchamos con el botón derecho del ratón y seleccionamos la opción Format Document

El código se formatea automáticamente

En esta animación lo vemos en funcionamiento

Existen unas herramientas denominadas linters que analizan el estilo del código y nos avisan cuando estamos usando prácticas de programación no muy buenas. En python hay una guía de estilo descrita en el documento pep8. Los linters para python se adhieren a esta guía, y nos marcan los puntos donde NO se está cumpliendo
Dos de los linters más populares son Flake8 y pylint. En esta guía vamos a usar el primero: Flake8
Flake8 está disponible como un paquete en Pypi. Lo instalamos bien gráficamente a través del pip-manager o bien en la consola ejecutando el comando pip install flake8
Una vez instalado lo veremos entre los paquetes, junto a sus dependencias. En el pantallazo se muestra tanto en el modo gráfico como en la consola. Está instalado flake8 junto con Black

Además vamos a instalar la extensión Flake8 de VSCode

Para comprobar el funcionamiento vamos a usar el mismo programa que empleamos con Black: Black-test.py. Lo vamos a probar tanto gráficamente como en línea de comandos
En la pestaña activa de VSCode mostramos el ficheros que queremos comprobar. Abrimos el terminal integrado de VSCode en el directorio donde está el programa a evaluar y ejecutamos el comando flake8 Black-test.py. En la consola veremos todos los Errores de estilo cometidos, junto con su identificador correspondiente y la posición (línea, columna) donde se ha producido

Aquí lo pongo en modo texto, para poder copiar y pegar partes:
(.venv) obijuan@JANEL:~/Develop/Learn-python/wiki/L1/Ejemplos$ flake8 Black-test.py
Black-test.py:7:9: E211 whitespace before '('
Black-test.py:7:14: E201 whitespace after '('
Black-test.py:7:17: E202 whitespace before ')'
Black-test.py:7:22: E203 whitespace before ':'
Black-test.py:11:5: E303 too many blank lines (3)
Black-test.py:11:10: E271 multiple spaces after keyword
Black-test.py:11:10: E211 whitespace before '('
Black-test.py:11:17: E201 whitespace after '('
Black-test.py:11:36: E202 whitespace before ')'
Black-test.py:12:11: E201 whitespace after '('
Black-test.py:12:48: E202 whitespace before ')'
Black-test.py:13:10: E271 multiple spaces after keyword
Black-test.py:13:10: E211 whitespace before '('
Black-test.py:13:17: E201 whitespace after '('
Black-test.py:13:32: W291 trailing whitespace
Black-test.py:14:10: E271 multiple spaces after keyword
Black-test.py:14:10: E211 whitespace before '('
Black-test.py:14:14: E201 whitespace after '('
Black-test.py:14:56: E202 whitespace before ')'
Black-test.py:15:1: E305 expected 2 blank lines after class or function definition, found 0
Black-test.py:15:7: E201 whitespace after '('
Black-test.py:15:50: E202 whitespace before ')'
Black-test.py:16:7: E201 whitespace after '('
Black-test.py:16:55: E202 whitespace before ')'
Black-test.py:17:6: E272 multiple spaces before keyword
Black-test.py:17:11: E271 multiple spaces after keyword
Black-test.py:17:21: E231 missing whitespace after ','
Black-test.py:17:24: E231 missing whitespace after ','
Black-test.py:17:30: E203 whitespace before ':'
Black-test.py:18:11: E201 whitespace after '('
Black-test.py:18:19: E202 whitespace before ')'
Black-test.py:20:5: E211 whitespace before '('
Black-test.py:20:7: E201 whitespace after '('
Black-test.py:20:11: E202 whitespace before ')'
Black-test.py:25:1: E303 too many blank lines (4)
Black-test.py:25:7: E201 whitespace after '('
Black-test.py:25:46: E202 whitespace before ')'
Black-test.py:33:1: W391 blank line at end of fileLa descripción de todas las reglas violadas se puede consultar en este enlace: Flake8 Rules
Vamos a analizar el primer mensaje de error, que tiene el código E211. Encontramos más información en este enlace: E211: White space before '('. Este error se produce porque hay un espacio innecesario entre el nombre de la función y el paréntesis de apertura (
Para corregirlo hay que situarse primero en el lugar donde se ha producido el error. Eso se hace fácilmente colocando el ratón sobre el mensaje Black-test.py:7:9: y pulsando el botón izquierdo del ratón a la vez que la tecla control. El cursor se nos sitúa automáticamente en esa posición, para que solucionemos el error. En esta animación lo vemos en acción:

Con el cursor situado en la nueva posición eliminamos los espacios, guardamos el fichero, y volvemos a invocar Flake8. Ahora ya NO aparece ese error

Al instalar la extensión Flake8 se llama automáticamente al Flake8 cada vez que se guarda el fichero. Desde el editor NO hay que hacer nada, simplemente observar TODOS los errores marcados, y corregirlos. Eso sí, cada vez que se solucione uno hay que guardar el fichero para que se vuelva a procesar y se refresquen los errores

Vamos a fijarnos en el primer error. Vemos que el nombre de la función test está marcado en rojo. Colocamos el cursor encima de test para que se nos muestre el error:

Lo corregimos: quitamos los espacios entre test y el paréntesis de apertura (. Al guardar el fichero vemos que el error desaparece

Si tenemos instalada la extensión de Flake8, cada vez que guardamos el fichero se invoca Flake8 y se muestran los errores de estilo actuales. Puede haber situaciones en las que nos interese que no se muestren esos errores. O nos puede interesar pasar al modo manual. En esos casos lo que podemos hacer es deshabilitar la extesión Flake8. Basta con ir a la parte de extensiones, buscar la de Flake8 y pulsar el botón de Deshabilitar la extensión

Las pruebas unitarias (o test unitarios) se utilizan para comprobar que las funciones y clases funcionan correctamente cuando se prueban individualmente. Estos tests son programas que llaman a estas funciones y comprueban el resultado devuelto
Las pruebas unitarias se pueden hacer directamente como cualquier otro programa python. Y por tanto las podemos ejecutar y depurar como ya sabemos
Sin embargo, normalmente se utilizan módulos python especializados que nos facilitan la programación de los tests, su ejecución y la posterior recoleción de estadísticas. Los paquetes más populares para pruebas unitarias en python son unittest y pytest
El paquete unittest es el que vamos a probar en esta sección. Es el que viene por defecto en python, por lo que NO HAY QUE instalar nada adicional
Comenzamos haciendo un programa de prueba que incluye 3 tests. El primer test simplemente imprime mensajes en la consola. El segundo comprueba el valor de una variable y finalmente el tercero siempre falla
El programa se llama test_L1.py y lo situamos en el mismo directorio donde tenemos los otros programas de python

Este es el programa en modo texto:
import unittest
class TestL1(unittest.TestCase):
def test_print(self):
# -- Esta prueba sólo imprime en la consola
# -- Realmente no se comprueba nada
print("══════════════════════════════")
print("Mensaje 1")
print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
print("✅ Test 1: OK")
def test_var(self):
# -- Asignar un valor a la variable
a = 1
# -- Comprobar que la variable es igual a 1
self.assertEqual(a, 1)
print("✅ Test 2: OK")
def test_fail(self):
# -- Este test siempre falla
self.assertFalse(True)
print("✅ Test 3: OK")
if __name__ == "__main__":
unittest.main()Los ficheros de test los nombramos con el prefijo test_. En este caso sólo tenemos 1 único fichero, pero normalmente habrá varios. Dentro cada fichero de test, importamos el módulo unittest
Las tres pruebas las creamos como métodos de la clase TestL1. Es importante que las clases de prueba siempre comiencen por el prefijo Test para que unittest las detecte y las ejecute
Fuera de la clase, en el programa principal, ejecutamos unnittest.main() que es el módulo principal de pruebas. Este se encarga de llamar, a su vez, a los métodos de prueba definidos en la clase TestL1
Note
No hay que indicar en ningún lugar la clase donde están situados los métodos de prueba. Basta con que el nombre de la clase comience por Test. El paquete unittest hace el resto
En este primer test no se comprueba nada. Simplemente se imprimen mensajes en la consola y luego termina. Es un hola mundo. Es un test que SIEMPRE se pasará
def test_print(self):
print("══════════════════════════════")
print("Mensaje 1")
print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
print("✅ Test 1: OK")En este segundo test se comprueba que la variable a tenga el valor 1. Primero se le asigna el valor 1, y luego se comprueba que efectivamente tiene ese valor, llamando al método assertEqual() del módulo unittest. Este método está en realidad en la clase TestL1, que los ha heredado de su clase padre unittest.TestCase
def test_var(self):
# -- Asignar un valor a la variable
a = 1
# -- Comprobar que la variable es igual a 1
self.assertEqual(a, 1)
print("✅ Test 2: OK")Este test siempre se cumple (porque asignamos 1 a la variable a siempre)
En este test se utiliza el método assertFalse() que comprueba si el parámetro pasado es el valor booleano False. Pero le pasamos (a posta) el valor True para forzar el error y que falle el test
def test_fail(self):
# -- Este test siempre falla
self.assertFalse(True)
print("✅ Test 3: OK")Este siempre siempre falla. Si cambiamos el valor a False entonces el test sí que pasará. Usaremos esto para hacer pruebas
Los test son programas de python, y por lo tanto los podemos ejecutar como ya sabemos. En esta sección los vamos a probarlos de 3 formas diferentes. En la siguiente utilizaremos la interfaz gráfica del VSCode
Abrimos el programa de test en una pestaña y pinchamos en el botón de Play. Se abre el terminal, se ejecuta el programa y se muestra su salida

Esta es la salida en la consola:
(.venv) obijuan@JANEL:~/Develop/Learn-python$ /home/obijuan/Develop/Learn-python/.venv/bin/python /home/obijuan/Develop/Learn-python/wiki/L1/Ejemplos/test_L1.py
F══════════════════════════════
Mensaje 1
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ Test 1: OK
.✅ Test 2: OK
.
======================================================================
FAIL: test_fail (__main__.TestL1.test_fail)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/obijuan/Develop/Learn-python/wiki/L1/Ejemplos/test_L1.py", line 24, in test_fail
self.assertFalse(True)
AssertionError: True is not false
----------------------------------------------------------------------
Ran 3 tests in 0.000s
FAILED (failures=1)
(.venv) obijuan@JANEL:~/Develop/Learn-python$Comprobamos que los dos primeros tests se ejecutan completamente, pero el tercero falla. En la parte final se muestran la cantidad de tests (3) y que ha fallado uno
El test se puede ejecutar directamente desde un terminal, interno o externo. En este pantallazo vemos su ejecución en el Terminal integrado de VSCode

Vamos a depurar. Ponemos un Breakpont en el test1 (línea 12) y pinchamos en el botón de play de depuración

Se abre el terminal para mostrar la salida por la consola y el programa se detiene en la línea 12

Si damos un paso se termina el test 1 y pasa automáticamente al test 2

Si pinchamos en continuar se ejecuta hasta al final. PERO como el último test falla, se produce una excepción y el programa se detiene. El depurador muestra un mensaje en Rojo

La extensión de python del VSCode incluye una sección especial de Test, situado en la parte izquierda. Esto nos va a permitir ejecutar los test gráficamente, muy fácilmente, y sobre todo ver los resultados rápidamente. También nos permite ejecutar individualmente cada uno de los tests
Para ponerla en marcha primero hay que configurarla
Lo primero que hacemos es abrir en una pestaña el programa de test y pinchar en el icono de Tests de la parte izquierda

Pinchamos en configura Python Tests y luego seleccionamos unittest

Ahora hay que seleccionar el directorio donde están los test. En nuestro caso marcamos wiki

Warning
Los tests los tenemos en wiki/L1/Ejemplos pero en esta versión de la extensión de python no nos permite navegar. Así que luego lo tendremos que cambiar manualmente en el fichero settings.json
Ahora seleccionamos el patrón para la identificación de los ficheros de test, que en nuestro caso será test_*.py

Lo que hemos ejecutado es un asistente que nos ha creado la configuración de unittest en el fichero settings.json. Vemos este fichero, que está en el directorio .vscode

Editamos la ruta de los tests, para poner la nuestra. En este tutorial la ruta es: ./wiki/L1/Ejemplos

Este es el fichero settings.json
{
"python.testing.unittestArgs": [
"-v",
"-s",
"./wiki/L1/Ejemplos",
"-p",
"test_*.py"
],
"python.testing.pytestEnabled": false,
"python.testing.unittestEnabled": true
}¡Ya tenemos configurados los Tests! Si nos vamos ahora a la sección de Test vemos su estado: todavía no se han ejecutado

Para ejecutar los tests pinchamos en el icono de Play de la parte superior izquierda. Se ejecutan TODOS los test y se muestra el resumen en la parte izquierda. En nuestro caso se han ejecutado 3 tests, de cuales 2 han funcionado (en verde) y 1 ha fallado (en rojo). Este mismo resultado lo vemos en la ventana de la parte inferior derecha

Dentro del fichero de test, también vemos en la parte izquierda el resultado de cada test: verde si lo ha pasado y rojo si no. Esto es MUY CÓMODO!! Sobre todo cuando se tienen muchos tests.

En el caso del test que ha fallado, además, hay información adicional. Si pinchamos sobre la etiqueta roja, se despliega y vemos todos los detalles

Para eliminar los errores y todos los resultados y poder ver el código como en la situación inicial pinchamos en el botón de la parte superior derecha y seleccionamos la opción Clear All Results

Se vuelve a la situación inicial

Para ejecutar los test en modo depuración basta con colocar un punto de ruptura en el test a depurar, y pinchar en el botón de depuración de la parte superior izquierda

La ejecución se detiene en el punto indicado, y a partir de aquí ya podemos ejecutar paso a paso y ver las variables

Es posible ejecutar cada uno de los test individualmente sin más que apretar el botón de play verde situado en la pestaña de edición a la izquierda del nombre de la función de test
Por ejemplo, vamos a ejecutar sólo el test 2. Pinchamos en su botón correspondiente de ejecución

Este es el resultado. El test 2 se pone en verde porque lo ha pasado. Pero el resto de test se quedan sin ejecutar

Hemos aprendido a configurar el VSCode para trabajar con Python. Ya sabemos cómo ejecutar un programa, cómo depurarlo (ejecución paso a paso) y cómo crear configuraciones de depuración. También sabemos cómo crear un entorno virtual en el que podemos instalar paquetes de python. Hemos visto cómo configurar y usar las herramientas para formatear el código automáticamente y detectar las violaciones del estilo. Finalmente hemos aprendido a configurar los Tests Unitarios, y a usarlos desde la interfaz gráfica del VSCode
Ya tenemos todos los conocimientos necesarios para hacer nuestros proyectos con VSCode y Python. También tenemos el entorno listo para aprender más sobre python
- Juan González-Gómez (Obijuan)