Hello World con Python y PyCharm

Python es uno de los lenguajes de programación más populares (no lo digo yo, lo dice la encuesta anual de Stack Overflow), y PyCharm es uno de los principales IDE para programar en Python (junto a Visual Studio Code, son las dos principales opciones), al proporcionar auto-completación de código, depuración avanzada, integración con Git, gestión de paquetes o librerías, refactorización de código, extensión mediante Plugins, y mucho más. En este Post vamos a explicar a través de un ejemplo, cómo crear un nuevo Proyecto en PyCharm, y aclarar las dudas habituales, como la gestión de los Virtual Environment, integración con Git y/o GitHub, ejecutar y depurar, Dockerizar nuestro programa, ejecutarlo con Docker Compose, añadir un README y una Licencia Open Source, etc.

Comenzamos una nueva serie de Posts, en este caso sobre Python, uno de los principales lenguajes de programación hoy en día, multidisciplinar, y con un gran crecimiento y popularidad, y para comenzar, qué mejor que hacer un sencillo programa «Hello World» en que podamos ver cómo trabajar con Python, utilizando un IDE en particular (en nuestro caso es PyCharm), y aclarar los típicos detalles iniciales y proporcionar ejemplos (ej: Dockerfile, Docker Compose, README, .gitignore, LICENSE, etc.).

Para este Post, partimos de un entorno formado por un portátil con Windows 11, en el que además de PyCharm, tenemos también ya instalado tanto Docker Desktop como MiniKube. Comenzamos.

Creación de un nuevo Proyecto Python con PyCharm

Partimos de un equipo con Windows 11 y PyCharm Community recién instalado, en particular, la versión 2022.2.3. Vamos a crear un nuevo Proyecto de Python con PyCharm. Para ello, abrimos PyCharm, y hacemos click en New Project.

En el diálogo de nuevo Proyecto tendremos que especificar varias cosas, principalmente las siguientes:

  • Ubicación del Proyecto (Location). Es un tema un poco personal, según se quiera organizar cada uno. Muchos programadores se crean una carpeta donde crean subcarpetas para cada uno de sus Proyectos (ej: c:\code), indiferentemente del lenguaje de programación, herramienta (ej: PyCharm, VSCode, Fleet, etc.), o tecnología, en lugar de utilizar la ruta por defecto de PyCharm (C:\Users\guill\PycharmProjects\), para tenerlo todo junto, mientras que otros programadores se conforman con la ruta que propone el propio IDE (en este caso PyCharm). En mi caso, voy a utilizar un directorio code por debajo de mi home, sobre el que ubicar todos mis Proyectos.
  • Virtual Environment. También es un tema personal, principalmente tenemos dos opciones para gestionar los Virtual Environments cuando tengamos que crear uno nuevo, aunque es posible utilizar uno existente (incluso compartirlo entre varios Proyectos).
    • Almacenar los Virtual Environment fuera del directorio del propio Proyecto. Tiene ventajas, ya que facilita poder compartir un mismo Virtual Environment entre varios Proyectos (esto es también un inconveniente, ya que produce acoplamiento) si marcamos la opción «Make available to all projects«, y además, si eliminamos el Proyecto de nuestro disco y nos lo volvemos a descargar del repo remoto (git clone), estaremos manteniendo nuestro Virtual Environment tal y cómo lo teníamos (permite hacer las cosas repetibles).
    • Dejarlo dentro del directorio del Proyecto, y añadirlo como exclusión al fichero .gitignore para evitar subir porquería al repo cuando hagamos un Push. En mi caso, me decanto por esta opción, ya que apoyándonos en un fichero requirements.txt con el detalle de librerías y versioens a importar, conseguimos hacer las cosas repetibles, y que cualquier compañero se pueda descargar nuestro repo y construirse su propio Virtual Environment rápidamente y equivalente al nuestro.

Una vez creado nuestro Proyecto, podemos abrir la ventana Terminal, donde tendremos una CLI con nuestro Virtual Environment activado. Es posible que nos encontremos el siguiente error de PowerShell, indicando que no ha podido activar el Virtual Environment porque el Script que se utiliza para tal fin no está firmado digitalmente, y no lo permite la actual política de ejecución de PowerShell.

