Tutorial 7 - Iniciando o uso de bibliotecas externas

Até o momento, o aplicativo que criamos usou apenas o nosso próprio código, além do código fornecido pelo BeeWare. Entretanto, em um aplicativo do mundo real, você provavelmente desejará usar uma biblioteca de terceiros, baixada do Python Package Index (PyPI).

Vamos modificar nosso aplicativo para incluir uma biblioteca de terceiros.

Acesso a uma API

Uma tarefa comum que um aplicativo precisará executar é fazer uma solicitação em uma API da Web para recuperar dados e exibir esses dados ao usuário. Como este é um aplicativo de brinquedo, não temos uma API real para trabalhar, portanto, usaremos a {JSON} Placeholder API como fonte de dados.

A API {JSON} Placeholder tem vários endpoints de API «falsos» que você pode usar como dados de teste. Uma dessas APIs é o ponto de extremidade /posts/, que retorna publicações de blog falsas. Se você abrir https://jsonplaceholder.typicode.com/posts/42 em seu navegador, obterá uma carga JSON que descreve uma única publicação - algum conteúdo Lorum ipsum para uma publicação de blog com ID 42.

A biblioteca padrão do Python contém todas as ferramentas necessárias para acessar uma API. Entretanto, as APIs incorporadas são de nível muito baixo. Elas são boas implementações do protocolo HTTP, mas exigem que o usuário gerencie muitos detalhes de baixo nível, como redirecionamento de URL, sessões, autenticação e codificação de carga útil. Como um «usuário normal de navegador», você provavelmente está acostumado a considerar esses detalhes como garantidos, pois o navegador gerencia esses detalhes para você.

Como resultado, as pessoas desenvolveram bibliotecas de terceiros que envolvem as APIs incorporadas e fornecem uma API mais simples que se aproxima da experiência cotidiana do navegador. Vamos usar uma dessas bibliotecas para acessar a API {JSON} Placeholder - uma biblioteca chamada httpx.

Vamos adicionar uma chamada de API httpx ao nosso aplicativo. Adicione uma importação na parte superior do app.py para importar httpx:

import httpx

Em seguida, modifique a chamada de retorno say_hello() para que fique assim:

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

Isso alterará a chamada de retorno say_hello() para que, quando for chamada, ela o faça:

  • faça uma solicitação GET na API do espaço reservado JSON para obter o post 42;

  • decodificar a resposta como JSON;

  • extrair o corpo da postagem; e

  • incluir o corpo dessa postagem como o texto da caixa de diálogo.

Vamos executar nosso aplicativo atualizado no modo de desenvolvedor do Briefcase para verificar se nossa alteração funcionou.

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

O que aconteceu? Adicionamos o httpx ao nosso código, mas não o adicionamos ao nosso ambiente virtual de desenvolvimento. Podemos corrigir isso instalando o httpx com o pip e, em seguida, executando novamente o briefcase dev:

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

Ao inserir um nome e pressionar o botão, você verá uma caixa de diálogo semelhante:

Caixa de diálogo do tutorial 7 do Hello World, no macOS

Agora temos um aplicativo funcional, usando uma biblioteca de terceiros, em execução no modo de desenvolvimento!

Executando o aplicativo atualizado

Vamos empacotar esse código de aplicativo atualizado como um aplicativo autônomo. Como fizemos alterações no código, precisamos seguir as mesmas etapas do Tutorial 4:

Atualize o código no aplicativo empacotado:

(beeware-venv) $ briefcase update

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

[helloworld] Application updated.

Reconstrua o aplicativo:

(beeware-venv) $ briefcase build

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

E, por fim, execute o aplicativo:

(beeware-venv) $ briefcase run

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

No entanto, quando o aplicativo for executado, você verá um erro no console, além de uma caixa de diálogo de falha:

Falha no aplicativo Hello World Tutorial 7, no macOS

Mais uma vez, o aplicativo não foi iniciado porque o httpx foi instalado - mas por quê? Já não instalamos o httpx?

Temos, mas somente no ambiente de desenvolvimento. O ambiente de desenvolvimento é totalmente local em seu computador e só é ativado quando você o ativa explicitamente. Embora o Briefcase tenha um modo de desenvolvimento, a principal razão pela qual você usaria o Briefcase é para empacotar o seu código para que você possa fornecê-lo a outra pessoa.

