Tutorial 7 - Poner en marcha esta (tercera)fiesta

Hasta ahora, la aplicación que hemos construido sólo ha utilizado nuestro propio código, además del código proporcionado por BeeWare. Sin embargo, en una aplicación del mundo real, es probable que desees utilizar una biblioteca de terceros, descargada del Python Package Index (PyPI).

Vamos a modificar nuestra aplicación para incluir una biblioteca de terceros.

Acceso a una API

Una tarea común que una aplicación necesitará realizar es hacer una petición a una API web para recuperar datos, y mostrar esos datos al usuario. Esta es una aplicación de juguete, así que no tenemos una API real con la que trabajar, así que usaremos la {JSON} Placeholder API como fuente de datos.

El {JSON} Placeholder API tiene una serie de «falsos» puntos finales de la API que puede utilizar como datos de prueba. Una de esas API es el punto final /posts/, que devuelve entradas de blog falsas. Si abre https://jsonplaceholder.typicode.com/posts/42 en su navegador, obtendrá una carga útil JSON que describe una única entrada: algo de contenido Lorum ipsum para una entrada de blog con ID 42.

La biblioteca estándar de Python contiene todas las herramientas necesarias para acceder a una API. Sin embargo, las API incorporadas son de muy bajo nivel. Son buenas implementaciones del protocolo HTTP, pero requieren que el usuario gestione muchos detalles de bajo nivel, como la redirección de URL, las sesiones, la autenticación y la codificación de la carga útil. Como «usuario normal de navegador» probablemente estés acostumbrado a dar por sentado estos detalles, ya que un navegador gestiona estos detalles por ti.

Como resultado, la gente ha desarrollado bibliotecas de terceros que envuelven las APIs integradas y proporcionan una API más simple que se acerca más a la experiencia cotidiana del navegador. Vamos a utilizar una de esas bibliotecas para acceder a la API {JSON} Placeholder - una biblioteca llamada httpx.

Vamos a añadir una llamada a la API httpx a nuestra aplicación. Añade un import al principio de app.py para importar httpx:

import httpx

Luego modifica el callback say_hello() para que se vea así:

def say_hello(self, widget):
    with httpx.Client() as client:
        response = client.get("https://jsonplaceholder.typicode.com/posts/42")

    payload = response.json()

    self.main_window.info_dialog(
        greeting(self.name_input.value),
        payload["body"],
    )

Esto cambiará la llamada de retorno say_hello() para que cuando sea invocada, lo haga:

  • realice una solicitud GET en la API de marcador de posición JSON para obtener el puesto 42;

  • decodificar la respuesta como JSON;

  • extraer el cuerpo del mensaje; y

  • incluir el cuerpo de ese mensaje como texto del diálogo.

Vamos a ejecutar nuestra aplicación actualizada en el modo de desarrollador de Briefcase para comprobar que nuestro cambio ha funcionado.

(beeware-venv) $ briefcase dev
Traceback (most recent call last):
File ".../venv/bin/briefcase", line 5, in <module>
    from briefcase.__main__ import main
File ".../venv/lib/python3.9/site-packages/briefcase/__main__.py", line 3, in <module>
    from .cmdline import parse_cmdline
File ".../venv/lib/python3.9/site-packages/briefcase/cmdline.py", line 6, in <module>
    from briefcase.commands import DevCommand, NewCommand, UpgradeCommand
File ".../venv/lib/python3.9/site-packages/briefcase/commands/__init__.py", line 1, in <module>
    from .build import BuildCommand  # noqa
File ".../venv/lib/python3.9/site-packages/briefcase/commands/build.py", line 5, in <module>
    from .base import BaseCommand, full_options
File ".../venv/lib/python3.9/site-packages/briefcase/commands/base.py", line 14, in <module>
    import httpx
ModuleNotFoundError: No module named 'httpx'

¿Qué ha pasado? Hemos añadido httpx a nuestro código, pero no lo hemos añadido a nuestro entorno virtual de desarrollo. Podemos solucionarlo instalando httpx con pip, y volviendo a ejecutar briefcase dev:

(beeware-venv) $ python -m pip install httpx
(beeware-venv) $ briefcase dev

Cuando introduzcas un nombre y pulses el botón, deberías ver un cuadro de diálogo parecido a:

Hello World Tutorial 7 diálogo, en macOS

Ya tenemos una aplicación que funciona, que utiliza una biblioteca de terceros y que se ejecuta en modo de desarrollo

Ejecutar la aplicación actualizada

Vamos a empaquetar este código de aplicación actualizado como una aplicación independiente. Como hemos hecho cambios en el código, tenemos que seguir los mismos pasos que en Tutorial 4:

Actualice el código en la aplicación empaquetada:

(beeware-venv) $ briefcase update

[helloworld] Updating application code...
...

[helloworld] Application updated.

Reconstruye la aplicación:

(beeware-venv) $ briefcase build

[helloworld] Adhoc signing app...
[helloworld] Built build/helloworld/macos/app/Hello World.app

Y, por último, ejecuta la aplicación:

(beeware-venv) $ briefcase run

[helloworld] Starting app...
===========================================================================

Sin embargo, cuando la aplicación se ejecute, verás un error en la consola y un cuadro de diálogo de bloqueo:

Fallo de la aplicación Hello World Tutorial 7, en macOS

Una vez más, la aplicación no ha podido iniciarse porque httpx ha sido instalado - pero ¿por qué? ¿No hemos instalado ya httpx?

Sí, pero sólo en el entorno de desarrollo. Tu entorno de desarrollo es totalmente local a tu máquina - y sólo se activa cuando lo activas explícitamente. Aunque Briefcase tiene un modo de desarrollo, la principal razón por la que utilizarías Briefcase es para empaquetar tu código y poder dárselo a otra persona.

La única forma de garantizar que alguien más tenga un entorno Python que contenga todo lo que necesita es construir un entorno Python completamente aislado. Esto significa que hay una instalación de Python completamente aislada, y un conjunto de dependencias completamente aislado. Esto es lo que Briefcase construye cuando ejecutas briefcase build - un entorno Python aislado. Esto también explica por qué httpx no está instalado - ha sido instalado en tu entorno de desarrollo, pero no en la aplicación empaquetada.

Por lo tanto, tenemos que decirle a Briefcase que nuestra aplicación tiene una dependencia externa.

Actualización de las dependencias

En el directorio raíz de tu aplicación, hay un archivo llamado pyproject.toml. Este archivo contiene todos los detalles de configuración de la aplicación que proporcionaste cuando ejecutaste briefcase new.

pyproject.toml está dividido en secciones; una de las secciones describe la configuración de tu aplicación:

[tool.briefcase.app.helloworld]
formal_name = "Hello World"
description = "A Tutorial app"
long_description = """More details about the app should go here.
"""
sources = ["src/helloworld"]
requires = []

La opción requires describe las dependencias de nuestra aplicación. Es una lista de cadenas, especificando librerías (y, opcionalmente, versiones) de librerías que quieres que se incluyan con tu app.

Modifique la configuración requires para que diga:

requires = [
    "httpx",
]

Al añadir esta opción, le estamos diciendo a Briefcase «cuando compiles mi aplicación, ejecuta pip install httpx en el paquete de la aplicación». Cualquier cosa que sea una entrada legal para pip install se puede utilizar aquí - por lo que podría especificar:

  • Una versión específica de la biblioteca (por ejemplo, "httpx==0.19.0");

  • Un rango de versiones de la biblioteca (por ejemplo, "httpx>=0.19");

  • Una ruta a un repositorio git (por ejemplo, "git+https://github.com/encode/httpx"); o bien

  • Una ruta de archivo local (No obstante, ten cuidado: si entregas tu código a otra persona, es probable que esta ruta no exista en su máquina)

