Esercitazione 7 - Iniziare questa (terza) festa#

Finora, l’applicazione che abbiamo costruito ha utilizzato solo il nostro codice e quello fornito da BeeWare. Tuttavia, in un’applicazione reale, è probabile che si voglia utilizzare una libreria di terze parti, scaricata dal Python Package Index (PyPI).

Modifichiamo la nostra applicazione per includere una libreria di terze parti.

Accesso a un’API#

Un compito comune che un’applicazione deve svolgere è quello di fare una richiesta a un’API web per recuperare dati e mostrarli all’utente. Questa è un’applicazione giocattolo, quindi non abbiamo un’API reale con cui lavorare, quindi useremo l’API segnaposto {JSON} come fonte di dati.

L’API {JSON} Placeholder ha una serie di endpoint API «falsi» che si possono usare come dati di prova. Una di queste API è l’endpoint /posts/, che restituisce finti post del blog. Se si apre https://jsonplaceholder.typicode.com/posts/42 nel browser, si otterrà un payload JSON che descrive un singolo post - un contenuto Lorum ipsum per un post di un blog con ID 42.

La libreria standard di Python contiene tutti gli strumenti necessari per accedere a un’API. Tuttavia, le API integrate sono di livello molto basso. Sono buone implementazioni del protocollo HTTP, ma richiedono all’utente di gestire molti dettagli di basso livello, come il reindirizzamento degli URL, le sessioni, l’autenticazione e la codifica del payload. Come «normale utente di browser», probabilmente siete abituati a dare per scontati questi dettagli, che il browser gestisce per voi.

Di conseguenza, sono state sviluppate librerie di terze parti che avvolgono le API integrate e forniscono un’API più semplice e più vicina all’esperienza quotidiana del browser. Utilizzeremo una di queste librerie per accedere all’API {JSON} Placeholder: una libreria chiamata httpx.

Aggiungiamo una chiamata API httpx alla nostra applicazione. Aggiungiamo un’importazione all’inizio di app.py per importare httpx:

import httpx

Modificare quindi il callback say_hello() in modo che assomigli a questo:

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"],
    )

Questo modificherà il callback say_hello() in modo che quando viene invocato, lo farà:

  • effettuare una richiesta GET all’API JSON dei segnaposto per ottenere il post 42;

  • decodificare la risposta come JSON;

  • estrarre il corpo del messaggio; e

  • includere il corpo di quel post come testo della finestra di dialogo.

Eseguiamo la nostra applicazione aggiornata in modalità sviluppatore di Briefcase per verificare che la nostra modifica abbia funzionato.