A única maneira de garantir que outra pessoa tenha um ambiente Python que contenha tudo o que ela precisa é criar um ambiente Python completamente isolado. Isso significa que há uma instalação completamente isolada do Python e um conjunto completamente isolado de dependências. Isso é o que o Briefcase está construindo quando você executa o briefcase build - um ambiente Python isolado. Isso também explica por que o httpx não está instalado - ele foi instalado em seu ambiente de desenvolvimento, mas não no aplicativo empacotado.

Portanto, precisamos informar ao Briefcase que nosso aplicativo tem uma dependência externa.

Atualização de dependências

No diretório raiz do seu aplicativo, há um arquivo chamado pyproject.toml. Esse arquivo contém todos os detalhes de configuração do aplicativo que você forneceu quando executou originalmente o briefcase new.

o pyproject.toml é dividido em seções; uma das seções descreve as configurações do seu aplicativo:

[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 = []

A opção requires descreve as dependências do nosso aplicativo. É uma lista de cadeias de caracteres, especificando as bibliotecas (e, opcionalmente, as versões) das bibliotecas que você deseja incluir em seu aplicativo.

Modifique a configuração requires para que fique assim:

requires = [
    "httpx",
]

Ao adicionar essa configuração, estamos dizendo ao Briefcase «quando você compilar meu aplicativo, execute pip install httpx no pacote de aplicativos». Qualquer coisa que seja uma entrada legal para pip install pode ser usada aqui - portanto, você poderia especificar:

  • Uma versão específica da biblioteca (por exemplo, "httpx==0.19.0");

  • Um intervalo de versões de biblioteca (por exemplo, "httpx>=0.19");

  • Um caminho para um repositório git (por exemplo, "git+https://github.com/encode/httpx"); ou

  • Um caminho de arquivo local (no entanto, esteja avisado: se você fornecer seu código a outra pessoa, esse caminho provavelmente não existirá no computador dela!)

Mais abaixo no pyproject.toml, você notará outras seções que dependem do sistema operacional, como [tool.briefcase.app.helloworld.macOS] e [tool.briefcase.app.helloworld.windows]. Essas seções também têm uma configuração requires. Essas configurações permitem definir dependências adicionais específicas da plataforma. Assim, por exemplo, se você precisar de uma biblioteca específica da plataforma para lidar com algum aspecto do seu aplicativo, poderá especificar essa biblioteca na seção requires específica da plataforma, e essa configuração será usada somente para essa plataforma. Você notará que as bibliotecas toga são todas especificadas na seção requires específica da plataforma - isso ocorre porque as bibliotecas necessárias para exibir uma interface de usuário são específicas da plataforma.

No nosso caso, queremos que o httpx seja instalado em todas as plataformas, portanto, usamos a configuração requires em nível de aplicativo. As dependências no nível do aplicativo sempre serão instaladas; as dependências específicas da plataforma são instaladas além das dependências no nível do aplicativo.

Alguns pacotes binários podem não estar disponíveis

Em plataformas de desktop (macOS, Windows, Linux), qualquer pip instalável pode ser adicionado aos seus requisitos. Em plataformas móveis e da Web, suas opções são ligeiramente limitadas.

Resumindo: qualquer pacote Python puro (ou seja, pacotes que não contêm um módulo binário) pode ser usado sem dificuldade. No entanto, se sua dependência contiver um componente binário, ele deverá ser compilado; no momento, a maioria dos pacotes Python não oferece suporte à compilação para plataformas que não sejam de desktop.

O BeeWare pode fornecer binários para alguns módulos binários populares (incluindo numpy, pandas e cryptography). Normalmente, é possível compilar pacotes para plataformas móveis, mas isso não é fácil de configurar, o que está fora do escopo de um tutorial introdutório como este.

Agora que informamos o Briefcase sobre nossos requisitos adicionais, podemos tentar empacotar nosso aplicativo novamente. Certifique-se de que salvou suas alterações no pyproject.toml e, em seguida, atualize seu aplicativo novamente - desta vez, passando o sinalizador -r. Isso diz ao Briefcase para atualizar os requisitos no aplicativo empacotado:

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

Depois de atualizar, você pode executar briefcase build e briefcase run e verá o aplicativo empacotado com o novo comportamento de diálogo.

Nota

A opção -r para atualizar os requisitos também é aceita pelos comandos build e run, portanto, se quiser atualizar, compilar e executar em uma única etapa, você pode usar briefcase run -u -r.

Próximos passos

Agora temos um aplicativo que usa uma biblioteca de terceiros! No entanto, você deve ter notado que, ao pressionar o botão, o aplicativo fica um pouco sem resposta. Podemos fazer algo para corrigir isso? Consulte o Tutorial 8 para descobrir…