La solución es bastante sencilla, es suficiente con cambiar la política de ejecución de PowerShell, ejecutando el siguiente comando Set-ExecutionPolicy en una ventana de PowerShell, y seguidamente cerrar y volver a abrir PyCharm. Ahora, ya podemos abrir nuestra ventana de Terminal sin errores.

Paquetería, Virtual Environments, y requirements.txt

Para trabajar con Python es fundamental familiarizarnos con los Virtual Environments de Python y con los ficheros requirements.txt, para hacer una correcta gestión de las librerías o paquetes que necesita nuestro Proyecto.

Podemos crearnos un Virtual Environment, tomando como base una versión concreta de Python (ej: Python 3.9), y sobre el mismo importar las librerías o paquetes que necesitemos para poder ejecutar correctamente nuestro programa. Es muy importante definir bien estas librerías y la versión de las mismas , ya que en futuras versiones puede haber cambios disruptivos en las mismas, y si queremos poder hacer funcionar nuestro código de forma sencilla (que sea repetible), es fundamental tener identificada tanto la librería como la versión apropiada, o acabaremos con un espagueti de dependencias que puede ser difícil de resolver.

Relacionado con esto, podemos crearnos un fichero requirements.txt con incluya el detalle de librerías y versiones de las mismas. Esto es una práctica habitual, y además podremos sincronizar el contenido del requirements.txt con nuestro Virtual Environment, de forma sencilla.

Vamos a ver esto en más detalle con PyCharm.

Una vez creado el Proyecto, podemos acceder a la configuración del Virtual Environment desde File -> Settings -> Project -> Python Interpreter, para ver el detalle de las librerías y versiones que tenemos importadas, así como podríamos importar manualmentes nuevas o quitar alguna de las existentes… aunque lo suyo es no hacerlo así, sino con un requirements.txt como vamos a ver ahora después. También podemos utilizar la ventana de herramientas de Python Packages. En la siguiente imagen, se representan ambas opciones.

Lo suyo es tener un fichero requirements.txt, ya sea en la raíz del Proyecto o en alguna otra ubicación (la raíz es quizás lo más habitual), donde incluyamos el detalle de las librerías que necesitemos y su versión. Al abrir el fichero requirements.txt desde PyCharm, se identificarán automáticamente los requisitos que no se cumplen, y PyCharm propondrá automáticamente instalar todas las librerías necesarias, como se ve en la siguiente pantalla capturada. Click en «Install requirements», y listo.

Esta es la opción ideal, porque podemos subir nuestro Proyecto a un repo, y cuando un compañero se lo baje a su PC, con instalarse las librerías del requirements.txt (super fácil), podrá ejecutar nuestro Proyecto sin problemas.

Otro detalle que nos puede interesar conocer. Si aún no tenemos generado nuestro fichero requirements.txt, y hemos estado añadiendo manualmente las librerías a nuestro Virtual Environment, podemos generar el fichero requirements.txt en base a las librerías actualmente importadas en nuestro Virtual Environment. Para ello, abriremos una ventana de Terminal dentro de PyCharm, y ejecutaremos el comando pip freeze de forma similar a como se muestra en la siguiente pantalla capturada.

Integración con Git en PyCharm

Lo más probable, es que necesitemos subir nuestro Proyecto a un repo Git, ya sea en un repo personal como podría ser GitHub, o bien en un repo empresarial (sea GitHub, GitLab, Bitbucket, Azure DevOps, o el que toque). Vamos a ver cómo hacerlo con PyCharm.

Para habilitar la integración con Git en un Proyecto Python de PyCharm, utilizaremos la opción VCS -> Enable Version Control Integration.

Esto nos mostrará un diálogo que nos preguntará qué tipo de integración deseamos (git, mercurial, ó subversion), a lo que seleccionaremos Git y click OK.

Con esto, tendremos habilitado nuestro Proyecto con Git en local. Podremos ver que algunos ficheros aparecen en rojo, ya que aún no han sido añadidos a Git. También tenemos disponible una ventana de herramientas de Git, que podemos ver en la parte inferior de la pantalla.

El siguiente paso sería añadir un fichero .gitignore que nos permita excluir los ficheros y directorios que no deban almacenarse en Git. En lugar de partir de un fichero vacío, podemos tomar como punto de partida el .gitignore que propone GitHub, y sobre el mismo añadir o modificar lo que consideremos oportuno: GitHub – Python .gitignore

