使用 setuptools,如何在安装时下载外部数据?

Using setuptools, how can I download external data upon installation?

我想创建一些简单易用的 pip 包,用于在 Python 中加载常见的机器学习数据集。 (是的,有些东西已经存在,但我希望它更简单。)

我想实现的是:

这个问题是关于项目符号 2 和项目符号 3 的。有没有办法使用设置工具来做到这一点?

Python 包安装说明它永远不应该执行 Python 代码来安装 Python 包。这意味着您可能无法在安装过程中下载东西。

如果您想下载一些额外的数据,请在安装包后进行,例如,当您导入包时,您可以下载此数据并将其缓存在某处,以免在每次新导入时都下载它。

Note that the data does not reside in the python package itself, but is downloaded from somewhere else.

请不要这样做。

Python 打包的全部意义在于提供一种完全确定的、可重复的、可重用的方式来安装每次都完全相同的东西。您的提案至少存在以下问题:

  • 最终用户可能会在计算机 A 上下载您的程序包,将其粘贴到 U 盘上,然后将其安装到没有互联网的计算机 B 上。
  • Web 上的数据可能会发生变化,这意味着安装完全相同的软件包的两个人会得到不同的结果。
  • 提供数据的网站可能不复存在或unwisely change the URL,这意味着仍然拥有该软件包的人将无法使用它。
  • 用户可能在 Internet 过滤器后面,您可能会得到一个无用的 "this page is blocked" HTML 文件,而不是您期望的数据集。

相反,您应该将您的数据包含在包中(使用 setup()package_data or data_files 参数),或者在您的 Python 代码中提供一个单独的顶级函数来当用户准备好时手动下载数据。

正如 Kevin 所提到的,Python 包安装应该是完全可重现的,任何潜在的外部下载问题都应该被推送到运行时。因此,不应使用 setuptools 处理此问题。

相反,为了避免给用户带来负担,请考虑在加载时以惰性方式下载数据。示例:

def download_data(url='http://...'):
    # Download; extract data to disk.
    # Raise an exception if the link is bad, or we can't connect, etc.

def load_data():
    if not os.path.exists(DATA_DIR):
        download_data()
    data = read_data_from_disk(DATA_DIR)
    return data

然后我们可以在文档中描述 download_data,但大多数用户永远不需要为它操心。这有点类似于 imageio 模块中关于在运行时下载必要的解码器的行为,而不是让用户自己管理外部下载。