Más abajo en pyproject.toml, verás otras secciones que dependen del sistema operativo, como [tool.briefcase.app.helloworld.macOS] y [tool.briefcase.app.helloworld.windows]. Estas secciones también tienen una configuración requires. Estas opciones te permiten definir dependencias adicionales específicas de la plataforma; así, por ejemplo, si necesitas una biblioteca específica de la plataforma para manejar algún aspecto de tu aplicación, puedes especificar esa biblioteca en la sección requires específica de la plataforma, y esa opción sólo se utilizará para esa plataforma. Notarás que las librerías toga están todas especificadas en la sección requires específica de la plataforma - esto es porque las librerías necesarias para mostrar una interfaz de usuario son específicas de la plataforma.

En nuestro caso, queremos que httpx se instale en todas las plataformas, por lo que utilizamos el parámetro requires a nivel de aplicación. Las dependencias a nivel de aplicación siempre se instalarán; las dependencias específicas de la plataforma se instalan además de las dependencias a nivel de aplicación.

Algunos paquetes binarios pueden no estar disponibles

En plataformas de escritorio (macOS, Windows, Linux), se puede añadir cualquier pip-instalable a sus requisitos. En plataformas móviles y web, las opciones son ligeramente limitadas <https://briefcase.readthedocs.io/en/latest/background/faq.html#can-i-use-third-party-python-packages-in-my-app>`__.

En resumen; cualquier paquete puro de Python (es decir, paquetes que no contienen un módulo binario) puede ser utilizado sin dificultad. Sin embargo, si su dependencia contiene un componente binario, debe ser compilado; en este momento, la mayoría de los paquetes de Python no proporcionan soporte de compilación para plataformas que no sean de escritorio.

BeeWare puede proporcionar binarios para algunos módulos binarios populares (incluyendo numpy, pandas, y cryptography). Es normalmente posible compilar paquetes para plataformas móviles, pero no es fácil de configurar - fuera del alcance de un tutorial introductorio como éste.

Ahora que hemos informado a Briefcase sobre nuestros requisitos adicionales, podemos intentar empaquetar nuestra aplicación de nuevo. Asegúrate de que has guardado los cambios en pyproject.toml, y luego actualiza tu aplicación de nuevo - esta vez, introduciendo la bandera -r. Esto le dice a Briefcase que actualice los requisitos en la aplicación empaquetada:

(beeware-venv) $ briefcase update -r

[helloworld] Updating application code...
Installing src/hello_world...

[helloworld] Updating requirements...
Collecting httpx
  Using cached httpx-0.27.0-py3-none-any.whl.metadata (7.2 kB)
...
Installing collected packages: zipp, typing-extensions, travertino, sniffio, pycairo, idna, h11, exceptiongroup, certifi, pygobject, importlib-metadata, httpcore, anyio, toga-core, httpx, gbulb, toga-gtk
Successfully installed anyio-4.3.0 certifi-2024.2.2 exceptiongroup-1.2.1 gbulb-0.6.5 h11-0.14.0 httpcore-1.0.5 httpx-0.27.0 idna-3.7 importlib-metadata-7.1.0 pycairo-1.26.0 pygobject-3.48.2 sniffio-1.3.1 toga-core-0.4.4 toga-gtk-0.4.4 travertino-0.3.0 typing-extensions-4.11.0 zipp-3.18.1

[helloworld] Removing unneeded app content...
...

[helloworld] Application updated.

Una vez que haya actualizado, puede ejecutar briefcase build y briefcase run - y usted debe ver su aplicación empaquetada, con el nuevo comportamiento de diálogo.

Nota

La opción -r para actualizar los requisitos también es respetada por los comandos build y run, así que si quieres actualizar, construir y ejecutar en un solo paso, puedes usar briefcase run -u -r.

Siguientes pasos

Ya tenemos una aplicación que utiliza una biblioteca de terceros Sin embargo, te habrás dado cuenta de que cuando pulsas el botón, la aplicación deja de responder. ¿Podemos hacer algo para solucionarlo? Visita Tutorial 8 para averiguarlo…