PyCharm nos preguntará si deseamos añadir el nuevo fichero (.gitignore) a Git, aceptaremos haciendo click en Add.

Al aceptar añadirlo a Git, veremos que aparece en verde (en lugar de rojo). Copiaremos el contenido del .gitignore de Python propuesto por GitHub del enlace anterior, y en nuestro caso, quitaremos el comentario de la última línea, para excluir la carpeta .idea/ que utilizar PyCharm.

Los siguiente es añadir todos los ficheros a git del Proyecto a Git, haciendo click con el botón derecho en la carpeta raíz del Proyecto, y después Git -> Add, tal y como se muestra en la siguiente imagen, y ya los tendremos todos en Git, en local.

En la ventana de Terminal podemos ejecutar comandos Git desde la CLI, por ejemplo, un git status, o lo que queramos. Nos quedaría confirmar los cambios, que si bien también podríamos hacerlo desde la CLI, en PyCharm tenemos la opción Git -> Commit., además de un atajo como botón en la barra de botones superior (tanto al Commit, como a otras acciones de Git).

Al hacer el Commit desde PyCharm, podremos seleccionar qué ficheros (cambios) queremos incluir en dicho Commit así como un comentario para el Commit.

Ahora nos queda poder subir nuestro código a un servidor remoto de Git, ya que por ahora sólo tenemos Git en local. Hemos creado un repo vacío (sin inicializar) en un servidor de Git (un Gitea de Laboratorio). En Pycharm utilizaremos la opción de menú Git -> Manage Remotes para ver y modificar la configuración de repos remotos con los que trabajamos. En nuestro caso, añadiremos un nuevo remoto (origin), con los datos del repo que acabamos de crear.

Ahora que ya tenemos configurado el remote, podemos utilizar la opción Git -> Push para subir nuestro código al repo remoto de Git.

Hecho esto, nuestro repo remoto habrá quedado actualizado. Tenemos más opciones disponibles, tanto en el menú Git de PyCharm, con la hacer click con el botón derecho sobre un fichero o directorio (también nos ofrecerá un menú Git contextual), pudiendo también utilizar el comando git desde la ventana de Terminal, para quienes se sientan más cómodos con la CLI.

Es posible, y de hecho es bastante habitual, trabajar con varios repos remotos. Por ejemplo, podría ser trabajador de una empresa que trabaja para un cliente, y estar desarrollando en la empresa con el repo remoto de la empresa para la que trabajo, y de forma periódica subir los cambios al repo del cliente. Y como este caso, hay muchos más.

En nuestro caso, vamos a añadir un remote adicional para GitHub, de tal forma que voy a poder subir los cambios tanto al repo privado que tengo en mi Gitea personal, como a mi repo público de GitHub, para poder compartirlo con la comunidad. Ahora al hacer un Git Push desde PyCharm, podremos elegir contra qué remote ejecutarlo.

El repo público de GitHub es el siguiente (si te gusta, puedes apoyarlo con una estrella): GitHub – ElWillieES / python-hello-world

Ejecutar y Depurar

Ya hemos creado un Proyecto Python con PyCharm, hemos configurado su paquetería (librerías y versiones) y nuestro Virtual Environment, y lo hemos sometido bajo control de cambios con Git, tanto local como subiendo cambios a un repo remoto. Ha llegado el momento de picar código, ejecutar y depurar, con PyCharm.

Escribiremos alguna línea de código, y añadiremos un par de puntos de interrupción, para poder trastear. Tenemos disponible tanto el menú Run, como algunos accesos en la botonera (barra superior), como la ventana de herramientas de Run en la parte de inferior. Podemos ejecutar nuestro programa con la opción de «Run main», de tal modo, que en la ventana de herramientas de Run podemos ver la salida de ejecución, como se ve en el siguiente ejemplo.

Mediante la opción Run, podemos elegir con qué configuración deseamos ejecutar nuestro programa, y tenemos la opción de modificar la configuración actual (main) así como crear configuraciones adicionales. Esto no estan habitual, pero puede haber situaciones que nos venga bien.

Para depurar podemos, poner los puntos de interrupción, y utilizar la opción Debug main (o la opción Debug a secas, que nos permitirá seleccionar la configuración que deseemos) para iniciar la depuración y ejecutar nuestro programa hasta el primer punto de interrupción que encuentre, donde se pausará y podremos inspeccionar variables, ejecutar paso a paso, reanudar la ejecución hasta el siguiente punto de interrupción, etc.

