使用 setuptools,如何在安装时下载外部数据?
Using setuptools, how can I download external data upon installation?
我想创建一些简单易用的 pip 包,用于在 Python 中加载常见的机器学习数据集。 (是的,有些东西已经存在,但我希望它更简单。)
我想实现的是:
- 用户运行
pip install dataset
- pip 下载数据集,比如通过
wget http://mydata.com/data.tar.gz
。请注意,数据并不驻留在 python 包本身中,而是从其他地方下载的。
- pip 从这个文件中提取数据并将其放入安装包的目录中。(这并不理想,但数据集非常小,所以我们假设将数据存储在这里不是一个大不了。)
- 以后用户导入我的模块时,模块会自动从指定位置加载数据。
这个问题是关于项目符号 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
模块中关于在运行时下载必要的解码器的行为,而不是让用户自己管理外部下载。
我想创建一些简单易用的 pip 包,用于在 Python 中加载常见的机器学习数据集。 (是的,有些东西已经存在,但我希望它更简单。)
我想实现的是:
- 用户运行
pip install dataset
- pip 下载数据集,比如通过
wget http://mydata.com/data.tar.gz
。请注意,数据并不驻留在 python 包本身中,而是从其他地方下载的。 - pip 从这个文件中提取数据并将其放入安装包的目录中。(这并不理想,但数据集非常小,所以我们假设将数据存储在这里不是一个大不了。)
- 以后用户导入我的模块时,模块会自动从指定位置加载数据。
这个问题是关于项目符号 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
模块中关于在运行时下载必要的解码器的行为,而不是让用户自己管理外部下载。