(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'

Cosa è successo? Abbiamo aggiunto httpx al nostro codice, ma non l’abbiamo aggiunto al nostro ambiente virtuale di sviluppo. Possiamo risolvere il problema installando httpx con pip e poi eseguendo nuovamente briefcase dev`:

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

Quando si inserisce un nome e si preme il pulsante, dovrebbe apparire una finestra di dialogo simile a questa:

Esercitazione Hello World 7, su macOS

Ora abbiamo un’applicazione funzionante, che utilizza una libreria di terze parti, in modalità di sviluppo!

Esecuzione dell’applicazione aggiornata#

Facciamo in modo che il codice aggiornato dell’applicazione venga confezionato come applicazione autonoma. Poiché abbiamo apportato modifiche al codice, dobbiamo seguire gli stessi passi di Tutorial 4:

Aggiornare il codice dell’applicazione confezionata:

(beeware-venv) $ briefcase update

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

[helloworld] Application updated.

Ricostruire l’applicazione:

(beeware-venv) $ briefcase build

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

Infine, eseguire l’applicazione:

(beeware-venv) $ briefcase run

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

Tuttavia, quando l’applicazione viene eseguita, viene visualizzato un errore nella console e una finestra di dialogo di arresto anomalo:

Arresto anomalo dell'applicazione Hello World Tutorial 7, su macOS

Ancora una volta, l’applicazione non è riuscita ad avviarsi perché httpx è stato installato - ma perché? Non abbiamo già installato httpx?

È così, ma solo nell’ambiente di sviluppo. L’ambiente di sviluppo è interamente locale alla vostra macchina e viene attivato solo quando lo attivate esplicitamente. Anche se Briefcase ha una modalità di sviluppo, il motivo principale per cui si usa Briefcase è per impacchettare il codice in modo da poterlo dare a qualcun altro.

L’unico modo per garantire che qualcun altro abbia un ambiente Python che contiene tutto ciò di cui ha bisogno è costruire un ambiente Python completamente isolato. Questo significa che c’è un’installazione di Python completamente isolata e un insieme di dipendenze completamente isolato. Questo è ciò che Briefcase costruisce quando si lancia briefcase build - un ambiente Python isolato. Questo spiega anche perché httpx non è installato: è stato installato nell’ambiente di sviluppo, ma non nell’applicazione confezionata.

Quindi, dobbiamo dire a Briefcase che la nostra applicazione ha una dipendenza esterna.

Aggiornamento delle dipendenze#

Nella directory principale dell’applicazione, c’è un file chiamato pyproject.toml. Questo file contiene tutti i dettagli di configurazione dell’applicazione forniti al momento dell’esecuzione di briefcase new.

il file pyproject.toml è suddiviso in sezioni; una delle sezioni descrive le impostazioni per l’applicazione:

[tool.briefcase.app.helloworld]
formal_name = "Hello World"
description = "A Tutorial app"
icon = "src/helloworld/resources/helloworld"
sources = ["src/helloworld"]
requires = []

L’opzione requires descrive le dipendenze della nostra applicazione. Si tratta di un elenco di stringhe, che specificano le librerie (e, opzionalmente, le versioni) delle librerie che si vogliono includere nella propria applicazione.

Modificare l’impostazione requires in modo che si legga:

requires = [
    "httpx",
]

Aggiungendo questa impostazione, si dice a Briefcase «quando costruisci la mia applicazione, esegui pip install httpx nel bundle dell’applicazione». Qualsiasi cosa che sia un input legale per pip install può essere usato qui, quindi si può specificare:

  • Una versione specifica della libreria (ad esempio, "httpx==0.19.0");

  • Un intervallo di versioni della libreria (ad esempio, "httpx>=0.19");

  • Un percorso a un repository git (ad esempio, git+https://github.com/encode/httpx"); oppure

  • Un percorso di file locale (tuttavia, attenzione: se si dà il codice a qualcun altro, questo percorso probabilmente non esisterà sulla sua macchina)

Più avanti in pyproject.toml, si noteranno altre sezioni che dipendono dal sistema operativo, come [tool.briefcase.app.helloworld.macOS] e [tool.briefcase.app.helloworld.windows]. Queste sezioni hanno anche un’impostazione requires. Queste impostazioni consentono di definire dipendenze aggiuntive specifiche per la piattaforma; quindi, ad esempio, se si ha bisogno di una libreria specifica per la piattaforma per gestire alcuni aspetti dell’applicazione, si può specificare tale libreria nella sezione requires specifica per la piattaforma, e tale impostazione sarà utilizzata solo per quella piattaforma. Si noterà che le librerie toga sono tutte specificate nella sezione requires specifica della piattaforma, perché le librerie necessarie per visualizzare l’interfaccia utente sono specifiche della piattaforma.

Nel nostro caso, vogliamo che httpx sia installato su tutte le piattaforme, quindi usiamo l’impostazione requires a livello di applicazione. Le dipendenze a livello di applicazione saranno sempre installate; le dipendenze specifiche della piattaforma sono installate in aggiunta a quelle a livello di applicazione.

Alcuni pacchetti binari potrebbero non essere disponibili

Sulle piattaforme desktop (macOS, Windows, Linux), qualsiasi pip installabile può essere aggiunto ai requisiti. Sulle piattaforme mobili e web, le opzioni sono leggermente limitate <https://briefcase.readthedocs.io/en/latest/background/faq.html#can-i-use-third-party-python-packages-in-my-app>`__.

In breve, qualsiasi pacchetto puro Python (cioè i pacchetti che non contengono un modulo binario) può essere usato senza problemi. Tuttavia, se la vostra dipendenza contiene un componente binario, deve essere compilata; al momento, la maggior parte dei pacchetti Python non fornisce supporto alla compilazione per piattaforme non desktop.

BeeWare può fornire binari per alcuni moduli binari popolari (tra cui numpy, pandas e cryptography). È di solito possibile compilare pacchetti per le piattaforme mobili, ma non è facile da configurare, il che esula dallo scopo di un tutorial introduttivo come questo.

Ora che abbiamo comunicato a Briefcase i nostri requisiti aggiuntivi, possiamo riprovare a pacchettizzare la nostra applicazione. Assicurarsi di aver salvato le modifiche a pyproject.toml e poi aggiornare di nuovo l’applicazione, questa volta inserendo il flag -r. Questo indica a Briefcase di aggiornare i requisiti nell’applicazione pacchettizzata:

(beeware-venv) $ briefcase update -r

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

[helloworld] Updating requirements...
Collecting httpx
  Using cached httpx-0.19.0-py3-none-any.whl (77 kB)
...
Installing collected packages: sniffio, idna, travertino, rfc3986, h11, anyio, toga-core, rubicon-objc, httpcore, charset-normalizer, certifi, toga-cocoa, httpx
Successfully installed anyio-3.3.2 certifi-2021.10.8 charset-normalizer-2.0.6 h11-0.12.0 httpcore-0.13.7 httpx-0.19.0 idna-3.2 rfc3986-1.5.0 rubicon-objc-0.4.1 sniffio-1.2.0 toga-cocoa-0.3.0.dev28 toga-core-0.3.0.dev28 travertino-0.1.3

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

[helloworld] Application updated.

Una volta effettuato l’aggiornamento, si può eseguire briefcase build e briefcase run e si dovrebbe vedere l’applicazione confezionata, con il nuovo comportamento della finestra di dialogo.

Nota

L’opzione -r per l’aggiornamento dei requisiti viene rispettata anche dai comandi build e run, quindi se si vuole aggiornare, compilare ed eseguire in un unico passaggio, si può usare briefcase run -u -r.

Prossimi passi#

Ora abbiamo un’applicazione che utilizza una libreria di terze parti! Tuttavia, avrete notato che quando si preme il pulsante, l’app diventa poco reattiva. Possiamo fare qualcosa per risolvere questo problema? Consultate Tutorial 8 per scoprirlo…