Dockerización de Python

Muchas veces necesitamos que nuestro Proyecto se ejecute Dockerizado (quizás en Kubernetes), por lo que nos puede interesar desarrollar de la forma que hemos visto hasta ahora (de formás rápida, con un Virtual Environment y las funciones de depuración de PyCharm), pero también tener un Dockerfile de Python que cargue el mismo requirements.txt y ejecute nuestro programa en local, de forma similar a como se va a ejecutar en Producción

Siguiendo nuestro ejemplo, podríamos añadir un fichero Dockerfile en la raíz de nuestro Proyecto, con el siguiente contenido, que partiendo de una imagen ligera de Python 3.9, instala las librerías de nuestro requirements.txt, copia nuestro programa, y lo ejecuta al arrancar el contenedor.

FROM python:3.9.15-slim-bullseye

RUN mkdir -p /usr/src/app
COPY requirements.txt /usr/src/app/

WORKDIR /usr/src/app

RUN pip3 install --upgrade pip
RUN pip3 install -r requirements.txt

COPY main.py /usr/src/app/

CMD cd /usr/src/app && python3 main.py

Desde la ventana Terminal, podemos lanzar comandos Docker. Por ejemplo, en el siguiente ejemplo vemos como construir una imagen Docker en local con nuestro programa, listar las imágenes Docker que tenemos en local, y cómo ejecutar un contenedor con nuestro programa utilizando la imagen que acabamos de crear.

docker build -t python-hello-world .
docker images
docker run --rm python-hello-world

Añadiremos los cambios a Git, y los subiremos al repo remoto para no perderlos. En la siguiente pantalla captura, se puede observar el Dockerfile, así como la ventana de Terminal en la que hemos construido nuestra imagen y la hemos ejecutado, para finalmente subir nuestros cambios al repo de Git.

Cuando son Proyectos más complejos quizás no sea suficiente con un único contenedor Docker, y necesitemos arrancar varios contenedores (ej: un Redis, un MySQL, un RabbitMQ, un Kong, un NGINX, etc.). En esos caso es habitual utilizar Docker Compose, de tal modo que podemos incluir en un yml la definición de todo nuestro Proyecto con todos sus componentes (contenedores), y arrancarlo con un único comando.

Vamos a añadir un fichero docker-compose.yml que nos permita ejecutar nuestro Proyecto también con Docker Compose, utilizando el Dockerfile que acabamos de crear. Lo probamos para asegurarnos que funciona correctamente, y lo subimos a nuestro repo remoto de git.
Para ejecutar nuestro Proyecto con Docker Compose podemos ejecutar el siguiente comando.

docker-compose -f docker-compose.yml up --build -d

Ejecución en Kubernetes (MiniKube)

Además de Docker y Docker Compose, si nuestra aplicación acabará corriendo en Kubernetes, necesitaremos también probar nuestra aplicación en Kubernetes, para lo cual vamos a utilizar MiniKube para ejecutar un Cluster de Kubernetes y un Registry Docker sobre nuestro portátil, donde podamos probar con libertad.

Partiendo de la imagen Docker que acabamos de construir, vamos a etiquetar y subirla a nuestro Registry, para luego ejecutar un par de comandos curl para consultar nuestra Imagen ya subida a nuestro Registry.

docker tag python-hello-world localhost:5000/python-hello-world
docker push localhost:5000/python-hello-world

curl http://localhost:5000/v2/python-hello-world/tags/list
curl http://localhost:5000/v2/python-hello-world/manifests/latest

Después, crearemos una carpeta kube en nuestro Proyecto de PyCharm, dentro de la cual crearemos dos ficheros yaml:

  • ns-hello-world.yml – Para el manifiesto del namespace que usaremos para nuestro Proyecto en Kubernetes
  • job-python-hello-world.yml – Para el Job que ejecutará nuestro Contenedor, utilizando la imagen que acabamos de subir al Registry

Realizado esto, en la ventana Terminal de PyCharm, podemos ejecutar los siguientes comandos, para aplicar ambos manifiestos en nuestro Cluster de MiniKube, y consultar el Log de ejecución (será el mismo, que cuando lo ejecutamos en Docker o directamente en PyCharm).

cd kube
kubectl apply -f ns-hello-world.yml
kubectl apply -f job-python-hello-world.yml
kubectl logs job/python-hello-world -n hello-world

