教程 7 - 启动这个(第三)派对#

到目前为止,我们构建的应用程序只使用了我们自己的代码和 BeeWare 提供的代码。不过,在实际应用中,您很可能需要使用从 Python 软件包索引(PyPI)下载的第三方库。

让我们修改应用程序,加入第三方库。

访问应用程序接口#

应用程序需要执行的一项常见任务是向网络应用程序接口发出请求以获取数据,并将数据显示给用户。这是一个玩具应用程序,因此我们没有*真正*的 API 可供使用,所以我们将使用 {JSON} 占位符 API 作为数据源。

{JSON} 占位符 API 有许多 “伪造 “的 API 端点,您可以将其用作测试数据。其中一个 API 是 /posts/ 端点,它会返回虚假的博客文章。如果在浏览器中打开 https://jsonplaceholder.typicode.com/posts/42 ,就会得到一个描述单篇博文的 JSON 有效载荷–ID 为 42 的博文的一些 Lorum ipsum 内容。

Python 标准库包含访问 API 所需的所有工具。然而,内置的 API 是非常低级的。它们很好地实现了 HTTP 协议,但需要用户管理大量低级细节,如 URL 重定向、会话、身份验证和有效负载编码。作为一名 “普通浏览器用户”,你可能已经习惯了将这些细节视为理所当然,因为浏览器会为你管理这些细节。

因此,人们开发了第三方库来封装内置的 API,并提供更简单的 API,使其更符合日常的浏览器体验。我们将使用其中一个库来访问 {JSON} 占位符 API - 一个名为 httpx 的库。

让我们在应用程序中添加一个 httpx API 调用。在 app.py 顶部添加导入,以导入 httpx::

import httpx

然后修改 say_hello() 回调,使其看起来像这样::

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

这将更改 say_hello() 回调,使它在被调用时,会:

  • 在 JSON 占位符 API 上发出 GET 请求,以获取职位 42;

  • 将响应解码为 JSON 格式;

  • 提取帖子正文;以及

  • 将该帖子的正文作为对话框的文本。

让我们在公文包开发者模式下运行更新后的应用程序,检查我们的更改是否有效。

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

发生了什么?我们已经将 httpx 添加到我们的代码*中,但我们还没有将它添加到我们的开发虚拟环境中。我们可以用 pip 安装 httpx,然后重新运行 briefcase dev

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

输入名称并按下按钮后,您会看到一个类似的对话框:

Hello World 教程 7 对话框,在 macOS 上运行

现在,我们已经有了一个可正常运行的应用程序,它使用第三方库,以开发模式运行!

运行更新后的应用程序#

让我们将更新后的应用程序代码打包为独立应用程序。由于我们对代码进行了修改,因此需要遵循 Tutorial 4 中的相同步骤:

更新打包应用程序中的代码:

(beeware-venv) $ briefcase update

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

[helloworld] Application updated.

重建应用程序:

(beeware-venv) $ briefcase build

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

最后,运行应用程序:

(beeware-venv) $ briefcase run

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

但是,当程序运行时,你会在控制台中看到一个错误,还有一个崩溃对话框:

MacOS 上的 Hello World Tutorial 7 应用程序崩溃

应用程序再次启动失败,因为已经安装了 httpx - 但为什么呢?我们不是已经安装了 httpx 吗?

我们有,但仅限于开发环境。你的开发环境完全在你的机器本地,只有当你明确激活它时才会启用。虽然公文包有开发模式,但使用公文包的主要原因是打包你的代码,这样你就可以把它交给别人。

要保证别人的 Python 环境包含它所需要的一切,唯一的办法就是构建一个完全隔离的 Python 环境。这意味着有一个完全独立的 Python 安装,和一套完全独立的依赖关系。这就是当你运行 briefcase build 时,Briefcase 正在构建的 - 一个隔离的 Python 环境。这也解释了为什么没有安装 httpx - 它已经安装在你的开发环境中,但没有安装在打包的应用程序中。

因此,我们需要告诉 Briefcase,我们的应用程序有一个外部依赖关系。

更新依赖项#

在应用程序的根目录中,有一个名为 pyproject.toml 的文件。该文件包含您最初运行 briefcase new 时提供的所有应用程序配置详细信息。

pyproject.toml “分为多个部分,其中一部分描述了应用程序的设置::

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

requires “选项描述了应用程序的依赖关系。它是一个字符串列表,其中指定了您希望应用程序包含的库(以及可选的版本)。

修改 requires 设置为::

requires = [
    "httpx",
]

通过添加此设置,我们告诉 Briefcase “当你构建我的应用程序时,运行 pip install httpx 到应用程序捆绑包中”。任何可以合法输入到 pip install 的内容都可以在这里使用–因此,你可以指定:

  • 特定的库版本(例如,"httpx===0.19.0");

  • 一系列库版本(例如,"httpx>=0.19");

  • 指向 git 仓库的路径(例如,"git+https://github.com/encode/httpx");或

  • 本地文件路径(不过需要注意的是:如果你把代码交给别人,这个路径很可能不存在于他们的机器上!)。

pyproject.toml 中的更下面部分,你会注意到与操作系统相关的其他部分,如 [tool.briefcase.app.helloworld.macOS][tool.briefcase.app.helloworld.windows]。这些部分**也有一个 requires 设置。这些设置允许你定义额外的特定平台依赖关系,例如,如果你需要一个特定平台的库来处理应用程序的某些方面,你可以在特定平台的 requires 部分中指定该库,而该设置将仅用于该平台。你会注意到,所有的 toga 库都是在特定平台的 requires 部分中指定的,这是因为显示用户界面所需的库都是特定平台的。

在我们的例子中,我们希望 httpx 安装在所有平台上,因此使用了应用程序级的 requires 设置。应用程序级的依赖项始终会被安装;特定平台的依赖项会在应用程序级的依赖项之外*安装。

某些二进制软件包可能不可用

在桌面平台(macOS、Windows、Linux)上,任何可安装的 “pip “都可以添加到您的需求中。在移动和网络平台上,”您的选择略显有限 <https://briefcase.readthedocs.io/en/latest/background/faq.html#can-i-use-third-party-python-packages-in-my-app>`__。

简而言之,任何*纯 Python* 包(即*不包含二进制模块的包)都可以毫无困难地使用。但是,如果您的依赖包包含二进制组件,则必须对其进行编译;目前,大多数 Python 包都不支持非桌面平台的编译。

BeeWare可以为一些流行的二进制模块(包括 “numpy”、”pandas “和 “加密”)提供二进制文件。为移动平台编译软件包通常是可行的,但设置起来并不容易–这已经超出了本入门教程的范围。

既然我们已经告诉了 Briefcase 我们的额外需求,那么我们就可以再次尝试打包应用程序了。确保已将更改保存到 pyproject.toml,然后再次更新应用程序–这一次,传递 -r 标志。这将告诉 Briefcase 更新打包应用程序中的需求:

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

更新完成后,您可以运行 briefcase buildbriefcase run - 您应该会看到打包后的应用程序,并带有新的对话框行为。

备注

用于更新需求的 -r 选项也会被 build` ``run` 命令接受,因此如果你想一步完成更新、编译和运行,可以使用 ``briefcase run -u -r

下一步#

我们现在有了一个使用第三方库的应用程序!不过,您可能已经注意到,当您按下按钮时,应用程序会变得有点反应迟钝。我们能解决这个问题吗?请访问 Tutorial 8 了解详情…