Añadiremos estos nuevos ficheros a Git, y los subiremos a nuestro repo.

Añadir un README.md

Un detalle importante, especialmente si trabajamos en equipo o si deseamos compartir nuestro repo con más gente (por ejemplo, como repo público de GitHub), es proporcionar un fichero READEME.md.

En el README.md, podemos hacer una introducción a nuestro Proyecto, describir su arquitectura, indicar el repo y su estructura de ramas y etiquetas, referenciar el proyecto de Jira o de Figma, hablar de los entornos que se usan y del CI/CD, explicar cómo ejecutar el Proyecto en local, incluir una matriz de contactos (personas y roles), y cualquier otra información que deseemos añadir (Release Notes, instrucciones de despliegue y de marcha atrás, detalles de la configuración del proyecto, etc), ya sea en este fichero, o bien incluyendo ficheros adicionales que referenciemos desde el READEME. Si lo hacemos bien, ayudará a la productividad del equipo.

En nuestro caso hemos añadido este README.md y lo hemos subido al repo remoto de Git.

Añádir una Licencia Open Source a nuestro repo

Si lo deseamos podemos añadir una Licencia Open Source a nuestro repo. Hay muchos tipos de Licencia, podemos verlo en más detalles en diferentes fuentes, como GitHub: GitHub – Licensing a repository

De hecho, muchos servidores Git (empezando por GitHub), cuando creas un repo nuevo te permite inicializarlo, incluyendo entre otras cosas el fichero de Licencia que tú eligas. En nuestro caso, vamos a añadir una Licencia Apache 2.0, que permite que las obras derivadas se distribuyan con la Licencia que se desee (es bastante abierta), y subiremos los cambios a nuestro repo remoto.

Plugins de PyCharm

Al igual que ocurre con Visual Studio Code, con PyCharm tenemos disponibles un montón de Plugins que nos podremos instalar para extender nuestro IDE, y hacer nuestro día a día más ágil. Hay muchos, tanto gratuitos cómo de pago, no es fácil hacer una lista, ya que la utilidad dependerá del uso que le de cada uno, y eso no es tan fácil de generalizar.

Podemos acceder a los Plugins, para ver cuáles tenemos instalados y para instalarnos nuevos desde el Marketplace, a través de File -> Settings -> Plugins. El número de descargas y las estrellas, nos ayudarán a identificar la popularidad de los Plugins antes de que nos los instalemos. Podemos instalarnos Plugins para Docker, Terraform, etc.

Un Plugin bastante útil es SonarLint, que ayuda a detectar de forma temprana bugs, vulnerabilidades, y code smells, y puede conectarse con un servidor remoto SonarQube (para más info se puede ver el Post de SonarQube – Introducción e instalación de SonarQube, SonarScanner CLI, y SonarLint).

Una vez instalado el Plugin de SonarLint, tendremos disponible una ventana (por defecto, en la parte inferior de PyCharm) con las opciones del Plugin. Ahí podemos configurar la conexión con nuestro servidor SonarQube (necesitaremos un Token, idealmente de tipo User), y para el Proyecto actual indicar la Project Key correspondiente de Sonar.

Atajos del teclado: Keymaps

PyCharm incluyen un conjunto de atajos de teclado ya predefinidos, que podemos consultar desde Help -> Keyboard shortcuts PDF, lo que nos mostrará un PDF como el siguiente. Hay algunos que nos puede ayudar memorizarlos o tenerlos a mano, para agilizar nuestro día a día.

Si lo deseamos, podemos personalizar los atajos de teclado de nuestra instalación, desde File -> Settings -> Keymap (viene organizado en varias secciones), configurándolo totalmente a nuestro gusto.

Despedida y Cierre

Como primer Post de Python, creo que está bastante bien, hemos visto de seguido varios detalles que nos solemos encontrar siempore que creamos un nuevo Proyecto Python con PyCharm a la vez que hemos intentado conocer un poco este IDE, que es uno de los más populares para programar en Python junto a Visual Studio Code. Hemos visto ejemplos de README, como integrarnos con Git y con GitHub, como ejecutar y depurar nuestro código en local, como Dockerizarlos y ejecutarlo con Docker y con Docker Compose, y otros muchos detalles.

Poco más por hoy. Como siempre, confío que la lectura resulte de interés.